1
ļ»æ// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
3
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
// software and associated documentation files (the "Software"), to deal in the Software
5
// without restriction, including without limitation the rights to use, copy, modify, merge,
6
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
// to whom the Software is furnished to do so, subject to the following conditions:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
12
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17
// DEALINGS IN THE SOFTWARE.
20
using System.Collections.Generic;
23
using ICSharpCode.NRefactory.TypeSystem;
24
using ICSharpCode.NRefactory.TypeSystem.Implementation;
25
using ICSharpCode.NRefactory.Utils;
27
namespace ICSharpCode.NRefactory.CSharp.Resolver
29
sealed class CSharpOperators
31
readonly ICompilation compilation;
33
private CSharpOperators(ICompilation compilation)
35
this.compilation = compilation;
36
InitParameterArrays();
40
/// Gets the CSharpOperators instance for the specified <see cref="ICompilation"/>.
41
/// This will make use of the context's cache manager (if available) to reuse the CSharpOperators instance.
43
public static CSharpOperators Get(ICompilation compilation)
45
CacheManager cache = compilation.CacheManager;
46
CSharpOperators operators = (CSharpOperators)cache.GetShared(typeof(CSharpOperators));
47
if (operators == null) {
48
operators = (CSharpOperators)cache.GetOrAddShared(typeof(CSharpOperators), new CSharpOperators(compilation));
53
#region class OperatorMethod
54
OperatorMethod[] Lift(params OperatorMethod[] methods)
56
List<OperatorMethod> result = new List<OperatorMethod>(methods);
57
foreach (OperatorMethod method in methods) {
58
OperatorMethod lifted = method.Lift(this);
62
return result.ToArray();
65
IParameter[] normalParameters = new IParameter[(int)(TypeCode.String + 1 - TypeCode.Object)];
66
IParameter[] nullableParameters = new IParameter[(int)(TypeCode.Decimal + 1 - TypeCode.Boolean)];
68
void InitParameterArrays()
70
for (TypeCode i = TypeCode.Object; i <= TypeCode.String; i++) {
71
normalParameters[i - TypeCode.Object] = new DefaultParameter(compilation.FindType(i), string.Empty);
73
for (TypeCode i = TypeCode.Boolean; i <= TypeCode.Decimal; i++) {
74
IType type = NullableType.Create(compilation, compilation.FindType(i));
75
nullableParameters[i - TypeCode.Boolean] = new DefaultParameter(type, string.Empty);
79
IParameter MakeParameter(TypeCode code)
81
return normalParameters[code - TypeCode.Object];
84
IParameter MakeNullableParameter(IParameter normalParameter)
86
for (TypeCode i = TypeCode.Boolean; i <= TypeCode.Decimal; i++) {
87
if (normalParameter == normalParameters[i - TypeCode.Object])
88
return nullableParameters[i - TypeCode.Boolean];
90
throw new ArgumentException();
93
internal class OperatorMethod : IParameterizedMember
95
readonly ICompilation compilation;
96
readonly IList<IParameter> parameters = new List<IParameter>();
98
protected OperatorMethod(ICompilation compilation)
100
this.compilation = compilation;
103
public IList<IParameter> Parameters {
104
get { return parameters; }
107
public IType ReturnType { get; internal set; }
109
public ICompilation Compilation {
110
get { return compilation; }
113
public virtual OperatorMethod Lift(CSharpOperators operators)
118
ITypeDefinition IEntity.DeclaringTypeDefinition {
122
IType IEntity.DeclaringType {
123
get { return SpecialType.UnknownType; }
126
IMember IMember.MemberDefinition {
130
IUnresolvedMember IMember.UnresolvedMember {
134
IList<IMember> IMember.ImplementedInterfaceMembers {
135
get { return EmptyList<IMember>.Instance; }
138
bool IMember.IsVirtual {
139
get { return false; }
142
bool IMember.IsOverride {
143
get { return false; }
146
bool IMember.IsOverridable {
147
get { return false; }
150
EntityType IEntity.EntityType {
151
get { return EntityType.Operator; }
154
DomRegion IEntity.Region {
155
get { return DomRegion.Empty; }
158
DomRegion IEntity.BodyRegion {
159
get { return DomRegion.Empty; }
162
IList<IAttribute> IEntity.Attributes {
163
get { return EmptyList<IAttribute>.Instance; }
166
Documentation.DocumentationComment IEntity.Documentation {
170
Accessibility IHasAccessibility.Accessibility {
171
get { return Accessibility.Public; }
174
bool IEntity.IsStatic {
178
bool IEntity.IsAbstract {
179
get { return false; }
182
bool IEntity.IsSealed {
183
get { return false; }
186
bool IEntity.IsShadowing {
187
get { return false; }
190
bool IEntity.IsSynthetic {
194
bool IHasAccessibility.IsPrivate {
195
get { return false; }
198
bool IHasAccessibility.IsPublic {
202
bool IHasAccessibility.IsProtected {
203
get { return false; }
206
bool IHasAccessibility.IsInternal {
207
get { return false; }
210
bool IHasAccessibility.IsProtectedOrInternal {
211
get { return false; }
214
bool IHasAccessibility.IsProtectedAndInternal {
215
get { return false; }
218
bool IMember.IsExplicitInterfaceImplementation {
219
get { return false; }
222
IAssembly IEntity.ParentAssembly {
223
get { return compilation.MainAssembly; }
226
IMemberReference IMember.ToMemberReference()
228
throw new NotSupportedException();
231
string INamedElement.FullName {
232
get { return "operator"; }
235
string INamedElement.Name {
236
get { return "operator"; }
239
string INamedElement.Namespace {
240
get { return string.Empty; }
243
string INamedElement.ReflectionName {
244
get { return "operator"; }
247
public override string ToString()
249
StringBuilder b = new StringBuilder();
250
b.Append(ReturnType + " operator(");
251
for (int i = 0; i < parameters.Count; i++) {
254
b.Append(parameters[i].Type);
262
#region Unary operator class definitions
263
internal class UnaryOperatorMethod : OperatorMethod
265
public virtual bool CanEvaluateAtCompileTime { get { return false; } }
267
public virtual object Invoke(CSharpResolver resolver, object input)
269
throw new NotSupportedException();
272
public UnaryOperatorMethod(ICompilation compilaton) : base(compilaton)
277
sealed class LambdaUnaryOperatorMethod<T> : UnaryOperatorMethod
279
readonly Func<T, T> func;
281
public LambdaUnaryOperatorMethod(CSharpOperators operators, Func<T, T> func)
282
: base(operators.compilation)
284
TypeCode typeCode = Type.GetTypeCode(typeof(T));
285
this.ReturnType = operators.compilation.FindType(typeCode);
286
this.Parameters.Add(operators.MakeParameter(typeCode));
290
public override bool CanEvaluateAtCompileTime {
294
public override object Invoke(CSharpResolver resolver, object input)
298
return func((T)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T)), input));
301
public override OperatorMethod Lift(CSharpOperators operators)
303
return new LiftedUnaryOperatorMethod(operators, this);
307
sealed class LiftedUnaryOperatorMethod : UnaryOperatorMethod, OverloadResolution.ILiftedOperator
309
UnaryOperatorMethod baseMethod;
311
public LiftedUnaryOperatorMethod(CSharpOperators operators, UnaryOperatorMethod baseMethod) : base(operators.compilation)
313
this.baseMethod = baseMethod;
314
this.ReturnType = NullableType.Create(baseMethod.Compilation, baseMethod.ReturnType);
315
this.Parameters.Add(operators.MakeNullableParameter(baseMethod.Parameters[0]));
318
public IList<IParameter> NonLiftedParameters {
319
get { return baseMethod.Parameters; }
324
#region Unary operator definitions
325
// C# 4.0 spec: Ā§7.7.1 Unary plus operator
326
OperatorMethod[] unaryPlusOperators;
328
public OperatorMethod[] UnaryPlusOperators {
330
OperatorMethod[] ops = LazyInit.VolatileRead(ref unaryPlusOperators);
334
return LazyInit.GetOrSet(ref unaryPlusOperators, Lift(
335
new LambdaUnaryOperatorMethod<int> (this, i => +i),
336
new LambdaUnaryOperatorMethod<uint> (this, i => +i),
337
new LambdaUnaryOperatorMethod<long> (this, i => +i),
338
new LambdaUnaryOperatorMethod<ulong> (this, i => +i),
339
new LambdaUnaryOperatorMethod<float> (this, i => +i),
340
new LambdaUnaryOperatorMethod<double> (this, i => +i),
341
new LambdaUnaryOperatorMethod<decimal>(this, i => +i)
347
// C# 4.0 spec: Ā§7.7.2 Unary minus operator
348
OperatorMethod[] uncheckedUnaryMinusOperators;
350
public OperatorMethod[] UncheckedUnaryMinusOperators {
352
OperatorMethod[] ops = LazyInit.VolatileRead(ref uncheckedUnaryMinusOperators);
356
return LazyInit.GetOrSet(ref uncheckedUnaryMinusOperators, Lift(
357
new LambdaUnaryOperatorMethod<int> (this, i => unchecked(-i)),
358
new LambdaUnaryOperatorMethod<long> (this, i => unchecked(-i)),
359
new LambdaUnaryOperatorMethod<float> (this, i => unchecked(-i)),
360
new LambdaUnaryOperatorMethod<double> (this, i => unchecked(-i)),
361
new LambdaUnaryOperatorMethod<decimal>(this, i => unchecked(-i))
367
OperatorMethod[] checkedUnaryMinusOperators;
369
public OperatorMethod[] CheckedUnaryMinusOperators {
371
OperatorMethod[] ops = LazyInit.VolatileRead(ref checkedUnaryMinusOperators);
375
return LazyInit.GetOrSet(ref checkedUnaryMinusOperators, Lift(
376
new LambdaUnaryOperatorMethod<int> (this, i => checked(-i)),
377
new LambdaUnaryOperatorMethod<long> (this, i => checked(-i)),
378
new LambdaUnaryOperatorMethod<float> (this, i => checked(-i)),
379
new LambdaUnaryOperatorMethod<double> (this, i => checked(-i)),
380
new LambdaUnaryOperatorMethod<decimal>(this, i => checked(-i))
386
// C# 4.0 spec: Ā§7.7.3 Logical negation operator
387
OperatorMethod[] logicalNegationOperators;
389
public OperatorMethod[] LogicalNegationOperators {
391
OperatorMethod[] ops = LazyInit.VolatileRead(ref logicalNegationOperators);
395
return LazyInit.GetOrSet(ref logicalNegationOperators, Lift(
396
new LambdaUnaryOperatorMethod<bool>(this, b => !b)
402
// C# 4.0 spec: Ā§7.7.4 Bitwise complement operator
403
OperatorMethod[] bitwiseComplementOperators;
405
public OperatorMethod[] BitwiseComplementOperators {
407
OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseComplementOperators);
411
return LazyInit.GetOrSet(ref bitwiseComplementOperators, Lift(
412
new LambdaUnaryOperatorMethod<int> (this, i => ~i),
413
new LambdaUnaryOperatorMethod<uint> (this, i => ~i),
414
new LambdaUnaryOperatorMethod<long> (this, i => ~i),
415
new LambdaUnaryOperatorMethod<ulong>(this, i => ~i)
422
#region Binary operator class definitions
423
internal class BinaryOperatorMethod : OperatorMethod
425
public virtual bool CanEvaluateAtCompileTime { get { return false; } }
426
public virtual object Invoke(CSharpResolver resolver, object lhs, object rhs) {
427
throw new NotSupportedException();
430
public BinaryOperatorMethod(ICompilation compilation) : base(compilation) {}
433
sealed class LambdaBinaryOperatorMethod<T1, T2> : BinaryOperatorMethod
435
readonly Func<T1, T2, T1> checkedFunc;
436
readonly Func<T1, T2, T1> uncheckedFunc;
438
public LambdaBinaryOperatorMethod(CSharpOperators operators, Func<T1, T2, T1> func)
439
: this(operators, func, func)
443
public LambdaBinaryOperatorMethod(CSharpOperators operators, Func<T1, T2, T1> checkedFunc, Func<T1, T2, T1> uncheckedFunc)
444
: base(operators.compilation)
446
TypeCode t1 = Type.GetTypeCode(typeof(T1));
447
this.ReturnType = operators.compilation.FindType(t1);
448
this.Parameters.Add(operators.MakeParameter(t1));
449
this.Parameters.Add(operators.MakeParameter(Type.GetTypeCode(typeof(T2))));
450
this.checkedFunc = checkedFunc;
451
this.uncheckedFunc = uncheckedFunc;
454
public override bool CanEvaluateAtCompileTime {
458
public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
460
if (lhs == null || rhs == null)
462
Func<T1, T2, T1> func = resolver.CheckForOverflow ? checkedFunc : uncheckedFunc;
463
return func((T1)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T1)), lhs),
464
(T2)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T2)), rhs));
467
public override OperatorMethod Lift(CSharpOperators operators)
469
return new LiftedBinaryOperatorMethod(operators, this);
473
sealed class LiftedBinaryOperatorMethod : BinaryOperatorMethod, OverloadResolution.ILiftedOperator
475
readonly BinaryOperatorMethod baseMethod;
477
public LiftedBinaryOperatorMethod(CSharpOperators operators, BinaryOperatorMethod baseMethod)
478
: base(operators.compilation)
480
this.baseMethod = baseMethod;
481
this.ReturnType = NullableType.Create(operators.compilation, baseMethod.ReturnType);
482
this.Parameters.Add(operators.MakeNullableParameter(baseMethod.Parameters[0]));
483
this.Parameters.Add(operators.MakeNullableParameter(baseMethod.Parameters[1]));
486
public IList<IParameter> NonLiftedParameters {
487
get { return baseMethod.Parameters; }
492
#region Arithmetic operators
493
// C# 4.0 spec: Ā§7.8.1 Multiplication operator
495
OperatorMethod[] multiplicationOperators;
497
public OperatorMethod[] MultiplicationOperators {
499
OperatorMethod[] ops = LazyInit.VolatileRead(ref multiplicationOperators);
503
return LazyInit.GetOrSet(ref multiplicationOperators, Lift(
504
new LambdaBinaryOperatorMethod<int, int> (this, (a, b) => checked(a * b), (a, b) => unchecked(a * b)),
505
new LambdaBinaryOperatorMethod<uint, uint> (this, (a, b) => checked(a * b), (a, b) => unchecked(a * b)),
506
new LambdaBinaryOperatorMethod<long, long> (this, (a, b) => checked(a * b), (a, b) => unchecked(a * b)),
507
new LambdaBinaryOperatorMethod<ulong, ulong> (this, (a, b) => checked(a * b), (a, b) => unchecked(a * b)),
508
new LambdaBinaryOperatorMethod<float, float> (this, (a, b) => checked(a * b), (a, b) => unchecked(a * b)),
509
new LambdaBinaryOperatorMethod<double, double> (this, (a, b) => checked(a * b), (a, b) => unchecked(a * b)),
510
new LambdaBinaryOperatorMethod<decimal, decimal>(this, (a, b) => checked(a * b), (a, b) => unchecked(a * b))
516
// C# 4.0 spec: Ā§7.8.2 Division operator
517
OperatorMethod[] divisionOperators;
519
public OperatorMethod[] DivisionOperators {
521
OperatorMethod[] ops = LazyInit.VolatileRead(ref divisionOperators);
525
return LazyInit.GetOrSet(ref divisionOperators, Lift(
526
new LambdaBinaryOperatorMethod<int, int> (this, (a, b) => checked(a / b), (a, b) => unchecked(a / b)),
527
new LambdaBinaryOperatorMethod<uint, uint> (this, (a, b) => checked(a / b), (a, b) => unchecked(a / b)),
528
new LambdaBinaryOperatorMethod<long, long> (this, (a, b) => checked(a / b), (a, b) => unchecked(a / b)),
529
new LambdaBinaryOperatorMethod<ulong, ulong> (this, (a, b) => checked(a / b), (a, b) => unchecked(a / b)),
530
new LambdaBinaryOperatorMethod<float, float> (this, (a, b) => checked(a / b), (a, b) => unchecked(a / b)),
531
new LambdaBinaryOperatorMethod<double, double> (this, (a, b) => checked(a / b), (a, b) => unchecked(a / b)),
532
new LambdaBinaryOperatorMethod<decimal, decimal>(this, (a, b) => checked(a / b), (a, b) => unchecked(a / b))
538
// C# 4.0 spec: Ā§7.8.3 Remainder operator
539
OperatorMethod[] remainderOperators;
541
public OperatorMethod[] RemainderOperators {
543
OperatorMethod[] ops = LazyInit.VolatileRead(ref remainderOperators);
547
return LazyInit.GetOrSet(ref remainderOperators, Lift(
548
new LambdaBinaryOperatorMethod<int, int> (this, (a, b) => checked(a % b), (a, b) => unchecked(a % b)),
549
new LambdaBinaryOperatorMethod<uint, uint> (this, (a, b) => checked(a % b), (a, b) => unchecked(a % b)),
550
new LambdaBinaryOperatorMethod<long, long> (this, (a, b) => checked(a % b), (a, b) => unchecked(a % b)),
551
new LambdaBinaryOperatorMethod<ulong, ulong> (this, (a, b) => checked(a % b), (a, b) => unchecked(a % b)),
552
new LambdaBinaryOperatorMethod<float, float> (this, (a, b) => checked(a % b), (a, b) => unchecked(a % b)),
553
new LambdaBinaryOperatorMethod<double, double> (this, (a, b) => checked(a % b), (a, b) => unchecked(a % b)),
554
new LambdaBinaryOperatorMethod<decimal, decimal>(this, (a, b) => checked(a % b), (a, b) => unchecked(a % b))
560
// C# 4.0 spec: Ā§7.8.3 Addition operator
561
OperatorMethod[] additionOperators;
563
public OperatorMethod[] AdditionOperators {
565
OperatorMethod[] ops = LazyInit.VolatileRead(ref additionOperators);
569
return LazyInit.GetOrSet(ref additionOperators, Lift(
570
new LambdaBinaryOperatorMethod<int, int> (this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
571
new LambdaBinaryOperatorMethod<uint, uint> (this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
572
new LambdaBinaryOperatorMethod<long, long> (this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
573
new LambdaBinaryOperatorMethod<ulong, ulong> (this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
574
new LambdaBinaryOperatorMethod<float, float> (this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
575
new LambdaBinaryOperatorMethod<double, double> (this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
576
new LambdaBinaryOperatorMethod<decimal, decimal>(this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
577
new StringConcatenation(this, TypeCode.String, TypeCode.String),
578
new StringConcatenation(this, TypeCode.String, TypeCode.Object),
579
new StringConcatenation(this, TypeCode.Object, TypeCode.String)
585
// not in this list, but handled manually: enum addition, delegate combination
586
sealed class StringConcatenation : BinaryOperatorMethod
588
bool canEvaluateAtCompileTime;
590
public StringConcatenation(CSharpOperators operators, TypeCode p1, TypeCode p2)
591
: base(operators.compilation)
593
this.canEvaluateAtCompileTime = p1 == TypeCode.String && p2 == TypeCode.String;
594
this.ReturnType = operators.compilation.FindType(KnownTypeCode.String);
595
this.Parameters.Add(operators.MakeParameter(p1));
596
this.Parameters.Add(operators.MakeParameter(p2));
599
public override bool CanEvaluateAtCompileTime {
600
get { return canEvaluateAtCompileTime; }
603
public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
605
return string.Concat(lhs, rhs);
609
// C# 4.0 spec: Ā§7.8.4 Subtraction operator
610
OperatorMethod[] subtractionOperators;
612
public OperatorMethod[] SubtractionOperators {
614
OperatorMethod[] ops = LazyInit.VolatileRead(ref subtractionOperators);
618
return LazyInit.GetOrSet(ref subtractionOperators, Lift(
619
new LambdaBinaryOperatorMethod<int, int> (this, (a, b) => checked(a - b), (a, b) => unchecked(a - b)),
620
new LambdaBinaryOperatorMethod<uint, uint> (this, (a, b) => checked(a - b), (a, b) => unchecked(a - b)),
621
new LambdaBinaryOperatorMethod<long, long> (this, (a, b) => checked(a - b), (a, b) => unchecked(a - b)),
622
new LambdaBinaryOperatorMethod<ulong, ulong> (this, (a, b) => checked(a - b), (a, b) => unchecked(a - b)),
623
new LambdaBinaryOperatorMethod<float, float> (this, (a, b) => checked(a - b), (a, b) => unchecked(a - b)),
624
new LambdaBinaryOperatorMethod<double, double> (this, (a, b) => checked(a - b), (a, b) => unchecked(a - b)),
625
new LambdaBinaryOperatorMethod<decimal, decimal>(this, (a, b) => checked(a - b), (a, b) => unchecked(a - b))
631
// C# 4.0 spec: Ā§7.8.5 Shift operators
632
OperatorMethod[] shiftLeftOperators;
634
public OperatorMethod[] ShiftLeftOperators {
636
OperatorMethod[] ops = LazyInit.VolatileRead(ref shiftLeftOperators);
640
return LazyInit.GetOrSet(ref shiftLeftOperators, Lift(
641
new LambdaBinaryOperatorMethod<int, int>(this, (a, b) => a << b),
642
new LambdaBinaryOperatorMethod<uint, int>(this, (a, b) => a << b),
643
new LambdaBinaryOperatorMethod<long, int>(this, (a, b) => a << b),
644
new LambdaBinaryOperatorMethod<ulong, int>(this, (a, b) => a << b)
650
OperatorMethod[] shiftRightOperators;
652
public OperatorMethod[] ShiftRightOperators {
654
OperatorMethod[] ops = LazyInit.VolatileRead(ref shiftRightOperators);
658
return LazyInit.GetOrSet(ref shiftRightOperators, Lift(
659
new LambdaBinaryOperatorMethod<int, int>(this, (a, b) => a >> b),
660
new LambdaBinaryOperatorMethod<uint, int>(this, (a, b) => a >> b),
661
new LambdaBinaryOperatorMethod<long, int>(this, (a, b) => a >> b),
662
new LambdaBinaryOperatorMethod<ulong, int>(this, (a, b) => a >> b)
669
#region Equality operators
670
sealed class EqualityOperatorMethod : BinaryOperatorMethod
672
public readonly TypeCode Type;
673
public readonly bool Negate;
675
public EqualityOperatorMethod(CSharpOperators operators, TypeCode type, bool negate)
676
: base(operators.compilation)
678
this.Negate = negate;
680
this.ReturnType = operators.compilation.FindType(KnownTypeCode.Boolean);
681
this.Parameters.Add(operators.MakeParameter(type));
682
this.Parameters.Add(operators.MakeParameter(type));
685
public override bool CanEvaluateAtCompileTime {
686
get { return Type != TypeCode.Object; }
689
public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
691
if (lhs == null && rhs == null)
692
return !Negate; // ==: true; !=: false
693
if (lhs == null || rhs == null)
694
return Negate; // ==: false; !=: true
695
lhs = resolver.CSharpPrimitiveCast(Type, lhs);
696
rhs = resolver.CSharpPrimitiveCast(Type, rhs);
698
if (Type == TypeCode.Single) {
699
equal = (float)lhs == (float)rhs;
700
} else if (Type == TypeCode.Double) {
701
equal = (double)lhs == (double)rhs;
703
equal = object.Equals(lhs, rhs);
705
return equal ^ Negate;
708
public override OperatorMethod Lift(CSharpOperators operators)
710
if (Type == TypeCode.Object || Type == TypeCode.String)
713
return new LiftedEqualityOperatorMethod(operators, this);
717
sealed class LiftedEqualityOperatorMethod : BinaryOperatorMethod, OverloadResolution.ILiftedOperator
719
readonly EqualityOperatorMethod baseMethod;
721
public LiftedEqualityOperatorMethod(CSharpOperators operators, EqualityOperatorMethod baseMethod)
722
: base(operators.compilation)
724
this.baseMethod = baseMethod;
725
this.ReturnType = baseMethod.ReturnType;
726
IParameter p = operators.MakeNullableParameter(baseMethod.Parameters[0]);
727
this.Parameters.Add(p);
728
this.Parameters.Add(p);
731
public override bool CanEvaluateAtCompileTime {
732
get { return baseMethod.CanEvaluateAtCompileTime; }
735
public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
737
return baseMethod.Invoke(resolver, lhs, rhs);
740
public IList<IParameter> NonLiftedParameters {
741
get { return baseMethod.Parameters; }
745
// C# 4.0 spec: Ā§7.10 Relational and type-testing operators
746
static readonly TypeCode[] valueEqualityOperatorsFor = {
747
TypeCode.Int32, TypeCode.UInt32,
748
TypeCode.Int64, TypeCode.UInt64,
749
TypeCode.Single, TypeCode.Double,
754
OperatorMethod[] valueEqualityOperators;
756
public OperatorMethod[] ValueEqualityOperators {
758
OperatorMethod[] ops = LazyInit.VolatileRead(ref valueEqualityOperators);
762
return LazyInit.GetOrSet(ref valueEqualityOperators, Lift(
763
valueEqualityOperatorsFor.Select(c => new EqualityOperatorMethod(this, c, false)).ToArray()
769
OperatorMethod[] valueInequalityOperators;
771
public OperatorMethod[] ValueInequalityOperators {
773
OperatorMethod[] ops = LazyInit.VolatileRead(ref valueInequalityOperators);
777
return LazyInit.GetOrSet(ref valueInequalityOperators, Lift(
778
valueEqualityOperatorsFor.Select(c => new EqualityOperatorMethod(this, c, true)).ToArray()
784
OperatorMethod[] referenceEqualityOperators;
786
public OperatorMethod[] ReferenceEqualityOperators {
788
OperatorMethod[] ops = LazyInit.VolatileRead(ref referenceEqualityOperators);
792
return LazyInit.GetOrSet(ref referenceEqualityOperators, Lift(
793
new EqualityOperatorMethod(this, TypeCode.Object, false),
794
new EqualityOperatorMethod(this, TypeCode.String, false)
800
OperatorMethod[] referenceInequalityOperators;
802
public OperatorMethod[] ReferenceInequalityOperators {
804
OperatorMethod[] ops = LazyInit.VolatileRead(ref referenceInequalityOperators);
808
return LazyInit.GetOrSet(ref referenceInequalityOperators, Lift(
809
new EqualityOperatorMethod(this, TypeCode.Object, true),
810
new EqualityOperatorMethod(this, TypeCode.String, true)
817
#region Relational Operators
818
sealed class RelationalOperatorMethod<T1, T2> : BinaryOperatorMethod
820
readonly Func<T1, T2, bool> func;
822
public RelationalOperatorMethod(CSharpOperators operators, Func<T1, T2, bool> func)
823
: base(operators.compilation)
825
this.ReturnType = operators.compilation.FindType(KnownTypeCode.Boolean);
826
this.Parameters.Add(operators.MakeParameter(Type.GetTypeCode(typeof(T1))));
827
this.Parameters.Add(operators.MakeParameter(Type.GetTypeCode(typeof(T2))));
831
public override bool CanEvaluateAtCompileTime {
835
public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
837
if (lhs == null || rhs == null)
839
return func((T1)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T1)), lhs),
840
(T2)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T2)), rhs));
843
public override OperatorMethod Lift(CSharpOperators operators)
845
var lifted = new LiftedBinaryOperatorMethod(operators, this);
846
lifted.ReturnType = this.ReturnType; // don't lift the return type for relational operators
851
OperatorMethod[] lessThanOperators;
853
public OperatorMethod[] LessThanOperators {
855
OperatorMethod[] ops = LazyInit.VolatileRead(ref lessThanOperators);
859
return LazyInit.GetOrSet(ref lessThanOperators, Lift(
860
new RelationalOperatorMethod<int, int> (this, (a, b) => a < b),
861
new RelationalOperatorMethod<uint, uint> (this, (a, b) => a < b),
862
new RelationalOperatorMethod<long, long> (this, (a, b) => a < b),
863
new RelationalOperatorMethod<ulong, ulong> (this, (a, b) => a < b),
864
new RelationalOperatorMethod<float, float> (this, (a, b) => a < b),
865
new RelationalOperatorMethod<double, double> (this, (a, b) => a < b),
866
new RelationalOperatorMethod<decimal, decimal>(this, (a, b) => a < b)
872
OperatorMethod[] lessThanOrEqualOperators;
874
public OperatorMethod[] LessThanOrEqualOperators {
876
OperatorMethod[] ops = LazyInit.VolatileRead(ref lessThanOrEqualOperators);
880
return LazyInit.GetOrSet(ref lessThanOrEqualOperators, Lift(
881
new RelationalOperatorMethod<int, int> (this, (a, b) => a <= b),
882
new RelationalOperatorMethod<uint, uint> (this, (a, b) => a <= b),
883
new RelationalOperatorMethod<long, long> (this, (a, b) => a <= b),
884
new RelationalOperatorMethod<ulong, ulong> (this, (a, b) => a <= b),
885
new RelationalOperatorMethod<float, float> (this, (a, b) => a <= b),
886
new RelationalOperatorMethod<double, double> (this, (a, b) => a <= b),
887
new RelationalOperatorMethod<decimal, decimal>(this, (a, b) => a <= b)
893
OperatorMethod[] greaterThanOperators;
895
public OperatorMethod[] GreaterThanOperators {
897
OperatorMethod[] ops = LazyInit.VolatileRead(ref greaterThanOperators);
901
return LazyInit.GetOrSet(ref greaterThanOperators, Lift(
902
new RelationalOperatorMethod<int, int> (this, (a, b) => a > b),
903
new RelationalOperatorMethod<uint, uint> (this, (a, b) => a > b),
904
new RelationalOperatorMethod<long, long> (this, (a, b) => a > b),
905
new RelationalOperatorMethod<ulong, ulong> (this, (a, b) => a > b),
906
new RelationalOperatorMethod<float, float> (this, (a, b) => a > b),
907
new RelationalOperatorMethod<double, double> (this, (a, b) => a > b),
908
new RelationalOperatorMethod<decimal, decimal>(this, (a, b) => a > b)
914
OperatorMethod[] greaterThanOrEqualOperators;
916
public OperatorMethod[] GreaterThanOrEqualOperators {
918
OperatorMethod[] ops = LazyInit.VolatileRead(ref greaterThanOrEqualOperators);
922
return LazyInit.GetOrSet(ref greaterThanOrEqualOperators, Lift(
923
new RelationalOperatorMethod<int, int> (this, (a, b) => a >= b),
924
new RelationalOperatorMethod<uint, uint> (this, (a, b) => a >= b),
925
new RelationalOperatorMethod<long, long> (this, (a, b) => a >= b),
926
new RelationalOperatorMethod<ulong, ulong> (this, (a, b) => a >= b),
927
new RelationalOperatorMethod<float, float> (this, (a, b) => a >= b),
928
new RelationalOperatorMethod<double, double> (this, (a, b) => a >= b),
929
new RelationalOperatorMethod<decimal, decimal>(this, (a, b) => a >= b)
936
#region Bitwise operators
937
OperatorMethod[] logicalAndOperators;
939
public OperatorMethod[] LogicalAndOperators {
941
OperatorMethod[] ops = LazyInit.VolatileRead(ref logicalAndOperators);
945
return LazyInit.GetOrSet(ref logicalAndOperators, new OperatorMethod[] {
946
new LambdaBinaryOperatorMethod<bool, bool>(this, (a, b) => a & b)
953
OperatorMethod[] bitwiseAndOperators;
955
public OperatorMethod[] BitwiseAndOperators {
957
OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseAndOperators);
961
return LazyInit.GetOrSet(ref bitwiseAndOperators, Lift(
962
new LambdaBinaryOperatorMethod<int, int> (this, (a, b) => a & b),
963
new LambdaBinaryOperatorMethod<uint, uint> (this, (a, b) => a & b),
964
new LambdaBinaryOperatorMethod<long, long> (this, (a, b) => a & b),
965
new LambdaBinaryOperatorMethod<ulong, ulong>(this, (a, b) => a & b),
966
this.LogicalAndOperators[0]
973
OperatorMethod[] logicalOrOperators;
975
public OperatorMethod[] LogicalOrOperators {
977
OperatorMethod[] ops = LazyInit.VolatileRead(ref logicalOrOperators);
981
return LazyInit.GetOrSet(ref logicalOrOperators, new OperatorMethod[] {
982
new LambdaBinaryOperatorMethod<bool, bool>(this, (a, b) => a | b)
988
OperatorMethod[] bitwiseOrOperators;
990
public OperatorMethod[] BitwiseOrOperators {
992
OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseOrOperators);
996
return LazyInit.GetOrSet(ref bitwiseOrOperators, Lift(
997
new LambdaBinaryOperatorMethod<int, int> (this, (a, b) => a | b),
998
new LambdaBinaryOperatorMethod<uint, uint> (this, (a, b) => a | b),
999
new LambdaBinaryOperatorMethod<long, long> (this, (a, b) => a | b),
1000
new LambdaBinaryOperatorMethod<ulong, ulong>(this, (a, b) => a | b),
1001
this.LogicalOrOperators[0]
1007
// Note: the logic for the lifted bool? bitwise operators is wrong;
1008
// we produce "true | null" = "null" when it should be true. However, this is irrelevant
1009
// because bool? cannot be a compile-time type.
1011
OperatorMethod[] bitwiseXorOperators;
1013
public OperatorMethod[] BitwiseXorOperators {
1015
OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseXorOperators);
1019
return LazyInit.GetOrSet(ref bitwiseXorOperators, Lift(
1020
new LambdaBinaryOperatorMethod<int, int> (this, (a, b) => a ^ b),
1021
new LambdaBinaryOperatorMethod<uint, uint> (this, (a, b) => a ^ b),
1022
new LambdaBinaryOperatorMethod<long, long> (this, (a, b) => a ^ b),
1023
new LambdaBinaryOperatorMethod<ulong, ulong>(this, (a, b) => a ^ b),
1024
new LambdaBinaryOperatorMethod<bool, bool> (this, (a, b) => a ^ b)