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));
            }
            }
        }
Exemple #3
0
        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);
        }
Exemple #7
0
        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());
        }
Exemple #8
0
        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));
            }
        }