Ejemplo n.º 1
0
        private static BlockExpression BlockCore(Type type, ReadOnlyCollection <ParameterExpression> variables, ReadOnlyCollection <Expression> expressions)
        {
            RequiresCanRead(expressions, nameof(expressions));
            ValidateVariables(variables, nameof(variables));

            if (type != null)
            {
                if (expressions.Count == 0)
                {
                    if (type != typeof(void))
                    {
                        throw Error.ArgumentTypesMustMatch();
                    }

                    return(new ScopeWithType(variables, expressions, type));
                }
                Expression last = expressions.Last();
                if (type != typeof(void))
                {
                    if (!TypeUtils.AreReferenceAssignable(type, last.Type))
                    {
                        throw Error.ArgumentTypesMustMatch();
                    }
                }

                if (!TypeUtils.AreEquivalent(type, last.Type))
                {
                    return(new ScopeWithType(variables, expressions, type));
                }
            }

            switch (expressions.Count)
            {
            case 0:
                return(new ScopeWithType(variables, expressions, typeof(void)));

            case 1:
                return(new Scope1(variables, expressions[0]));

            default:
                return(new ScopeN(variables, expressions));
            }
        }
Ejemplo n.º 2
0
        // Value types must stay as the same type, otherwise it's now a
        // different operation, e.g. adding two doubles vs adding two ints.
        private static void ValidateChildType(Type before, Type after, string methodName)
        {
            if (before.GetTypeInfo().IsValueType)
            {
                if (TypeUtils.AreEquivalent(before, after))
                {
                    // types are the same value type
                    return;
                }
            }
            else if (!after.GetTypeInfo().IsValueType)
            {
                // both are reference types
                return;
            }

            // Otherwise, it's an invalid type change.
            throw Error.MustRewriteChildToSameType(before, after, methodName);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Creates a <see cref="CatchBlock"/> representing a catch statement with the specified elements.
        /// </summary>
        /// <param name="type">The <see cref="Type"/> of <see cref="Exception"/> this <see cref="CatchBlock"/> will handle.</param>
        /// <param name="variable">A <see cref="ParameterExpression"/> representing a reference to the <see cref="Exception"/> object caught by this handler.</param>
        /// <param name="body">The body of the catch statement.</param>
        /// <param name="filter">The body of the <see cref="Exception"/> filter.</param>
        /// <returns>The created <see cref="CatchBlock"/>.</returns>
        /// <remarks><paramref name="type"/> must be non-null and match the type of <paramref name="variable"/> (if it is supplied).</remarks>
        public static CatchBlock MakeCatchBlock(Type type, ParameterExpression variable, Expression body, Expression filter)
        {
            ContractUtils.RequiresNotNull(type, "type");
            ContractUtils.Requires(variable == null || TypeUtils.AreEquivalent(variable.Type, type), "variable");
            if (variable != null && variable.IsByRef)
            {
                throw Error.VariableMustNotBeByRef(variable, variable.Type);
            }
            RequiresCanRead(body, "body");
            if (filter != null)
            {
                RequiresCanRead(filter, "filter");
                if (filter.Type != typeof(bool))
                {
                    throw Error.ArgumentMustBeBoolean();
                }
            }

            return(new CatchBlock(type, variable, body, filter));
        }
Ejemplo n.º 4
0
        private void AddressOf(IndexExpression node, Type type)
        {
            if (!TypeUtils.AreEquivalent(type, node.Type) || node.Indexer != null)
            {
                EmitExpressionAddress(node, type);
                return;
            }

            if (node.ArgumentCount == 1)
            {
                EmitExpression(node.Object);
                EmitExpression(node.GetArgument(0));
                _ilg.Emit(OpCodes.Ldelema, node.Type);
            }
            else
            {
                var address = node.Object.Type.GetMethod("Address", BindingFlags.Public | BindingFlags.Instance);
                EmitMethodCall(node.Object, address, node);
            }
        }
Ejemplo n.º 5
0
 /// <summary>
 /// If custom type is provided, all branches must be reference assignable to the result type.
 /// If no custom type is provided, all branches must have the same type - resultType.
 /// </summary>
 private static void ValidateSwitchCaseType(Expression @case, bool customType, Type resultType, string parameterName)
 {
     if (customType)
     {
         if (resultType != typeof(void))
         {
             if (!TypeUtils.AreReferenceAssignable(resultType, @case.Type))
             {
                 throw new ArgumentException(Strings.ArgumentTypesMustMatch, parameterName);
             }
         }
     }
     else
     {
         if (!TypeUtils.AreEquivalent(resultType, @case.Type))
         {
             throw new ArgumentException(Strings.AllCaseBodiesMustHaveSameType, parameterName);
         }
     }
 }
Ejemplo n.º 6
0
        // Emits the address of the expression, returning the write back if necessary
        //
        // For properties, we want to write back into the property if it's
        // passed byref.
        private WriteBack?EmitAddressWriteBack(Expression node, Type type)
        {
            var labelScopeChangeInfo = GetLabelScopeChangeInfo(true, _labelBlock, node);

            if (labelScopeChangeInfo.HasValue)
            {
                _labelBlock = new LabelScopeInfo(labelScopeChangeInfo.Value.parent, labelScopeChangeInfo.Value.kind);
                DefineBlockLabels(labelScopeChangeInfo.Value.nodes);
            }

            WriteBack?result = null;

            if (TypeUtils.AreEquivalent(type, node.Type))
            {
                switch (node.NodeType)
                {
                case ExpressionType.MemberAccess:
                    result = AddressOfWriteBack((MemberExpression)node);
                    break;

                case ExpressionType.Index:
                    result = AddressOfWriteBack((IndexExpression)node);
                    break;

                default:
                    break;
                }
            }

            if (result == null)
            {
                EmitAddress(node, type, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
            }

            if (labelScopeChangeInfo.HasValue)
            {
                _labelBlock = labelScopeChangeInfo.Value.parent;
            }

            return(result);
        }
Ejemplo n.º 7
0
        /// <summary>
        ///     Creates a <see cref="ConditionalExpression" />.
        /// </summary>
        /// <param name="test">An <see cref="Expression" /> to set the <see cref="ConditionalExpression.Test" /> property equal to.</param>
        /// <param name="ifTrue">
        ///     An <see cref="Expression" /> to set the <see cref="ConditionalExpression.IfTrue" /> property equal
        ///     to.
        /// </param>
        /// <param name="ifFalse">
        ///     An <see cref="Expression" /> to set the <see cref="ConditionalExpression.IfFalse" /> property
        ///     equal to.
        /// </param>
        /// <returns>
        ///     A <see cref="ConditionalExpression" /> that has the <see cref="NodeType" /> property equal to
        ///     <see cref="ExpressionType.Conditional" /> and the <see cref="ConditionalExpression.Test" />,
        ///     <see cref="ConditionalExpression.IfTrue" />,
        ///     and <see cref="ConditionalExpression.IfFalse" /> properties set to the specified values.
        /// </returns>
        public static ConditionalExpression Condition(Expression test, Expression ifTrue, Expression ifFalse)
        {
            ContractUtils.RequiresNotNull(test, nameof(test));
            ContractUtils.RequiresNotNull(ifTrue, nameof(ifTrue));
            ContractUtils.RequiresNotNull(ifFalse, nameof(ifFalse));
            ExpressionUtils.RequiresCanRead(test, nameof(test));
            ExpressionUtils.RequiresCanRead(ifTrue, nameof(ifTrue));
            ExpressionUtils.RequiresCanRead(ifFalse, nameof(ifFalse));

            if (test.Type != typeof(bool))
            {
                throw new ArgumentException("Argument must be boolean", nameof(test));
            }

            if (!TypeUtils.AreEquivalent(ifTrue.Type, ifFalse.Type))
            {
                throw new ArgumentException("Argument types do not match");
            }

            return(ConditionalExpression.Make(test, ifTrue, ifFalse, ifTrue.Type));
        }
Ejemplo n.º 8
0
 internal static MethodInfo FindConversionOperator(MethodInfo[] methods, Type typeFrom, Type typeTo, bool implicitOnly)
 {
     foreach (MethodInfo mi in methods)
     {
         if (mi.Name != "op_Implicit" && (implicitOnly || mi.Name != "op_Explicit"))
         {
             continue;
         }
         if (!TypeUtils.AreEquivalent(mi.ReturnType, typeTo))
         {
             continue;
         }
         ParameterInfo[] pis = mi.GetParametersCached();
         if (!TypeUtils.AreEquivalent(pis[0].ParameterType, typeFrom))
         {
             continue;
         }
         return(mi);
     }
     return(null);
 }
        private static void ValidateCustomBinaryAssign(CSharpExpressionType binaryType, Expression left, Expression right, ref MethodInfo method, LambdaExpression leftConversion, LambdaExpression finalConversion)
        {
            var leftType  = left.Type;
            var rightType = right.Type;

            if (leftConversion != null)
            {
                leftType = ValidateConversion(binaryType, leftType, leftConversion);
            }

            // NB: Just leverage LINQ to do the dirty work to check everything. Note that this assumes that the
            //     left conversion performed widening if that's required for the underlying operation. However,
            //     the use of FunctionalOp below will widen the right operand to match the left operand's type,
            //     which is what we do during Reduce as well (see remarks in FunctionalOp). This could produce
            //     mysterious error messages. (TODO: Review what's most appropriate here.)
            //
            // NB: We can't have it check the final conversion, because it doesn't allow these without the use of
            //     a custom method, so we check that ourselves further down.

            var leftDummy    = Expression.Parameter(leftType, "__left");
            var rightDummy   = Expression.Parameter(rightType, "__right");
            var functionalOp = FunctionalOp(binaryType, leftDummy, rightDummy, method);

            if (method == null)
            {
                method = functionalOp.Method;
            }

            var resultType = functionalOp.Type;

            if (finalConversion != null)
            {
                resultType = ValidateConversion(binaryType, resultType, finalConversion);
            }

            if (!TypeUtils.AreEquivalent(resultType, left.Type))
            {
                throw Error.InvalidCompoundAssignmentWithOperands(binaryType, left.Type, right.Type);
            }
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Creates a <see cref="BlockExpression"/> that contains the given variables and expressions.
        /// </summary>
        /// <param name="type">The result type of the block.</param>
        /// <param name="variables">The variables in the block.</param>
        /// <param name="expressions">The expressions in the block.</param>
        /// <returns>The created <see cref="BlockExpression"/>.</returns>
        public static BlockExpression Block(Type type, IEnumerable <ParameterExpression> variables, IEnumerable <Expression> expressions)
        {
            ContractUtils.RequiresNotNull(type, "type");
            ContractUtils.RequiresNotNull(expressions, "expressions");

            var expressionList = expressions.ToReadOnly();
            var variableList   = variables.ToReadOnly();

            ContractUtils.RequiresNotEmpty(expressionList, "expressions");
            RequiresCanRead(expressionList, "expressions");
            ValidateVariables(variableList, "variables");

            Expression last = expressionList.Last();

            if (type != typeof(void))
            {
                if (!TypeUtils.AreReferenceAssignable(type, last.Type))
                {
                    throw Error.ArgumentTypesMustMatch();
                }
            }

            if (!TypeUtils.AreEquivalent(type, last.Type))
            {
                return(new ScopeWithType(variableList, expressionList, type));
            }
            else
            {
                if (expressionList.Count == 1)
                {
                    return(new Scope1(variableList, expressionList[0]));
                }
                else
                {
                    return(new ScopeN(variableList, expressionList));
                }
            }
        }
Ejemplo n.º 11
0
 private void EmitExpressionAsType(Expression node, Type type, CompilationFlags flags)
 {
     if (type == typeof(void))
     {
         EmitExpressionAsVoid(node, flags);
     }
     else
     {
         // if the node is emitted as a different type, CastClass IL is emitted at the end,
         // should not emit with tail calls.
         if (!TypeUtils.AreEquivalent(node.Type, type))
         {
             EmitExpression(node);
             Debug.Assert(TypeUtils.AreReferenceAssignable(type, node.Type));
             _ilg.Emit(OpCodes.Castclass, type);
         }
         else
         {
             // emit the node with the flags and emit expression start
             EmitExpression(node, UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitExpressionStart));
         }
     }
 }
Ejemplo n.º 12
0
        internal static MethodInfo GetUserDefinedCoercionMethod(Type convertFrom, Type convertToType, bool implicitOnly)
        {
            // check for implicit coercions first
            Type nnExprType = TypeUtils.GetNonNullableType(convertFrom);
            Type nnConvType = TypeUtils.GetNonNullableType(convertToType);

            // try exact match on types
            MethodInfo[] eMethods = nnExprType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
            MethodInfo   method   = FindConversionOperator(eMethods, convertFrom, convertToType, implicitOnly);

            if (method != null)
            {
                return(method);
            }
            MethodInfo[] cMethods = nnConvType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
            method = FindConversionOperator(cMethods, convertFrom, convertToType, implicitOnly);
            if (method != null)
            {
                return(method);
            }
            // try lifted conversion
            if (!TypeUtils.AreEquivalent(nnExprType, convertFrom) ||
                !TypeUtils.AreEquivalent(nnConvType, convertToType))
            {
                method = FindConversionOperator(eMethods, nnExprType, nnConvType, implicitOnly);
                if (method == null)
                {
                    method = FindConversionOperator(cMethods, nnExprType, nnConvType, implicitOnly);
                }
                if (method != null)
                {
                    return(method);
                }
            }
            return(null);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Creates a <see cref="CatchBlock"/> representing a catch statement with the specified elements.
        /// </summary>
        /// <param name="type">The <see cref="Type"/> of <see cref="Exception"/> this <see cref="CatchBlock"/> will handle.</param>
        /// <param name="variable">A <see cref="ParameterExpression"/> representing a reference to the <see cref="Exception"/> object caught by this handler.</param>
        /// <param name="body">The body of the catch statement.</param>
        /// <param name="filter">The body of the <see cref="Exception"/> filter.</param>
        /// <returns>The created <see cref="CatchBlock"/>.</returns>
        /// <remarks><paramref name="type"/> must be non-null and match the type of <paramref name="variable"/> (if it is supplied).</remarks>
        public static CatchBlock MakeCatchBlock(Type type, ParameterExpression?variable, Expression body, Expression?filter)
        {
            ContractUtils.RequiresNotNull(type, nameof(type));
            ContractUtils.Requires(variable == null || TypeUtils.AreEquivalent(variable.Type, type), nameof(variable));
            if (variable == null)
            {
                TypeUtils.ValidateType(type, nameof(type));
            }
            else if (variable.IsByRef)
            {
                throw Error.VariableMustNotBeByRef(variable, variable.Type, nameof(variable));
            }
            ExpressionUtils.RequiresCanRead(body, nameof(body));
            if (filter != null)
            {
                ExpressionUtils.RequiresCanRead(filter, nameof(filter));
                if (filter.Type != typeof(bool))
                {
                    throw Error.ArgumentMustBeBoolean(nameof(filter));
                }
            }

            return(new CatchBlock(type, variable, body, filter));
        }
Ejemplo n.º 14
0
        private static void ValidateNewArgs(ConstructorInfo constructor, ref ReadOnlyCollection <Expression> arguments, ref ReadOnlyCollection <MemberInfo> members)
        {
            ParameterInfo[] pis;
            if ((pis = constructor.GetParametersCached()).Length > 0)
            {
                if (arguments.Count != pis.Length)
                {
                    throw Error.IncorrectNumberOfConstructorArguments();
                }
                if (arguments.Count != members.Count)
                {
                    throw Error.IncorrectNumberOfArgumentsForMembers();
                }
                Expression[]? newArguments = null;
                MemberInfo[]? newMembers   = null;
                for (int i = 0, n = arguments.Count; i < n; i++)
                {
                    Expression arg = arguments[i];
                    ExpressionUtils.RequiresCanRead(arg, nameof(arguments), i);
                    MemberInfo member = members[i];
                    ContractUtils.RequiresNotNull(member, nameof(members), i);
                    if (!TypeUtils.AreEquivalent(member.DeclaringType, constructor.DeclaringType))
                    {
                        throw Error.ArgumentMemberNotDeclOnType(member.Name, constructor.DeclaringType !.Name, nameof(members), i);
                    }
                    Type memberType;
                    ValidateAnonymousTypeMember(ref member, out memberType, nameof(members), i);
                    if (!TypeUtils.AreReferenceAssignable(memberType, arg.Type))
                    {
                        if (!TryQuote(memberType, ref arg))
                        {
                            throw Error.ArgumentTypeDoesNotMatchMember(arg.Type, memberType, nameof(arguments), i);
                        }
                    }
                    ParameterInfo pi    = pis[i];
                    Type          pType = pi.ParameterType;
                    if (pType.IsByRef)
                    {
                        pType = pType.GetElementType() !;
                    }
                    if (!TypeUtils.AreReferenceAssignable(pType, arg.Type))
                    {
                        if (!TryQuote(pType, ref arg))
                        {
                            throw Error.ExpressionTypeDoesNotMatchConstructorParameter(arg.Type, pType, nameof(arguments), i);
                        }
                    }
                    if (newArguments == null && arg != arguments[i])
                    {
                        newArguments = new Expression[arguments.Count];
                        for (int j = 0; j < i; j++)
                        {
                            newArguments[j] = arguments[j];
                        }
                    }
                    if (newArguments != null)
                    {
                        newArguments[i] = arg;
                    }

                    if (newMembers == null && member != members[i])
                    {
                        newMembers = new MemberInfo[members.Count];
                        for (int j = 0; j < i; j++)
                        {
                            newMembers[j] = members[j];
                        }
                    }
                    if (newMembers != null)
                    {
                        newMembers[i] = member;
                    }
                }
                if (newArguments != null)
                {
                    arguments = new TrueReadOnlyCollection <Expression>(newArguments);
                }
                if (newMembers != null)
                {
                    members = new TrueReadOnlyCollection <MemberInfo>(newMembers);
                }
            }
            else if (arguments != null && arguments.Count > 0)
            {
                throw Error.IncorrectNumberOfConstructorArguments();
            }
            else if (members != null && members.Count > 0)
            {
                throw Error.IncorrectNumberOfMembersForGivenConstructor();
            }
        }
Ejemplo n.º 15
0
 public override bool Equals(object obj)
 {
     return(obj is TypeRestriction other && other._expression == _expression && TypeUtils.AreEquivalent(other._type, _type));
 }
Ejemplo n.º 16
0
 /// <summary>
 ///     Returns our Expression converted to DynamicObject
 /// </summary>
 private Expression GetLimitedSelf()
 {
     // Convert to DynamicObject rather than LimitType, because
     // the limit type might be non-public.
     return(TypeUtils.AreEquivalent(Expression.Type, typeof(DynamicObject)) ? Expression : Expression.Convert(Expression, typeof(DynamicObject)));
 }
Ejemplo n.º 17
0
        // Tries to emit switch as a jmp table
        private bool TryEmitSwitchInstruction(SwitchExpression node, CompilationFlags flags)
        {
            // If we have a comparison, bail
            if (node.Comparison != null)
            {
                return(false);
            }

            // Make sure the switch value type and the right side type
            // are types we can optimize
            Type type = node.SwitchValue.Type;

            if (!CanOptimizeSwitchType(type) ||
                !TypeUtils.AreEquivalent(type, node.Cases[0].TestValues[0].Type))
            {
                return(false);
            }

            // Make sure all test values are constant, or we can't emit the
            // jump table.
            if (!node.Cases.All(c => c.TestValues.All(t => t is ConstantExpression)))
            {
                return(false);
            }

            //
            // We can emit the optimized switch, let's do it.
            //

            // Build target labels, collect keys.
            var labels = new Label[node.Cases.Count];
            var isGoto = new bool[node.Cases.Count];

            var uniqueKeys = new HashSet <decimal>();
            var keys       = new List <SwitchLabel>();

            for (int i = 0; i < node.Cases.Count; i++)
            {
                DefineSwitchCaseLabel(node.Cases[i], out labels[i], out isGoto[i]);

                foreach (ConstantExpression test in node.Cases[i].TestValues)
                {
                    // Guaranteed to work thanks to CanOptimizeSwitchType.
                    //
                    // Use decimal because it can hold Int64 or UInt64 without
                    // precision loss or signed/unsigned conversions.
                    decimal key = ConvertSwitchValue(test.Value);

                    // Only add each key once. If it appears twice, it's
                    // allowed, but can't be reached.
                    if (uniqueKeys.Add(key))
                    {
                        keys.Add(new SwitchLabel(key, test.Value, labels[i]));
                    }
                }
            }

            // Sort the keys, and group them into buckets.
            keys.Sort((x, y) => Math.Sign(x.Key - y.Key));
            var buckets = new List <List <SwitchLabel> >();

            foreach (var key in keys)
            {
                AddToBuckets(buckets, key);
            }

            // Emit the switchValue
            LocalBuilder value = GetLocal(node.SwitchValue.Type);

            EmitExpression(node.SwitchValue);
            _ilg.Emit(OpCodes.Stloc, value);

            // Create end label, and default label if needed
            Label end      = _ilg.DefineLabel();
            Label @default = (node.DefaultBody == null) ? end : _ilg.DefineLabel();

            // Emit the switch
            var info = new SwitchInfo(node, value, @default);

            EmitSwitchBuckets(info, buckets, 0, buckets.Count - 1);

            // Emit the case bodies and default
            EmitSwitchCases(node, labels, isGoto, @default, end, flags);

            FreeLocal(value);
            return(true);
        }
Ejemplo n.º 18
0
        private static void ValidateNewArgs(ConstructorInfo constructor, ref Expression[] arguments, ref ReadOnlyCollectionEx <MemberInfo> members)
        {
            ParameterInfo[] pis = constructor.GetParameters();
            if (pis.Length > 0)
            {
                if (arguments.Length != pis.Length)
                {
                    throw new ArgumentException("Incorrect number of arguments for constructor");
                }

                if (arguments.Length != members.Count)
                {
                    throw new ArgumentException("Incorrect number of arguments for the given members ");
                }

                Expression[]? newArguments = null;
                MemberInfo[]? newMembers   = null;
                for (int i = 0, n = arguments.Length; i < n; i++)
                {
                    var arg = arguments[i];
                    ContractUtils.RequiresNotNull(arg, nameof(arguments), i);
                    ExpressionUtils.RequiresCanRead(arg, nameof(arguments), i);
                    var member = members[i];
                    ContractUtils.RequiresNotNull(member, nameof(members), i);
                    if (!TypeUtils.AreEquivalent(member.DeclaringType, constructor.DeclaringType))
                    {
                        throw new ArgumentException($" The member '{member.Name}' is not declared on type '{constructor.DeclaringType?.Name}' being created", i >= 0 ? $"{nameof(members)}[{i}]" : nameof(members));
                    }

                    ValidateAnonymousTypeMember(ref member, out var memberType, nameof(members), i);
                    if (!memberType.IsReferenceAssignableFromInternal(arg.Type) && !TryQuote(memberType, ref arg))
                    {
                        throw new ArgumentException($" Argument type '{arg.Type}' does not match the corresponding member type '{memberType}'", i >= 0 ? $"{nameof(arguments)}[{i}]" : nameof(arguments));
                    }

                    var pi    = pis[i];
                    var pType = pi.ParameterType;
                    if (pType.IsByRef)
                    {
                        pType = pType.GetElementType();
                    }

                    if (!pType.IsReferenceAssignableFromInternal(arg.Type) && !TryQuote(pType, ref arg))
                    {
                        throw new ArgumentException($"Expression of type '{arg.Type}' cannot be used for constructor parameter of type '{pType}'", i >= 0 ? $"{nameof(arguments)}[{i}]" : nameof(arguments));
                    }

                    if (newArguments == null && arg != arguments[i])
                    {
                        newArguments = new Expression[arguments.Length];
                        for (var j = 0; j < i; j++)
                        {
                            newArguments[j] = arguments[j];
                        }
                    }

                    if (newArguments != null)
                    {
                        newArguments[i] = arg;
                    }

                    if (newMembers == null && member != members[i])
                    {
                        newMembers = new MemberInfo[members.Count];
                        for (var j = 0; j < i; j++)
                        {
                            newMembers[j] = members[j];
                        }
                    }

                    if (newMembers != null)
                    {
                        newMembers[i] = member;
                    }
                }

                if (newArguments != null)
                {
                    arguments = newArguments;
                }

                if (newMembers != null)
                {
                    members = ReadOnlyCollectionEx.Create(newMembers);
                }
            }
            else if (arguments?.Length > 0)
            {
                throw new ArgumentException("Incorrect number of arguments for constructor");
            }
            else if (members?.Count > 0)
            {
                throw new ArgumentException("Incorrect number of members for constructor");
            }
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Creates a <see cref="SwitchExpression"/>.
        /// </summary>
        /// <param name="type">The result type of the switch.</param>
        /// <param name="switchValue">The value to be tested against each case.</param>
        /// <param name="defaultBody">The result of the switch if no cases are matched.</param>
        /// <param name="comparison">The equality comparison method to use.</param>
        /// <param name="cases">The valid cases for this switch.</param>
        /// <returns>The created <see cref="SwitchExpression"/>.</returns>
        public static SwitchExpression Switch(Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison, IEnumerable <SwitchCase> cases)
        {
            RequiresCanRead(switchValue, "switchValue");
            if (switchValue.Type == typeof(void))
            {
                throw Error.ArgumentCannotBeOfTypeVoid();
            }

            var caseList = cases.ToReadOnly();

            ContractUtils.RequiresNotEmpty(caseList, "cases");
            ContractUtils.RequiresNotNullItems(caseList, "cases");

            // Type of the result. Either provided, or it is type of the branches.
            Type resultType = type ?? caseList[0].Body.Type;
            bool customType = type != null;

            if (comparison != null)
            {
                var pms = comparison.GetParametersCached();
                if (pms.Length != 2)
                {
                    throw Error.IncorrectNumberOfMethodCallArguments(comparison);
                }
                // Validate that the switch value's type matches the comparison method's
                // left hand side parameter type.
                var  leftParam  = pms[0];
                bool liftedCall = false;
                if (!ParameterIsAssignable(leftParam, switchValue.Type))
                {
                    liftedCall = ParameterIsAssignable(leftParam, switchValue.Type.GetNonNullableType());
                    if (!liftedCall)
                    {
                        throw Error.SwitchValueTypeDoesNotMatchComparisonMethodParameter(switchValue.Type, leftParam.ParameterType);
                    }
                }

                var rightParam = pms[1];
                foreach (var c in caseList)
                {
                    ContractUtils.RequiresNotNull(c, "cases");
                    ValidateSwitchCaseType(c.Body, customType, resultType, "cases");
                    for (int i = 0; i < c.TestValues.Count; i++)
                    {
                        // When a comparison method is provided, test values can have different type but have to
                        // be reference assignable to the right hand side parameter of the method.
                        Type rightOperandType = c.TestValues[i].Type;
                        if (liftedCall)
                        {
                            if (!rightOperandType.IsNullableType())
                            {
                                throw Error.TestValueTypeDoesNotMatchComparisonMethodParameter(rightOperandType, rightParam.ParameterType);
                            }
                            rightOperandType = rightOperandType.GetNonNullableType();
                        }
                        if (!ParameterIsAssignable(rightParam, rightOperandType))
                        {
                            throw Error.TestValueTypeDoesNotMatchComparisonMethodParameter(rightOperandType, rightParam.ParameterType);
                        }
                    }
                }
            }
            else
            {
                // When comparison method is not present, all the test values must have
                // the same type. Use the first test value's type as the baseline.
                var firstTestValue = caseList[0].TestValues[0];
                foreach (var c in caseList)
                {
                    ContractUtils.RequiresNotNull(c, "cases");
                    ValidateSwitchCaseType(c.Body, customType, resultType, "cases");
                    // When no comparison method is provided, require all test values to have the same type.
                    for (int i = 0; i < c.TestValues.Count; i++)
                    {
                        if (!TypeUtils.AreEquivalent(firstTestValue.Type, c.TestValues[i].Type))
                        {
                            throw new ArgumentException(Strings.AllTestValuesMustHaveSameType, "cases");
                        }
                    }
                }

                // Now we need to validate that switchValue.Type and testValueType
                // make sense in an Equal node. Fortunately, Equal throws a
                // reasonable error, so just call it.
                var equal = Equal(switchValue, firstTestValue, false, comparison);

                // Get the comparison function from equals node.
                comparison = equal.Method;
            }

            if (defaultBody == null)
            {
                if (resultType != typeof(void))
                {
                    throw Error.DefaultBodyMustBeSupplied();
                }
            }
            else
            {
                ValidateSwitchCaseType(defaultBody, customType, resultType, "defaultBody");
            }

            // if we have a non-boolean userdefined equals, we don't want it.
            if (comparison != null && comparison.ReturnType != typeof(bool))
            {
                throw Error.EqualityMustReturnBoolean(comparison);
            }

            return(new SwitchExpression(resultType, switchValue, defaultBody, comparison, caseList));
        }
Ejemplo n.º 20
0
        private void EmitUnaryOperator(ExpressionType op, Type operandType, Type resultType)
        {
            bool operandIsNullable = TypeUtils.IsNullableType(operandType);

            if (op == ExpressionType.ArrayLength)
            {
                _ilg.Emit(OpCodes.Ldlen);
                return;
            }

            if (operandIsNullable)
            {
                switch (op)
                {
                case ExpressionType.Not:
                {
                    if (operandType != typeof(bool?))
                    {
                        goto case ExpressionType.Negate;
                    }
                    Label        labEnd = _ilg.DefineLabel();
                    LocalBuilder loc    = GetLocal(operandType);

                    // store values (reverse order since they are already on the stack)
                    _ilg.Emit(OpCodes.Stloc, loc);

                    // test for null
                    _ilg.Emit(OpCodes.Ldloca, loc);
                    _ilg.EmitHasValue(operandType);
                    _ilg.Emit(OpCodes.Brfalse_S, labEnd);

                    // do op on non-null value
                    _ilg.Emit(OpCodes.Ldloca, loc);
                    _ilg.EmitGetValueOrDefault(operandType);
                    Type nnOperandType = TypeUtils.GetNonNullableType(operandType);
                    EmitUnaryOperator(op, nnOperandType, typeof(bool));

                    // construct result
                    ConstructorInfo ci = resultType.GetConstructor(ArrayOfType_Bool);
                    _ilg.Emit(OpCodes.Newobj, ci);
                    _ilg.Emit(OpCodes.Stloc, loc);

                    _ilg.MarkLabel(labEnd);
                    _ilg.Emit(OpCodes.Ldloc, loc);
                    FreeLocal(loc);
                    return;
                }

                case ExpressionType.UnaryPlus:
                case ExpressionType.NegateChecked:
                case ExpressionType.Negate:
                case ExpressionType.Increment:
                case ExpressionType.Decrement:
                case ExpressionType.OnesComplement:
                case ExpressionType.IsFalse:
                case ExpressionType.IsTrue:
                {
                    Debug.Assert(TypeUtils.AreEquivalent(operandType, resultType));
                    Label        labIfNull = _ilg.DefineLabel();
                    Label        labEnd    = _ilg.DefineLabel();
                    LocalBuilder loc       = GetLocal(operandType);

                    // check for null
                    _ilg.Emit(OpCodes.Stloc, loc);
                    _ilg.Emit(OpCodes.Ldloca, loc);
                    _ilg.EmitHasValue(operandType);
                    _ilg.Emit(OpCodes.Brfalse_S, labIfNull);

                    // apply operator to non-null value
                    _ilg.Emit(OpCodes.Ldloca, loc);
                    _ilg.EmitGetValueOrDefault(operandType);
                    Type nnOperandType = TypeUtils.GetNonNullableType(resultType);
                    EmitUnaryOperator(op, nnOperandType, nnOperandType);

                    // construct result
                    ConstructorInfo ci = resultType.GetConstructor(new Type[] { nnOperandType });
                    _ilg.Emit(OpCodes.Newobj, ci);
                    _ilg.Emit(OpCodes.Stloc, loc);
                    _ilg.Emit(OpCodes.Br_S, labEnd);

                    // if null then create a default one
                    _ilg.MarkLabel(labIfNull);
                    _ilg.Emit(OpCodes.Ldloca, loc);
                    _ilg.Emit(OpCodes.Initobj, resultType);

                    _ilg.MarkLabel(labEnd);
                    _ilg.Emit(OpCodes.Ldloc, loc);
                    FreeLocal(loc);
                    return;
                }

                case ExpressionType.TypeAs:
                    _ilg.Emit(OpCodes.Box, operandType);
                    _ilg.Emit(OpCodes.Isinst, resultType);
                    if (TypeUtils.IsNullableType(resultType))
                    {
                        _ilg.Emit(OpCodes.Unbox_Any, resultType);
                    }
                    return;

                default:
                    throw Error.UnhandledUnary(op);
                }
            }
            else
            {
                switch (op)
                {
                case ExpressionType.Not:
                    if (operandType == typeof(bool))
                    {
                        _ilg.Emit(OpCodes.Ldc_I4_0);
                        _ilg.Emit(OpCodes.Ceq);
                    }
                    else
                    {
                        _ilg.Emit(OpCodes.Not);
                    }
                    break;

                case ExpressionType.OnesComplement:
                    _ilg.Emit(OpCodes.Not);
                    break;

                case ExpressionType.IsFalse:
                    _ilg.Emit(OpCodes.Ldc_I4_0);
                    _ilg.Emit(OpCodes.Ceq);
                    // Not an arithmetic operation -> no conversion
                    return;

                case ExpressionType.IsTrue:
                    _ilg.Emit(OpCodes.Ldc_I4_1);
                    _ilg.Emit(OpCodes.Ceq);
                    // Not an arithmetic operation -> no conversion
                    return;

                case ExpressionType.UnaryPlus:
                    _ilg.Emit(OpCodes.Nop);
                    break;

                case ExpressionType.Negate:
                case ExpressionType.NegateChecked:
                    _ilg.Emit(OpCodes.Neg);
                    break;

                case ExpressionType.TypeAs:
                    if (operandType.GetTypeInfo().IsValueType)
                    {
                        _ilg.Emit(OpCodes.Box, operandType);
                    }
                    _ilg.Emit(OpCodes.Isinst, resultType);
                    if (TypeUtils.IsNullableType(resultType))
                    {
                        _ilg.Emit(OpCodes.Unbox_Any, resultType);
                    }
                    // Not an arithmetic operation -> no conversion
                    return;

                case ExpressionType.Increment:
                    EmitConstantOne(resultType);
                    _ilg.Emit(OpCodes.Add);
                    break;

                case ExpressionType.Decrement:
                    EmitConstantOne(resultType);
                    _ilg.Emit(OpCodes.Sub);
                    break;

                default:
                    throw Error.UnhandledUnary(op);
                }

                EmitConvertArithmeticResult(op, resultType);
            }
        }
Ejemplo n.º 21
0
        private void EmitLift(ExpressionType nodeType, Type resultType, MethodCallExpression mc, ParameterExpression[] paramList, Expression[] argList)
        {
            Debug.Assert(TypeUtils.AreEquivalent(resultType.GetNonNullableType(), mc.Type.GetNonNullableType()));

            switch (nodeType)
            {
            default:
            case ExpressionType.LessThan:
            case ExpressionType.LessThanOrEqual:
            case ExpressionType.GreaterThan:
            case ExpressionType.GreaterThanOrEqual:
            {
                Label        exit     = _ilg.DefineLabel();
                Label        exitNull = _ilg.DefineLabel();
                LocalBuilder anyNull  = GetLocal(typeof(bool));
                for (int i = 0, n = paramList.Length; i < n; i++)
                {
                    ParameterExpression v   = paramList[i];
                    Expression          arg = argList[i];
                    if (arg.Type.IsNullableType())
                    {
                        _scope.AddLocal(this, v);
                        EmitAddress(arg, arg.Type);
                        _ilg.Emit(OpCodes.Dup);
                        _ilg.EmitHasValue(arg.Type);
                        _ilg.Emit(OpCodes.Ldc_I4_0);
                        _ilg.Emit(OpCodes.Ceq);
                        _ilg.Emit(OpCodes.Stloc, anyNull);
                        _ilg.EmitGetValueOrDefault(arg.Type);
                        _scope.EmitSet(v);
                    }
                    else
                    {
                        _scope.AddLocal(this, v);
                        EmitExpression(arg);
                        if (!arg.Type.IsValueType)
                        {
                            _ilg.Emit(OpCodes.Dup);
                            _ilg.Emit(OpCodes.Ldnull);
                            _ilg.Emit(OpCodes.Ceq);
                            _ilg.Emit(OpCodes.Stloc, anyNull);
                        }
                        _scope.EmitSet(v);
                    }
                    _ilg.Emit(OpCodes.Ldloc, anyNull);
                    _ilg.Emit(OpCodes.Brtrue, exitNull);
                }
                EmitMethodCallExpression(mc);
                if (resultType.IsNullableType() && !TypeUtils.AreEquivalent(resultType, mc.Type))
                {
                    ConstructorInfo ci = resultType.GetConstructor(new Type[] { mc.Type });
                    _ilg.Emit(OpCodes.Newobj, ci);
                }
                _ilg.Emit(OpCodes.Br_S, exit);
                _ilg.MarkLabel(exitNull);
                if (TypeUtils.AreEquivalent(resultType, mc.Type.GetNullableType()))
                {
                    if (resultType.IsValueType)
                    {
                        LocalBuilder result = GetLocal(resultType);
                        _ilg.Emit(OpCodes.Ldloca, result);
                        _ilg.Emit(OpCodes.Initobj, resultType);
                        _ilg.Emit(OpCodes.Ldloc, result);
                        FreeLocal(result);
                    }
                    else
                    {
                        _ilg.Emit(OpCodes.Ldnull);
                    }
                }
                else
                {
                    Debug.Assert(nodeType == ExpressionType.LessThan ||
                                 nodeType == ExpressionType.LessThanOrEqual ||
                                 nodeType == ExpressionType.GreaterThan ||
                                 nodeType == ExpressionType.GreaterThanOrEqual);

                    _ilg.Emit(OpCodes.Ldc_I4_0);
                }
                _ilg.MarkLabel(exit);
                FreeLocal(anyNull);
                return;
            }

            case ExpressionType.Equal:
            case ExpressionType.NotEqual:
            {
                if (TypeUtils.AreEquivalent(resultType, mc.Type.GetNullableType()))
                {
                    goto default;
                }
                Label exit        = _ilg.DefineLabel();
                Label exitAllNull = _ilg.DefineLabel();
                Label exitAnyNull = _ilg.DefineLabel();

                LocalBuilder anyNull = GetLocal(typeof(bool));
                LocalBuilder allNull = GetLocal(typeof(bool));
                _ilg.Emit(OpCodes.Ldc_I4_0);
                _ilg.Emit(OpCodes.Stloc, anyNull);
                _ilg.Emit(OpCodes.Ldc_I4_1);
                _ilg.Emit(OpCodes.Stloc, allNull);

                for (int i = 0, n = paramList.Length; i < n; i++)
                {
                    ParameterExpression v   = paramList[i];
                    Expression          arg = argList[i];
                    _scope.AddLocal(this, v);
                    if (arg.Type.IsNullableType())
                    {
                        EmitAddress(arg, arg.Type);
                        _ilg.Emit(OpCodes.Dup);
                        _ilg.EmitHasValue(arg.Type);
                        _ilg.Emit(OpCodes.Ldc_I4_0);
                        _ilg.Emit(OpCodes.Ceq);
                        _ilg.Emit(OpCodes.Dup);
                        _ilg.Emit(OpCodes.Ldloc, anyNull);
                        _ilg.Emit(OpCodes.Or);
                        _ilg.Emit(OpCodes.Stloc, anyNull);
                        _ilg.Emit(OpCodes.Ldloc, allNull);
                        _ilg.Emit(OpCodes.And);
                        _ilg.Emit(OpCodes.Stloc, allNull);
                        _ilg.EmitGetValueOrDefault(arg.Type);
                    }
                    else
                    {
                        EmitExpression(arg);
                        if (!arg.Type.IsValueType)
                        {
                            _ilg.Emit(OpCodes.Dup);
                            _ilg.Emit(OpCodes.Ldnull);
                            _ilg.Emit(OpCodes.Ceq);
                            _ilg.Emit(OpCodes.Dup);
                            _ilg.Emit(OpCodes.Ldloc, anyNull);
                            _ilg.Emit(OpCodes.Or);
                            _ilg.Emit(OpCodes.Stloc, anyNull);
                            _ilg.Emit(OpCodes.Ldloc, allNull);
                            _ilg.Emit(OpCodes.And);
                            _ilg.Emit(OpCodes.Stloc, allNull);
                        }
                        else
                        {
                            _ilg.Emit(OpCodes.Ldc_I4_0);
                            _ilg.Emit(OpCodes.Stloc, allNull);
                        }
                    }
                    _scope.EmitSet(v);
                }
                _ilg.Emit(OpCodes.Ldloc, allNull);
                _ilg.Emit(OpCodes.Brtrue, exitAllNull);
                _ilg.Emit(OpCodes.Ldloc, anyNull);
                _ilg.Emit(OpCodes.Brtrue, exitAnyNull);

                EmitMethodCallExpression(mc);
                if (resultType.IsNullableType() && !TypeUtils.AreEquivalent(resultType, mc.Type))
                {
                    ConstructorInfo ci = resultType.GetConstructor(new Type[] { mc.Type });
                    _ilg.Emit(OpCodes.Newobj, ci);
                }
                _ilg.Emit(OpCodes.Br_S, exit);

                _ilg.MarkLabel(exitAllNull);
                _ilg.EmitPrimitive(nodeType == ExpressionType.Equal);
                _ilg.Emit(OpCodes.Br_S, exit);

                _ilg.MarkLabel(exitAnyNull);
                _ilg.EmitPrimitive(nodeType == ExpressionType.NotEqual);

                _ilg.MarkLabel(exit);
                FreeLocal(anyNull);
                FreeLocal(allNull);
                return;
            }
            }
        }
Ejemplo n.º 22
0
 public override bool Equals(object obj)
 {
     BindingRestrictions.TypeRestriction restriction = obj as BindingRestrictions.TypeRestriction;
     return (((restriction != null) && TypeUtils.AreEquivalent(restriction._type, this._type)) && (restriction._expression == this._expression));
 }
Ejemplo n.º 23
0
        private void EmitConvert(UnaryExpression node, CompilationFlags flags)
        {
            if (node.Method != null)
            {
                // User-defined conversions are only lifted if both source and
                // destination types are value types.  The C# compiler gets this wrong.
                // In C#, if you have an implicit conversion from int->MyClass and you
                // "lift" the conversion to int?->MyClass then a null int? goes to a
                // null MyClass.  This is contrary to the specification, which states
                // that the correct behaviour is to unwrap the int?, throw an exception
                // if it is null, and then call the conversion.
                //
                // We cannot fix this in C# but there is no reason why we need to
                // propagate this behavior into the expression tree API.  Unfortunately
                // this means that when the C# compiler generates the lambda
                // (int? i)=>(MyClass)i, we will get different results for converting
                // that lambda to a delegate directly and converting that lambda to
                // an expression tree and then compiling it.  We can live with this
                // discrepancy however.

                if (node.IsLifted && (!node.Type.GetTypeInfo().IsValueType || !node.Operand.Type.GetTypeInfo().IsValueType))
                {
                    ParameterInfo[] pis = node.Method.GetParametersCached();
                    Debug.Assert(pis != null && pis.Length == 1);
                    Type paramType = pis[0].ParameterType;
                    if (paramType.IsByRef)
                    {
                        paramType = paramType.GetElementType();
                    }

                    UnaryExpression e = Expression.Convert(
                        Expression.Call(
                            node.Method,
                            Expression.Convert(node.Operand, pis[0].ParameterType)
                            ),
                        node.Type
                        );

                    EmitConvert(e, flags);
                }
                else
                {
                    EmitUnaryMethod(node, flags);
                }
            }
            else if (node.Type == typeof(void))
            {
                EmitExpressionAsVoid(node.Operand, flags);
            }
            else
            {
                if (TypeUtils.AreEquivalent(node.Operand.Type, node.Type))
                {
                    EmitExpression(node.Operand, flags);
                }
                else
                {
                    // A conversion is emitted after emitting the operand, no tail call is emitted
                    EmitExpression(node.Operand);
                    _ilg.EmitConvertToType(node.Operand.Type, node.Type, node.NodeType == ExpressionType.ConvertChecked);
                }
            }
        }
Ejemplo n.º 24
0
 /// <summary>
 ///     Returns our Expression converted to our known LimitType
 /// </summary>
 private Expression GetLimitedSelf()
 {
     return(TypeUtils.AreEquivalent(Expression.Type, LimitType) ? Expression : Expression.Convert(Expression, LimitType));
 }
Ejemplo n.º 25
0
        private void EmitLift(ExpressionType nodeType, Type resultType, MethodCallExpression mc, ParameterExpression[] paramList, Expression[] argList)
        {
            Debug.Assert(TypeUtils.AreEquivalent(resultType.GetNonNullable(), mc.Type.GetNonNullable()));

            switch (nodeType)
            {
            case ExpressionType.Equal:
            case ExpressionType.NotEqual:
                if (TypeUtils.AreEquivalent(resultType, mc.Type.GetNullable()))
                {
                    goto default;
                }

                EmitLiftEqualityComparison(nodeType, resultType, mc, paramList, argList);
                return;

            default:
                var exit     = IL.DefineLabel();
                var exitNull = IL.DefineLabel();
                var anyNull  = GetLocal(typeof(bool));
                for (int i = 0, n = paramList.Length; i < n; i++)
                {
                    var v   = paramList[i];
                    var arg = argList[i];
                    if (arg.Type.IsNullable())
                    {
                        _scope.AddLocal(this, v);
                        EmitAddress(arg, arg.Type);
                        IL.Emit(OpCodes.Dup);
                        IL.EmitHasValue(arg.Type);
                        IL.Emit(OpCodes.Ldc_I4_0);
                        IL.Emit(OpCodes.Ceq);
                        IL.Emit(OpCodes.Stloc, anyNull);
                        IL.EmitGetValueOrDefault(arg.Type);
                        _scope.EmitSet(v);
                    }
                    else
                    {
                        _scope.AddLocal(this, v);
                        EmitExpression(arg);
                        if (!arg.Type.IsValueType)
                        {
                            IL.Emit(OpCodes.Dup);
                            IL.Emit(OpCodes.Ldnull);
                            IL.Emit(OpCodes.Ceq);
                            IL.Emit(OpCodes.Stloc, anyNull);
                        }

                        _scope.EmitSet(v);
                    }

                    IL.Emit(OpCodes.Ldloc, anyNull);
                    IL.Emit(OpCodes.Brtrue, exitNull);
                }

                EmitMethodCallExpression(mc);
                if (resultType.IsNullable() && !TypeUtils.AreEquivalent(resultType, mc.Type))
                {
                    var ci = resultType.GetConstructor(new[] { mc.Type });
                    IL.Emit(OpCodes.Newobj, ci);
                }

                IL.Emit(OpCodes.Br_S, exit);
                IL.MarkLabel(exitNull);
                if (TypeUtils.AreEquivalent(resultType, mc.Type.GetNullable()))
                {
                    if (resultType.IsValueType)
                    {
                        var result = GetLocal(resultType);
                        IL.Emit(OpCodes.Ldloca, result);
                        IL.Emit(OpCodes.Initobj, resultType);
                        IL.Emit(OpCodes.Ldloc, result);
                        FreeLocal(result);
                    }
                    else
                    {
                        IL.Emit(OpCodes.Ldnull);
                    }
                }
                else
                {
                    Debug.Assert
                    (
                        nodeType == ExpressionType.LessThan ||
                        nodeType == ExpressionType.LessThanOrEqual ||
                        nodeType == ExpressionType.GreaterThan ||
                        nodeType == ExpressionType.GreaterThanOrEqual
                    );

                    IL.Emit(OpCodes.Ldc_I4_0);
                }

                IL.MarkLabel(exit);
                FreeLocal(anyNull);
                return;
            }
        }
Ejemplo n.º 26
0
        private void EmitLiftEqualityComparison(ExpressionType nodeType, Type resultType, MethodCallExpression mc, ParameterExpression[] paramList, Expression[] argList)
        {
            var exit        = IL.DefineLabel();
            var exitAllNull = IL.DefineLabel();
            var exitAnyNull = IL.DefineLabel();

            var anyNull = GetLocal(typeof(bool));
            var allNull = GetLocal(typeof(bool));

            IL.Emit(OpCodes.Ldc_I4_0);
            IL.Emit(OpCodes.Stloc, anyNull);
            IL.Emit(OpCodes.Ldc_I4_1);
            IL.Emit(OpCodes.Stloc, allNull);

            for (int i = 0, n = paramList.Length; i < n; i++)
            {
                var v   = paramList[i];
                var arg = argList[i];
                _scope.AddLocal(this, v);
                if (arg.Type.IsNullable())
                {
                    EmitAddress(arg, arg.Type);
                    IL.Emit(OpCodes.Dup);
                    IL.EmitHasValue(arg.Type);
                    IL.Emit(OpCodes.Ldc_I4_0);
                    IL.Emit(OpCodes.Ceq);
                    IL.Emit(OpCodes.Dup);
                    IL.Emit(OpCodes.Ldloc, anyNull);
                    IL.Emit(OpCodes.Or);
                    IL.Emit(OpCodes.Stloc, anyNull);
                    IL.Emit(OpCodes.Ldloc, allNull);
                    IL.Emit(OpCodes.And);
                    IL.Emit(OpCodes.Stloc, allNull);
                    IL.EmitGetValueOrDefault(arg.Type);
                }
                else
                {
                    EmitExpression(arg);
                    if (!arg.Type.IsValueType)
                    {
                        IL.Emit(OpCodes.Dup);
                        IL.Emit(OpCodes.Ldnull);
                        IL.Emit(OpCodes.Ceq);
                        IL.Emit(OpCodes.Dup);
                        IL.Emit(OpCodes.Ldloc, anyNull);
                        IL.Emit(OpCodes.Or);
                        IL.Emit(OpCodes.Stloc, anyNull);
                        IL.Emit(OpCodes.Ldloc, allNull);
                        IL.Emit(OpCodes.And);
                        IL.Emit(OpCodes.Stloc, allNull);
                    }
                    else
                    {
                        IL.Emit(OpCodes.Ldc_I4_0);
                        IL.Emit(OpCodes.Stloc, allNull);
                    }
                }

                _scope.EmitSet(v);
            }

            IL.Emit(OpCodes.Ldloc, allNull);
            IL.Emit(OpCodes.Brtrue, exitAllNull);
            IL.Emit(OpCodes.Ldloc, anyNull);
            IL.Emit(OpCodes.Brtrue, exitAnyNull);

            EmitMethodCallExpression(mc);
            if (resultType.IsNullable() && !TypeUtils.AreEquivalent(resultType, mc.Type))
            {
                var ci = resultType.GetConstructor(new[] { mc.Type });
                IL.Emit(OpCodes.Newobj, ci);
            }

            IL.Emit(OpCodes.Br_S, exit);

            IL.MarkLabel(exitAllNull);
            IL.EmitPrimitive(nodeType == ExpressionType.Equal);
            IL.Emit(OpCodes.Br_S, exit);

            IL.MarkLabel(exitAnyNull);
            IL.EmitPrimitive(nodeType == ExpressionType.NotEqual);

            IL.MarkLabel(exit);
            FreeLocal(anyNull);
            FreeLocal(allNull);
        }
Ejemplo n.º 27
0
        private void EmitLiftedRelational(ExpressionType op, Type leftType, Type rightType, Type resultType, bool liftedToNull)
        {
            Debug.Assert(leftType.IsNullableType());

            Label        shortCircuit = _ilg.DefineLabel();
            LocalBuilder locLeft      = GetLocal(leftType);
            LocalBuilder locRight     = GetLocal(rightType);

            // store values (reverse order since they are already on the stack)
            _ilg.Emit(OpCodes.Stloc, locRight);
            _ilg.Emit(OpCodes.Stloc, locLeft);

            if (op == ExpressionType.Equal)
            {
                // test for both null -> true
                _ilg.Emit(OpCodes.Ldloca, locLeft);
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Ldc_I4_0);
                _ilg.Emit(OpCodes.Ceq);
                _ilg.Emit(OpCodes.Ldloca, locRight);
                _ilg.EmitHasValue(rightType);
                _ilg.Emit(OpCodes.Ldc_I4_0);
                _ilg.Emit(OpCodes.Ceq);
                _ilg.Emit(OpCodes.And);
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Brtrue_S, shortCircuit);
                _ilg.Emit(OpCodes.Pop);

                // test for either is null -> false
                _ilg.Emit(OpCodes.Ldloca, locLeft);
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Ldloca, locRight);
                _ilg.EmitHasValue(rightType);
                _ilg.Emit(OpCodes.And);

                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Brfalse_S, shortCircuit);
                _ilg.Emit(OpCodes.Pop);
            }
            else if (op == ExpressionType.NotEqual)
            {
                // test for both null -> false
                _ilg.Emit(OpCodes.Ldloca, locLeft);
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Ldloca, locRight);
                _ilg.EmitHasValue(rightType);
                _ilg.Emit(OpCodes.Or);
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Brfalse_S, shortCircuit);
                _ilg.Emit(OpCodes.Pop);

                // test for either is null -> true
                _ilg.Emit(OpCodes.Ldloca, locLeft);
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Ldc_I4_0);
                _ilg.Emit(OpCodes.Ceq);
                _ilg.Emit(OpCodes.Ldloca, locRight);
                _ilg.EmitHasValue(rightType);
                _ilg.Emit(OpCodes.Ldc_I4_0);
                _ilg.Emit(OpCodes.Ceq);
                _ilg.Emit(OpCodes.Or);
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Brtrue_S, shortCircuit);
                _ilg.Emit(OpCodes.Pop);
            }
            else
            {
                // test for either is null -> false
                _ilg.Emit(OpCodes.Ldloca, locLeft);
                _ilg.EmitHasValue(leftType);
                _ilg.Emit(OpCodes.Ldloca, locRight);
                _ilg.EmitHasValue(rightType);
                _ilg.Emit(OpCodes.And);
                _ilg.Emit(OpCodes.Dup);
                _ilg.Emit(OpCodes.Brfalse_S, shortCircuit);
                _ilg.Emit(OpCodes.Pop);
            }

            // do op on values
            _ilg.Emit(OpCodes.Ldloca, locLeft);
            _ilg.EmitGetValueOrDefault(leftType);
            _ilg.Emit(OpCodes.Ldloca, locRight);
            _ilg.EmitGetValueOrDefault(rightType);

            //RELEASING locLeft locRight
            FreeLocal(locLeft);
            FreeLocal(locRight);

            EmitBinaryOperator(
                op,
                leftType.GetNonNullableType(),
                rightType.GetNonNullableType(),
                resultType.GetNonNullableType(),
                liftedToNull: false
                );

            if (!liftedToNull)
            {
                _ilg.MarkLabel(shortCircuit);
            }

            if (!TypeUtils.AreEquivalent(resultType, resultType.GetNonNullableType()))
            {
                _ilg.EmitConvertToType(resultType.GetNonNullableType(), resultType, isChecked: true);
            }

            if (liftedToNull)
            {
                Label labEnd = _ilg.DefineLabel();
                _ilg.Emit(OpCodes.Br, labEnd);
                _ilg.MarkLabel(shortCircuit);
                _ilg.Emit(OpCodes.Pop);
                _ilg.Emit(OpCodes.Ldnull);
                _ilg.Emit(OpCodes.Unbox_Any, resultType);
                _ilg.MarkLabel(labEnd);
            }
        }
        private void EmitNullableCoalesce(BinaryExpression b)
        {
            Debug.Assert(b.Method == null);

            LocalBuilder loc       = GetLocal(b.Left.Type);
            Label        labIfNull = _ilg.DefineLabel();
            Label        labEnd    = _ilg.DefineLabel();

            EmitExpression(b.Left);
            _ilg.Emit(OpCodes.Stloc, loc);
            _ilg.Emit(OpCodes.Ldloca, loc);
            _ilg.EmitHasValue(b.Left.Type);
            _ilg.Emit(OpCodes.Brfalse, labIfNull);

            Type nnLeftType = b.Left.Type.GetNonNullableType();

            if (b.Conversion != null)
            {
                Debug.Assert(b.Conversion.ParameterCount == 1);
                ParameterExpression p = b.Conversion.GetParameter(0);
                Debug.Assert(p.Type.IsAssignableFrom(b.Left.Type) ||
                             p.Type.IsAssignableFrom(nnLeftType));

                // emit the delegate instance
                EmitLambdaExpression(b.Conversion);

                // emit argument
                if (!p.Type.IsAssignableFrom(b.Left.Type))
                {
                    _ilg.Emit(OpCodes.Ldloca, loc);
                    _ilg.EmitGetValueOrDefault(b.Left.Type);
                }
                else
                {
                    _ilg.Emit(OpCodes.Ldloc, loc);
                }

                // emit call to invoke
                _ilg.Emit(OpCodes.Callvirt, b.Conversion.Type.GetMethod("Invoke"));
            }
            else if (!TypeUtils.AreEquivalent(b.Type, nnLeftType))
            {
                _ilg.Emit(OpCodes.Ldloca, loc);
                _ilg.EmitGetValueOrDefault(b.Left.Type);
                _ilg.EmitConvertToType(nnLeftType, b.Type, isChecked: true);
            }
            else
            {
                _ilg.Emit(OpCodes.Ldloca, loc);
                _ilg.EmitGetValueOrDefault(b.Left.Type);
            }
            FreeLocal(loc);

            _ilg.Emit(OpCodes.Br, labEnd);
            _ilg.MarkLabel(labIfNull);
            EmitExpression(b.Right);
            if (!TypeUtils.AreEquivalent(b.Right.Type, b.Type))
            {
                _ilg.EmitConvertToType(b.Right.Type, b.Type, isChecked: true);
            }
            _ilg.MarkLabel(labEnd);
        }
