private BoundExpression VisitObjectCreationExpressionInternal(BoundObjectCreationExpression node) { if (node.ConstantValue != null) { // typically a decimal constant. return(Constant(node)); } if ((object)node.Constructor == null || (node.Arguments.Length == 0 && !node.Type.IsStructType()) || node.Constructor.IsDefaultValueTypeConstructor()) { return(ExprFactory("New", _bound.Typeof(node.Type))); } var ctor = _bound.ConstructorInfo(node.Constructor); var args = _bound.Convert(_IEnumerableType.Construct(ExpressionType), Expressions(node.Arguments)); if (node.Type.IsAnonymousType && node.Arguments.Length != 0) { var anonType = (NamedTypeSymbol)node.Type; var membersBuilder = ArrayBuilder <BoundExpression> .GetInstance(); for (int i = 0; i < node.Arguments.Length; i++) { membersBuilder.Add(_bound.MethodInfo(AnonymousTypeManager.GetAnonymousTypeProperty(anonType, i).GetMethod)); } return(ExprFactory("New", ctor, args, _bound.ArrayOrEmpty(MemberInfoType, membersBuilder.ToImmutableAndFree()))); } else { return(ExprFactory("New", ctor, args)); } }
private BoundExpression VisitBinaryOperator(BinaryOperatorKind opKind, MethodSymbol methodOpt, TypeSymbol type, BoundExpression left, BoundExpression right) { bool isChecked, isLifted, requiresLifted; string opName = GetBinaryOperatorName(opKind, out isChecked, out isLifted, out requiresLifted); // Fix up the null value for a nullable comparison vs null if ((object)left.Type == null && left.IsLiteralNull()) { left = _bound.Default(right.Type); } if ((object)right.Type == null && right.IsLiteralNull()) { right = _bound.Default(left.Type); } // Enums are handled as per their promoted underlying type switch (opKind.OperandTypes()) { case BinaryOperatorKind.EnumAndUnderlying: case BinaryOperatorKind.UnderlyingAndEnum: case BinaryOperatorKind.Enum: { var enumOperand = (opKind.OperandTypes() == BinaryOperatorKind.UnderlyingAndEnum) ? right : left; var promotedType = PromotedType(enumOperand.Type.StrippedType().GetEnumUnderlyingType()); if (opKind.IsLifted()) { promotedType = _nullableType.Construct(promotedType); } var loweredLeft = VisitAndPromoteEnumOperand(left, promotedType, isChecked); var loweredRight = VisitAndPromoteEnumOperand(right, promotedType, isChecked); var result = MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight); return(Demote(result, type, isChecked)); } default: { var loweredLeft = Visit(left); var loweredRight = Visit(right); return(MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight)); } } }
internal LoweredDynamicOperation MakeDynamicOperation( BoundExpression binderConstruction, BoundExpression loweredReceiver, RefKind receiverRefKind, ImmutableArray <BoundExpression> loweredArguments, ImmutableArray <RefKind> refKinds, BoundExpression loweredRight, TypeSymbol resultType) { Debug.Assert(!loweredArguments.IsDefault); // get well-known types and members we need: NamedTypeSymbol delegateTypeOverMethodTypeParameters = GetDelegateType(loweredReceiver, receiverRefKind, loweredArguments, refKinds, loweredRight, resultType); NamedTypeSymbol callSiteTypeGeneric = _factory.WellKnownType(WellKnownType.core_runtime_compiler_CallSite_T); MethodSymbol callSiteFactoryGeneric = _factory.WellKnownMethod(WellKnownMember.System_Runtime_CompilerServices_CallSite_T__Create); FieldSymbol callSiteTargetFieldGeneric = (FieldSymbol)_factory.WellKnownMember(WellKnownMember.System_Runtime_CompilerServices_CallSite_T__Target); MethodSymbol delegateInvoke; if (binderConstruction == null || (object)delegateTypeOverMethodTypeParameters == null || delegateTypeOverMethodTypeParameters.IsErrorType() || (object)(delegateInvoke = delegateTypeOverMethodTypeParameters.DelegateInvokeMethod) == null || callSiteTypeGeneric.IsErrorType() || (object)callSiteFactoryGeneric == null || (object)callSiteTargetFieldGeneric == null) { // CS1969: One or more types required to compile a dynamic expression cannot be found. // Dev11 reports it with source location for each dynamic operation, which results in many error messages. // The diagnostic that names the specific missing type or member has already been reported. _factory.Diagnostics.Add(ErrorCode.ERR_DynamicRequiredTypesMissing, NoLocation.Singleton); return(LoweredDynamicOperation.Bad(loweredReceiver, loweredArguments, loweredRight, resultType)); } if ((object)_currentDynamicCallSiteContainer == null) { _currentDynamicCallSiteContainer = CreateCallSiteContainer(_factory, _methodOrdinal); } var containerDef = (SynthesizedContainer)_currentDynamicCallSiteContainer.OriginalDefinition; var methodToContainerTypeParametersMap = containerDef.TypeMap; ImmutableArray <LocalSymbol> temps = MakeTempsForDiscardArguments(ref loweredArguments); var callSiteType = callSiteTypeGeneric.Construct(new[] { delegateTypeOverMethodTypeParameters }); var callSiteFactoryMethod = callSiteFactoryGeneric.AsMember(callSiteType); var callSiteTargetField = callSiteTargetFieldGeneric.AsMember(callSiteType); var callSiteField = DefineCallSiteStorageSymbol(containerDef, delegateTypeOverMethodTypeParameters, methodToContainerTypeParametersMap); var callSiteFieldAccess = _factory.Field(null, callSiteField); var callSiteArguments = GetCallSiteArguments(callSiteFieldAccess, loweredReceiver, loweredArguments, loweredRight); var nullCallSite = _factory.Null(callSiteField.Type.TypeSymbol); var siteInitialization = _factory.Conditional( _factory.ObjectEqual(callSiteFieldAccess, nullCallSite), _factory.AssignmentExpression(callSiteFieldAccess, _factory.Call(null, callSiteFactoryMethod, binderConstruction)), nullCallSite, callSiteField.Type.TypeSymbol); var siteInvocation = _factory.Call( _factory.Field(callSiteFieldAccess, callSiteTargetField), delegateInvoke, callSiteArguments); return(new LoweredDynamicOperation(_factory, siteInitialization, siteInvocation, resultType, temps)); }
public void TestBaseTypeDynamicTransforms() { CommonTestInitialization(); // public class Base0 { } Assert.Equal(_objectType, _base0Class.BaseType()); Assert.False(_base0Class.ContainsDynamic()); // public class Base1<T> { } Assert.Equal(_objectType, _base1Class.BaseType()); Assert.False(_base1Class.ContainsDynamic()); // public class Base2<T, U> { } Assert.Equal(_objectType, _base2Class.BaseType()); Assert.False(_base2Class.ContainsDynamic()); // public class Derived<T> : Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic> where T : Derived<T> { ... } Assert.False(_derivedClass.ContainsDynamic()); Assert.True(_derivedClass.BaseType().ContainsDynamic()); // Outer<dynamic> var outerClassOfDynamic = _outerClass.Construct(s_dynamicType); // Outer<dynamic>.Inner<T[], dynamic> var t = _derivedClass.TypeParameters[0]; var arrayOfT = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(t)); var innerClassOfTArrDynamic = outerClassOfDynamic.GetTypeMember("Inner").Construct(arrayOfT, s_dynamicType); // Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[] var memberInnerInnerOfInt = innerClassOfTArrDynamic.GetTypeMember("InnerInner").Construct(_intType); var arrayOfInnerInnerOfInt = ArrayTypeSymbol.CreateCSharpArray(_assembly, TypeWithAnnotations.Create(memberInnerInnerOfInt)); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic> var memberComplicatedInner = outerClassOfDynamic.GetTypeMember("Inner").Construct(arrayOfInnerInnerOfInt, s_dynamicType); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic> var memberInnerInnerOfDynamic = memberComplicatedInner.GetTypeMember("InnerInner").Construct(s_dynamicType); Assert.Equal(memberInnerInnerOfDynamic, _derivedClass.BaseType()); // public class Outer<T> : Base1<dynamic> Assert.False(_outerClass.ContainsDynamic()); Assert.True(_outerClass.BaseType().ContainsDynamic()); var base1OfDynamic = _base1Class.Construct(s_dynamicType); Assert.Equal(base1OfDynamic, _outerClass.BaseType()); // public class Inner<U, V> : Base2<dynamic, V> Assert.False(_innerClass.ContainsDynamic()); Assert.True(_innerClass.BaseType().ContainsDynamic()); var base2OfDynamicV = _base2Class.Construct(s_dynamicType, _innerClass.TypeParameters[1]); Assert.Equal(base2OfDynamicV, _innerClass.BaseType()); // public class InnerInner<W> : Base1<dynamic> { } Assert.False(_innerInnerClass.ContainsDynamic()); Assert.True(_innerInnerClass.BaseType().ContainsDynamic()); Assert.Equal(base1OfDynamic, _innerInnerClass.BaseType()); // public class Outer2<T> : Base1<dynamic> Assert.False(_outer2Class.ContainsDynamic()); Assert.True(_outer2Class.BaseType().ContainsDynamic()); Assert.Equal(base1OfDynamic, _outer2Class.BaseType()); // public class Inner2<U, V> : Base0 Assert.False(_inner2Class.ContainsDynamic()); Assert.False(_inner2Class.BaseType().ContainsDynamic()); Assert.Equal(_base0Class, _inner2Class.BaseType()); // public class InnerInner2<W> : Base0 { } Assert.False(_innerInner2Class.ContainsDynamic()); Assert.False(_innerInner2Class.BaseType().ContainsDynamic()); Assert.Equal(_base0Class, _innerInner2Class.BaseType()); // public class Inner3<U> Assert.False(_inner3Class.ContainsDynamic()); }
public void ReadOnlyStructApiMetadata() { var text1 = @" class Program { readonly struct S1 { public S1(int dummy) { } public string M1() { return ""1""; } public override string ToString() { return ""2""; } } readonly struct S1<T> { public S1(int dummy) { } public string M1() { return ""1""; } public override string ToString() { return ""2""; } } struct S2 { public S2(int dummy) { } public string M1() { return ""1""; } public override string ToString() { return ""2""; } } class C1 { public C1(int dummy) { } public string M1() { return ""1""; } public override string ToString() { return ""2""; } } delegate int D1(); } "; var comp1 = CreateCompilation(text1, assemblyName: "A"); var ref1 = comp1.EmitToImageReference(); var comp = CreateCompilation("//NO CODE HERE", new[] { ref1 }, parseOptions: TestOptions.Regular); // S1 NamedTypeSymbol namedType = comp.GetTypeByMetadataName("Program+S1"); Assert.True(namedType.IsReadOnly); Assert.Equal(RefKind.Out, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("M1").ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("ToString").ThisParameter.RefKind); // S1<T> namedType = comp.GetTypeByMetadataName("Program+S1`1"); Assert.True(namedType.IsReadOnly); Assert.Equal(RefKind.Out, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("M1").ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("ToString").ThisParameter.RefKind); // T TypeSymbol type = namedType.TypeParameters[0]; Assert.True(namedType.IsReadOnly); Assert.Equal(RefKind.Out, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("M1").ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("ToString").ThisParameter.RefKind); // S1<object> namedType = namedType.Construct(comp.ObjectType); Assert.True(namedType.IsReadOnly); Assert.Equal(RefKind.Out, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("M1").ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("ToString").ThisParameter.RefKind); // S2 namedType = comp.GetTypeByMetadataName("Program+S2"); Assert.False(namedType.IsReadOnly); Assert.Equal(RefKind.Out, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.Ref, namedType.GetMethod("M1").ThisParameter.RefKind); Assert.Equal(RefKind.Ref, namedType.GetMethod("ToString").ThisParameter.RefKind); // C1 namedType = comp.GetTypeByMetadataName("Program+C1"); Assert.False(namedType.IsReadOnly); Assert.Equal(RefKind.None, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.None, namedType.GetMethod("M1").ThisParameter.RefKind); Assert.Equal(RefKind.None, namedType.GetMethod("ToString").ThisParameter.RefKind); // D1 namedType = comp.GetTypeByMetadataName("Program+D1"); Assert.False(namedType.IsReadOnly); Assert.Equal(RefKind.None, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.None, namedType.GetMethod("Invoke").ThisParameter.RefKind); // object[] type = comp.CreateArrayTypeSymbol(comp.ObjectType); Assert.False(type.IsReadOnly); // dynamic type = comp.DynamicType; Assert.False(type.IsReadOnly); // object type = comp.ObjectType; Assert.False(type.IsReadOnly); // anonymous type type = (TypeSymbol)comp.CreateAnonymousTypeSymbol(ImmutableArray.Create <ITypeSymbol>(comp.ObjectType), ImmutableArray.Create("qq")); Assert.False(type.IsReadOnly); // pointer type type = (TypeSymbol)comp.CreatePointerTypeSymbol(comp.ObjectType); Assert.False(type.IsReadOnly); // tuple type type = (TypeSymbol)comp.CreateTupleTypeSymbol(ImmutableArray.Create <ITypeSymbol>(comp.ObjectType, comp.ObjectType)); Assert.False(type.IsReadOnly); }
public void ReadOnlyStructApi() { var text = @" class Program { readonly struct S1 { public S1(int dummy) { } public string M1() { return ""1""; } public override string ToString() { return ""2""; } } readonly struct S1<T> { public S1(int dummy) { } public string M1() { return ""1""; } public override string ToString() { return ""2""; } } struct S2 { public S2(int dummy) { } public string M1() { return ""1""; } public override string ToString() { return ""2""; } } class C1 { public C1(int dummy) { } public string M1() { return ""1""; } public override string ToString() { return ""2""; } } delegate int D1(); } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular); // S1 NamedTypeSymbol namedType = comp.GetTypeByMetadataName("Program+S1"); Assert.True(namedType.IsReadOnly); Assert.Equal(RefKind.Out, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("M1").ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("ToString").ThisParameter.RefKind); void validate(ModuleSymbol module) { var test = module.ContainingAssembly.GetTypeByMetadataName("Program+S1"); var peModule = (PEModuleSymbol)module; Assert.True(peModule.Module.HasIsReadOnlyAttribute(((PENamedTypeSymbol)test).Handle)); AssertDeclaresType(peModule, WellKnownType.System_Runtime_CompilerServices_IsReadOnlyAttribute, Accessibility.Internal); } CompileAndVerify(comp, symbolValidator: validate); // S1<T> namedType = comp.GetTypeByMetadataName("Program+S1`1"); Assert.True(namedType.IsReadOnly); Assert.Equal(RefKind.Out, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("M1").ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("ToString").ThisParameter.RefKind); // T TypeSymbol type = namedType.TypeParameters[0]; Assert.True(namedType.IsReadOnly); Assert.Equal(RefKind.Out, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("M1").ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("ToString").ThisParameter.RefKind); // S1<object> namedType = namedType.Construct(comp.ObjectType); Assert.True(namedType.IsReadOnly); Assert.Equal(RefKind.Out, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("M1").ThisParameter.RefKind); Assert.Equal(RefKind.In, namedType.GetMethod("ToString").ThisParameter.RefKind); // S2 namedType = comp.GetTypeByMetadataName("Program+S2"); Assert.False(namedType.IsReadOnly); Assert.Equal(RefKind.Out, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.Ref, namedType.GetMethod("M1").ThisParameter.RefKind); Assert.Equal(RefKind.Ref, namedType.GetMethod("ToString").ThisParameter.RefKind); // C1 namedType = comp.GetTypeByMetadataName("Program+C1"); Assert.False(namedType.IsReadOnly); Assert.Equal(RefKind.None, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.None, namedType.GetMethod("M1").ThisParameter.RefKind); Assert.Equal(RefKind.None, namedType.GetMethod("ToString").ThisParameter.RefKind); // D1 namedType = comp.GetTypeByMetadataName("Program+D1"); Assert.False(namedType.IsReadOnly); Assert.Equal(RefKind.None, namedType.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.None, namedType.GetMethod("Invoke").ThisParameter.RefKind); // object[] type = comp.CreateArrayTypeSymbol(comp.ObjectType); Assert.False(type.IsReadOnly); // dynamic type = comp.DynamicType; Assert.False(type.IsReadOnly); // object type = comp.ObjectType; Assert.False(type.IsReadOnly); // anonymous type type = (TypeSymbol)comp.CreateAnonymousTypeSymbol(ImmutableArray.Create <ITypeSymbol>(comp.ObjectType), ImmutableArray.Create("qq")); Assert.False(type.IsReadOnly); // pointer type type = (TypeSymbol)comp.CreatePointerTypeSymbol(comp.ObjectType); Assert.False(type.IsReadOnly); // tuple type type = (TypeSymbol)comp.CreateTupleTypeSymbol(ImmutableArray.Create <ITypeSymbol>(comp.ObjectType, comp.ObjectType)); Assert.False(type.IsReadOnly); // S1 from image var clientComp = CreateCompilation("", references: new[] { comp.EmitToImageReference() }); NamedTypeSymbol s1 = clientComp.GetTypeByMetadataName("Program+S1"); Assert.True(s1.IsReadOnly); Assert.Empty(s1.GetAttributes()); Assert.Equal(RefKind.Out, s1.Constructors[0].ThisParameter.RefKind); Assert.Equal(RefKind.In, s1.GetMethod("M1").ThisParameter.RefKind); Assert.Equal(RefKind.In, s1.GetMethod("ToString").ThisParameter.RefKind); }
public void TestBaseTypeDynamicTransforms() { CommonTestInitialization(); // public class Base0 { } Assert.Equal(objectType, base0Class.BaseType); Assert.False(base0Class.ContainsDynamic()); // public class Base1<T> { } Assert.Equal(objectType, base1Class.BaseType); Assert.False(base1Class.ContainsDynamic()); // public class Base2<T, U> { } Assert.Equal(objectType, base2Class.BaseType); Assert.False(base2Class.ContainsDynamic()); // public class Derived<T> : Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic> where T : Derived<T> { ... } Assert.False(derivedClass.ContainsDynamic()); Assert.True(derivedClass.BaseType.ContainsDynamic()); // Outer<dynamic> var outerClassOfDynamic = outerClass.Construct(dynamicType); // Outer<dynamic>.Inner<T[], dynamic> var t = derivedClass.TypeParameters[0]; var arrayOfT = new ArrayTypeSymbol(assembly, t); var innerClassOfTArrDynamic = outerClassOfDynamic.GetTypeMember("Inner").Construct(arrayOfT, dynamicType); // Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[] var memberInnerInnerOfInt = innerClassOfTArrDynamic.GetTypeMember("InnerInner").Construct(intType); var arrayOfInnerInnerOfInt = new ArrayTypeSymbol(assembly, memberInnerInnerOfInt); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic> var memberComplicatedInner = outerClassOfDynamic.GetTypeMember("Inner").Construct(arrayOfInnerInnerOfInt, dynamicType); // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int>[], dynamic>.InnerInner<dynamic> var memberInnerInnerOfDynamic = memberComplicatedInner.GetTypeMember("InnerInner").Construct(dynamicType); Assert.Equal(memberInnerInnerOfDynamic, derivedClass.BaseType); // public class Outer<T> : Base1<dynamic> Assert.False(outerClass.ContainsDynamic()); Assert.True(outerClass.BaseType.ContainsDynamic()); var base1OfDynamic = base1Class.Construct(dynamicType); Assert.Equal(base1OfDynamic, outerClass.BaseType); // public class Inner<U, V> : Base2<dynamic, V> Assert.False(innerClass.ContainsDynamic()); Assert.True(innerClass.BaseType.ContainsDynamic()); var base2OfDynamicV = base2Class.Construct(dynamicType, innerClass.TypeParameters[1]); Assert.Equal(base2OfDynamicV, innerClass.BaseType); // public class InnerInner<W> : Base1<dynamic> { } Assert.False(innerInnerClass.ContainsDynamic()); Assert.True(innerInnerClass.BaseType.ContainsDynamic()); Assert.Equal(base1OfDynamic, innerInnerClass.BaseType); // public class Outer2<T> : Base1<dynamic> Assert.False(outer2Class.ContainsDynamic()); Assert.True(outer2Class.BaseType.ContainsDynamic()); Assert.Equal(base1OfDynamic, outer2Class.BaseType); // public class Inner2<U, V> : Base0 Assert.False(inner2Class.ContainsDynamic()); Assert.False(inner2Class.BaseType.ContainsDynamic()); Assert.Equal(base0Class, inner2Class.BaseType); // public class InnerInner2<W> : Base0 { } Assert.False(innerInner2Class.ContainsDynamic()); Assert.False(innerInner2Class.BaseType.ContainsDynamic()); Assert.Equal(base0Class, innerInner2Class.BaseType); // public class Inner3<U> Assert.False(inner3Class.ContainsDynamic()); }
private BoundExpression VisitBinaryOperator(BoundBinaryOperator node) { var opKind = node.OperatorKind; var op = opKind & BinaryOperatorKind.OpMask; var isChecked = (opKind & BinaryOperatorKind.Checked) != 0; var isLogical = (opKind & BinaryOperatorKind.Logical) != 0; var isLifted = (opKind & BinaryOperatorKind.Lifted) != 0; bool requiresLifted = false; string opname; switch (op) { case BinaryOperatorKind.Addition: opname = isChecked ? "AddChecked" : "Add"; break; case BinaryOperatorKind.Multiplication: opname = isChecked ? "MultiplyChecked" : "Multiply"; break; case BinaryOperatorKind.Subtraction: opname = isChecked ? "SubtractChecked" : "Subtract"; break; case BinaryOperatorKind.Division: opname = "Divide"; break; case BinaryOperatorKind.Remainder: opname = "Modulo"; break; case BinaryOperatorKind.And: opname = isLogical ? "AndAlso" : "And"; break; case BinaryOperatorKind.Xor: opname = "ExclusiveOr"; break; case BinaryOperatorKind.Or: opname = isLogical ? "OrElse" : "Or"; break; case BinaryOperatorKind.LeftShift: opname = "LeftShift"; break; case BinaryOperatorKind.RightShift: opname = "RightShift"; break; case BinaryOperatorKind.Equal: opname = "Equal"; requiresLifted = true; break; case BinaryOperatorKind.NotEqual: opname = "NotEqual"; requiresLifted = true; break; case BinaryOperatorKind.LessThan: opname = "LessThan"; requiresLifted = true; break; case BinaryOperatorKind.LessThanOrEqual: opname = "LessThanOrEqual"; requiresLifted = true; break; case BinaryOperatorKind.GreaterThan: opname = "GreaterThan"; requiresLifted = true; break; case BinaryOperatorKind.GreaterThanOrEqual: opname = "GreaterThanOrEqual"; requiresLifted = true; break; default: throw ExceptionUtilities.UnexpectedValue(op); } BoundExpression left = node.Left; BoundExpression right = node.Right; // Fix up the null value for a nullable comparison vs null if ((object)left.Type == null && left.IsLiteralNull()) { left = Bound.Default(right.Type); } if ((object)right.Type == null && right.IsLiteralNull()) { right = Bound.Default(left.Type); } var loweredLeft = Visit(left); var loweredRight = Visit(right); // Enums are handled as per their promoted underlying type switch (node.OperatorKind.OperandTypes()) { case BinaryOperatorKind.Enum: case BinaryOperatorKind.EnumAndUnderlying: case BinaryOperatorKind.UnderlyingAndEnum: { var enumOperand = (node.OperatorKind.OperandTypes() == BinaryOperatorKind.UnderlyingAndEnum) ? right : left; var promotedType = PromotedType(enumOperand.Type.StrippedType().GetEnumUnderlyingType()); if (isLifted) { promotedType = NullableType.Construct(promotedType); } loweredLeft = Convert(loweredLeft, left.Type, promotedType, isChecked, false); loweredRight = Convert(loweredRight, right.Type, promotedType, isChecked, false); var result = MakeBinary(node, isLifted, requiresLifted, opname, loweredLeft, loweredRight); return(Demote(result, node.Type, isChecked)); } default: return(MakeBinary(node, isLifted, requiresLifted, opname, loweredLeft, loweredRight)); } }