Ejemplo n.º 29
0
            public override bool Equals(object obj)
            {
                var other = obj as TypeRestriction;

                return(other != null && TypeUtils.AreEquivalent(other._type, _type) && other._expression == _expression);
            }
Ejemplo n.º 30
0
        private void EmitUnaryOperator(ExpressionType op, Type operandType, Type resultType)
        {
            var operandIsNullable = operandType.IsNullable();

            if (op == ExpressionType.ArrayLength)
            {
                IL.Emit(OpCodes.Ldlen);
                return;
            }

            if (operandIsNullable)
            {
                switch (op)
                {
                case ExpressionType.UnaryPlus:
                    return;

                case ExpressionType.TypeAs:
                    if (operandType == resultType)
                    {
                        return;
                    }

                    IL.Emit(OpCodes.Box, operandType);
                    IL.Emit(OpCodes.Isinst, resultType);
                    if (resultType.IsNullable())
                    {
                        IL.Emit(OpCodes.Unbox_Any, resultType);
                    }

                    return;

                default:
                    Debug.Assert(TypeUtils.AreEquivalent(operandType, resultType));
                    var labIfNull = IL.DefineLabel();
                    var labEnd    = IL.DefineLabel();
                    var loc       = GetLocal(operandType);

                    // check for null
                    IL.Emit(OpCodes.Stloc, loc);
                    IL.Emit(OpCodes.Ldloca, loc);
                    IL.EmitHasValue(operandType);
                    IL.Emit(OpCodes.Brfalse_S, labIfNull);

                    // apply operator to non-null value
                    IL.Emit(OpCodes.Ldloca, loc);
                    IL.EmitGetValueOrDefault(operandType);
                    var nnOperandType = resultType.GetNonNullable();
                    EmitUnaryOperator(op, nnOperandType, nnOperandType);

                    // construct result
                    var ci = resultType.GetConstructor(new[] { nnOperandType });
                    // ReSharper disable once AssignNullToNotNullAttribute
                    IL.Emit(OpCodes.Newobj, ci);
                    IL.Emit(OpCodes.Br_S, labEnd);

                    // if null then push back on stack.
                    IL.MarkLabel(labIfNull);
                    IL.Emit(OpCodes.Ldloc, loc);
                    FreeLocal(loc);
                    IL.MarkLabel(labEnd);
                    return;
                }
            }

            switch (op)
            {
            case ExpressionType.Not:
                if (operandType == typeof(bool))
                {
                    IL.Emit(OpCodes.Ldc_I4_0);
                    IL.Emit(OpCodes.Ceq);
                    return;
                }

                goto case ExpressionType.OnesComplement;

            case ExpressionType.OnesComplement:
                IL.Emit(OpCodes.Not);
                if (!operandType.IsUnsigned())
                {
                    // Guaranteed to fit within result type: no conversion
                    return;
                }

                break;

            case ExpressionType.IsFalse:
                IL.Emit(OpCodes.Ldc_I4_0);
                IL.Emit(OpCodes.Ceq);
                // Not an arithmetic operation -> no conversion
                return;

            case ExpressionType.IsTrue:
                IL.Emit(OpCodes.Ldc_I4_1);
                IL.Emit(OpCodes.Ceq);
                // Not an arithmetic operation -> no conversion
                return;

            case ExpressionType.UnaryPlus:
                // Guaranteed to fit within result type: no conversion
                return;

            case ExpressionType.Negate:
            case ExpressionType.NegateChecked:
                IL.Emit(OpCodes.Neg);
                // Guaranteed to fit within result type: no conversion
                // (integer NegateChecked was rewritten to 0 - operand and doesn't hit here).
                return;

            case ExpressionType.TypeAs:
                if (operandType == resultType)
                {
                    return;
                }

                if (operandType.IsValueType)
                {
                    IL.Emit(OpCodes.Box, operandType);
                }

                IL.Emit(OpCodes.Isinst, resultType);
                if (resultType.IsNullable())
                {
                    IL.Emit(OpCodes.Unbox_Any, resultType);
                }

                // Not an arithmetic operation -> no conversion
                return;

            case ExpressionType.Increment:
                EmitConstantOne(resultType);
                IL.Emit(OpCodes.Add);
                break;

            case ExpressionType.Decrement:
                EmitConstantOne(resultType);
                IL.Emit(OpCodes.Sub);
                break;

            default:
                break;
            }

            EmitConvertArithmeticResult(op, resultType);
        }