Пример #1
0
        /// <summary>
        /// Creates a <see cref="MemberExpression"/> accessing a field.
        /// </summary>
        /// <param name="expression">The containing object of the field.  This can be null for static fields.</param>
        /// <param name="field">The field to be accessed.</param>
        /// <returns>The created <see cref="MemberExpression"/>.</returns>
        public static MemberExpression Field(Expression expression, FieldInfo field)
        {
            ContractUtils.RequiresNotNull(field, "field");

            if (field.IsStatic)
            {
                if (expression != null)
                {
                    throw new ArgumentException(Strings.OnlyStaticFieldsHaveNullInstance, "expression");
                }
            }
            else
            {
                if (expression == null)
                {
                    throw new ArgumentException(Strings.OnlyStaticFieldsHaveNullInstance, "field");
                }

                RequiresCanRead(expression, "expression");
                if (!TypeHelper.AreReferenceAssignable(field.DeclaringType, expression.Type))
                {
                    throw Error.FieldInfoNotDefinedForType(field.DeclaringType, field.Name, expression.Type);
                }
            }
            return(MemberExpression.Make(expression, field));
        }
Пример #2
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");

            var last = expressionList.Last();

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

            if (type != last.Type)
            {
                return(new ScopeWithType(variableList, expressionList, type));
            }
            if (expressionList.Count == 1)
            {
                return(new Scope1(variableList, expressionList[0]));
            }

            return(new ScopeN(variableList, expressionList));
        }
        internal Expression ReduceTypeEqual()
        {
            var cType = Expression.Type;

            // For value types (including Void, but not nullables), we can
            // determine the result now
            if (cType.IsValueType && !cType.IsNullableType())
            {
                return(Block(Expression, Constant(cType == _typeOperand.GetNonNullableType())));
            }

            // Can check the value right now for constants.
            if (Expression.NodeType == ExpressionType.Constant)
            {
                return(ReduceConstantTypeEqual());
            }

            // If the operand type is a sealed reference type or a nullable
            // type, it will match if value is not null
            if (cType.IsSealed && (cType == _typeOperand))
            {
                if (cType.IsNullableType())
                {
                    return(NotEqual(Expression, Constant(null, Expression.Type)));
                }
                else
                {
                    return(ReferenceNotEqual(Expression, Constant(null, Expression.Type)));
                }
            }

            // expression is a ByVal parameter. Can safely reevaluate.
            var parameter = Expression as ParameterExpression;

            if (parameter != null && !parameter.IsByRef)
            {
                return(ByValParameterTypeEqual(parameter));
            }

            // Create a temp so we only evaluate the left side once
            parameter = Parameter(typeof(object));

            // Convert to object if necessary
            var expression = Expression;

            if (!TypeHelper.AreReferenceAssignable(typeof(object), expression.Type))
            {
                expression = Convert(expression, typeof(object));
            }

            return(Block(
                       new[] { parameter },
                       Assign(parameter, expression),
                       ByValParameterTypeEqual(parameter)
                       ));
        }
        private void EmitSwitchExpression(Expression expr, CompilationFlags flags)
        {
            var node = (SwitchExpression)expr;

            // Try to emit it as an IL switch. Works for integer types.
            if (TryEmitSwitchInstruction(node, flags))
            {
                return;
            }

            // Try to emit as a hashtable lookup. Works for strings.
            if (TryEmitHashtableSwitch(node, flags))
            {
                return;
            }

            //
            // Fall back to a series of tests. We need to IL gen instead of
            // transform the tree to avoid stack overflow on a big switch.
            //

            var switchValue = Expression.Parameter(node.SwitchValue.Type, "switchValue");
            var testValue   = Expression.Parameter(GetTestValueType(node), "testValue");

            _scope.AddLocal(this, switchValue);
            _scope.AddLocal(this, testValue);

            EmitExpression(node.SwitchValue);
            _scope.EmitSet(switchValue);

            // Emit tests
            var labels = new Label[node.Cases.Count];
            var isGoto = new bool[node.Cases.Count];
            var n      = node.Cases.Count;

            for (int i = 0; i < n; i++)
            {
                DefineSwitchCaseLabel(node.Cases[i], out labels[i], out isGoto[i]);
                foreach (Expression test in node.Cases[i].TestValues)
                {
                    // Pull the test out into a temp so it runs on the same
                    // stack as the switch. This simplifies spilling.
                    EmitExpression(test);
                    _scope.EmitSet(testValue);
                    Debug.Assert(TypeHelper.AreReferenceAssignable(testValue.Type, test.Type));
                    EmitExpressionAndBranch(true, Expression.Equal(switchValue, testValue, false, node.Comparison), labels[i]);
                }
            }

            // Define labels
            var end      = _ilg.DefineLabel();
            var @default = (node.DefaultBody == null) ? end : _ilg.DefineLabel();

            // Emit the case and default bodies
            EmitSwitchCases(node, labels, isGoto, @default, end, flags);
        }
        private void EmitExpressionAddress(Expression node, Type type)
        {
            Debug.Assert(TypeHelper.AreReferenceAssignable(type, node.Type));

            EmitExpression(node, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitNoExpressionStart);
            var tmp = GetLocal(type);

            _ilg.Emit(OpCodes.Stloc, tmp);
            _ilg.Emit(OpCodes.Ldloca, tmp);
        }
Пример #6
0
        private static void ValidateAccessorArgumentTypes(MethodInfo method, ParameterInfo[] indexes, ref ReadOnlyCollection <Expression> arguments)
        {
            if (indexes.Length > 0)
            {
                if (indexes.Length != arguments.Count)
                {
                    throw Error.IncorrectNumberOfMethodCallArguments(method);
                }
                Expression[] newArgs = null;
                var          n       = indexes.Length;
                for (var i = 0; i < n; i++)
                {
                    var arg = arguments[i];
                    var pi  = indexes[i];
                    RequiresCanRead(arg, "arguments");

                    var pType = pi.ParameterType;
                    if (pType.IsByRef)
                    {
                        throw Error.AccessorsCannotHaveByRefArgs();
                    }

                    TypeHelper.ValidateType(pType);

                    if (!TypeHelper.AreReferenceAssignable(pType, arg.Type))
                    {
                        if (!TryQuote(pType, ref arg))
                        {
                            throw Error.ExpressionTypeDoesNotMatchMethodParameter(arg.Type, pType, method);
                        }
                    }
                    if (newArgs == null && arg != arguments[i])
                    {
                        newArgs = new Expression[arguments.Count];
                        for (var j = 0; j < i; j++)
                        {
                            newArgs[j] = arguments[j];
                        }
                    }
                    if (newArgs != null)
                    {
                        newArgs[i] = arg;
                    }
                }
                if (newArgs != null)
                {
                    arguments = new TrueReadOnlyCollection <Expression>(newArgs);
                }
            }
            else if (arguments.Count > 0)
            {
                throw Error.IncorrectNumberOfMethodCallArguments(method);
            }
        }
Пример #7
0
 // For optimized Equal/NotEqual, we can eliminate reference
 // conversions. IL allows comparing managed pointers regardless of
 // type. See ECMA-335 "Binary Comparison or Branch Operations", in
 // Partition III, Section 1.5 Table 4.
 private static Expression GetEqualityOperand(Expression expression)
 {
     if (expression.NodeType == ExpressionType.Convert)
     {
         var convert = (UnaryExpression)expression;
         if (TypeHelper.AreReferenceAssignable(convert.Type, convert.Operand.Type))
         {
             return(convert.Operand);
         }
     }
     return(expression);
 }
Пример #8
0
 // Standard argument validation, taken from ValidateArgumentTypes
 private static void ValidateGotoType(Type expectedType, ref Expression value, string paramName)
 {
     RequiresCanRead(value, paramName);
     if (expectedType != typeof(void))
     {
         if (!TypeHelper.AreReferenceAssignable(expectedType, value.Type))
         {
             // C# autoquotes return values, so we'll do that here
             if (!TryQuote(expectedType, ref value))
             {
                 throw Error.ExpressionTypeDoesNotMatchLabel(value.Type, expectedType);
             }
         }
     }
 }
Пример #9
0
        /// <summary>
        /// Creates a new array expression of the specified type from the provided initializers.
        /// </summary>
        /// <param name="type">A Type that represents the element type of the array.</param>
        /// <param name="initializers">The expressions used to create the array elements.</param>
        /// <returns>An instance of the <see cref="NewArrayExpression"/>.</returns>
        public static NewArrayExpression NewArrayInit(Type type, IEnumerable <Expression> initializers)
        {
            ContractUtils.RequiresNotNull(type, "type");
            ContractUtils.RequiresNotNull(initializers, "initializers");
            if (type == typeof(void))
            {
                throw Error.ArgumentCannotBeOfTypeVoid();
            }

            var initializerList = initializers.ToReadOnly();

            Expression[] newList = null;
            var          n       = initializerList.Count;

            for (var i = 0; i < n; i++)
            {
                var expr = initializerList[i];
                RequiresCanRead(expr, "initializers");

                if (!TypeHelper.AreReferenceAssignable(type, expr.Type))
                {
                    if (!TryQuote(type, ref expr))
                    {
                        throw Error.ExpressionTypeCannotInitializeArrayType(expr.Type, type);
                    }
                    if (newList == null)
                    {
                        newList = new Expression[n];
                        for (var j = 0; j < i; j++)
                        {
                            newList[j] = initializerList[j];
                        }
                    }
                }
                if (newList != null)
                {
                    newList[i] = expr;
                }
            }
            if (newList != null)
            {
                initializerList = new TrueReadOnlyCollection <Expression>(newList);
            }

            return(NewArrayExpression.Make(ExpressionType.NewArrayInit, type.MakeArrayType(), initializerList));
        }
Пример #10
0
        private static bool IsCompatible(PropertyInfo pi, Expression[] args)
        {
            var mi = pi.GetGetMethod(true);

            ParameterInfo[] parms;
            if (mi != null)
            {
                parms = mi.GetParameters();
            }
            else
            {
                mi = pi.GetSetMethod(true);
                //The setter has an additional parameter for the value to set,
                //need to remove the last type to match the arguments.
                parms = mi.GetParameters().RemoveLast();
            }

            if (mi == null)
            {
                return(false); // TODO: Test coverage?
            }
            if (args == null)
            {
                return(parms.Length == 0);
            }

            if (parms.Length != args.Length)
            {
                return(false);
            }

            for (var i = 0; i < args.Length; i++)
            {
                if (args[i] == null)
                {
                    return(false);
                }

                if (!TypeHelper.AreReferenceAssignable(parms[i].ParameterType, args[i].Type))
                {
                    return(false);
                }
            }
            return(true);
        }
Пример #11
0
        internal static void ValidateLift(IList <ParameterExpression> variables, IList <Expression> arguments)
        {
            Debug.Assert(variables != null);
            Debug.Assert(arguments != null);
            var n = variables.Count;

            if (n != arguments.Count)
            {
                throw Error.IncorrectNumberOfIndexes();
            }
            for (int i = 0; i < n; i++)
            {
                if (!TypeHelper.AreReferenceAssignable(variables[i].Type, arguments[i].Type.GetNonNullableType()))
                {
                    throw Error.ArgumentTypesMustMatch();
                }
            }
        }
Пример #12
0
 //Validate that the body of the try expression must have the same type as the body of every try block.
 private static void ValidateTryAndCatchHaveSameType(Type type, Expression tryBody, ReadOnlyCollection <CatchBlock> handlers)
 {
     // Type unification ... all parts must be reference assignable to "type"
     if (type != null)
     {
         if (type != typeof(void))
         {
             if (!TypeHelper.AreReferenceAssignable(type, tryBody.Type))
             {
                 throw Error.ArgumentTypesMustMatch();
             }
             foreach (var cb in handlers)
             {
                 if (!TypeHelper.AreReferenceAssignable(type, cb.Body.Type))
                 {
                     throw Error.ArgumentTypesMustMatch();
                 }
             }
         }
     }
     else if (tryBody == null || tryBody.Type == typeof(void))
     {
         //The body of every try block must be null or have void type.
         foreach (var cb in handlers)
         {
             if (cb.Body != null && cb.Body.Type != typeof(void))
             {
                 throw Error.BodyOfCatchMustHaveSameTypeAsBodyOfTry();
             }
         }
     }
     else
     {
         //Body of every catch must have the same type of body of try.
         type = tryBody.Type;
         foreach (var cb in handlers)
         {
             if (cb.Body == null || cb.Body.Type != type)
             {
                 throw Error.BodyOfCatchMustHaveSameTypeAsBodyOfTry();
             }
         }
     }
 }
 private static void ValidateSwitchCaseType(Expression @case, bool customType, Type resultType, string parameterName)
 {
     if (customType)
     {
         if (resultType != typeof(void))
         {
             if (!TypeHelper.AreReferenceAssignable(resultType, @case.Type))
             {
                 throw new ArgumentException(Strings.ArgumentTypesMustMatch, parameterName);
             }
         }
     }
     else
     {
         if (resultType != @case.Type)
         {
             throw new ArgumentException(Strings.AllCaseBodiesMustHaveSameType, parameterName);
         }
     }
 }
Пример #14
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 (node.Type != type)
         {
             EmitExpression(node);
             Debug.Assert(TypeHelper.AreReferenceAssignable(type, node.Type));
             _ilg.Emit(OpCodes.Castclass, type);
         }
         else
         {
             // emit the with the flags and emit emit expression start
             EmitExpression(node, UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitExpressionStart));
         }
     }
 }
Пример #15
0
        /// <summary>
        /// Reduces this node to a simpler expression. If CanReduce returns
        /// true, this should return a valid expression. This method is
        /// allowed to return another node which itself must be reduced.
        /// </summary>
        /// <returns>The reduced expression.</returns>
        /// <remarks >
        /// Unlike Reduce, this method checks that the reduced node satisfies
        /// certain invariants.
        /// </remarks>
        public Expression ReduceAndCheck()
        {
            if (!CanReduce)
            {
                throw Error.MustBeReducible();
            }

            var newNode = Reduce();

            // 1. Reduction must return a new, non-null node
            // 2. Reduction must return a new node whose result type can be assigned to the type of the original node
            if (newNode == null || newNode == this)
            {
                throw Error.MustReduceToDifferent();
            }

            if (!TypeHelper.AreReferenceAssignable(Type, newNode.Type))
            {
                throw Error.ReducedNotCompatible();
            }

            return(newNode);
        }
Пример #16
0
        /// <summary>
        /// Creates a <see cref="ConditionalExpression"/>.
        /// </summary>
        /// <param name="test">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.Test"/> property equal to.</param>
        /// <param name="ifTrue">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfTrue"/> property equal to.</param>
        /// <param name="ifFalse">An <see cref="Expression"/> to set the <see cref="P:ConditionalExpression.IfFalse"/> property equal to.</param>
        /// <param name="type">A <see cref="Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param>
        /// <returns>A <see cref="ConditionalExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to
        /// <see cref="F:ExpressionType.Conditional"/> and the <see cref="P:ConditionalExpression.Test"/>, <see cref="P:ConditionalExpression.IfTrue"/>,
        /// and <see cref="P:ConditionalExpression.IfFalse"/> properties set to the specified values.</returns>
        /// <remarks>This method allows explicitly unifying the result type of the conditional expression in cases where the types of <paramref name="ifTrue"/>
        /// and <paramref name="ifFalse"/> expressions are not equal. Types of both <paramref name="ifTrue"/> and <paramref name="ifFalse"/> must be implicitly
        /// reference assignable to the result type. The <paramref name="type"/> is allowed to be <see cref="System.Void"/>.</remarks>
        public static ConditionalExpression Condition(Expression test, Expression ifTrue, Expression ifFalse, Type type)
        {
            RequiresCanRead(test, "test");
            RequiresCanRead(ifTrue, "ifTrue");
            RequiresCanRead(ifFalse, "ifFalse");
            ContractUtils.RequiresNotNull(type, "type");

            if (test.Type != typeof(bool))
            {
                throw Error.ArgumentMustBeBoolean();
            }

            if (type != typeof(void))
            {
                if (!TypeHelper.AreReferenceAssignable(type, ifTrue.Type) ||
                    !TypeHelper.AreReferenceAssignable(type, ifFalse.Type))
                {
                    throw Error.ArgumentTypesMustMatch();
                }
            }

            return(ConditionalExpression.Make(test, ifTrue, ifFalse, type));
        }
Пример #17
0
        public static Expression ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi)
        {
            RequiresCanRead(arg, "arguments");
            var pType = pi.ParameterType;

            if (pType.IsByRef)
            {
                pType = pType.GetElementType();
            }
            TypeHelper.ValidateType(pType);
            if (!TypeHelper.AreReferenceAssignable(pType, arg.Type))
            {
                if (!TryQuote(pType, ref arg))
                {
                    // Throw the right error for the node we were given
                    switch (nodeKind)
                    {
                    case ExpressionType.New:
                        throw Error.ExpressionTypeDoesNotMatchConstructorParameter(arg.Type, pType);

                    case ExpressionType.Invoke:
                        throw Error.ExpressionTypeDoesNotMatchParameter(arg.Type, pType);

#if !NET35
                    case ExpressionType.Dynamic:
#endif
                    case ExpressionType.Call:
                        throw Error.ExpressionTypeDoesNotMatchMethodParameter(arg.Type, pType, method);

                    default:
                        throw ContractUtils.Unreachable;
                    }
                }
            }
            return(arg);
        }
Пример #18
0
        private static void VerifyRewrite(Result result, Expression node)
        {
            Debug.Assert(result.Node != null);

            // (result.Action == RewriteAction.None) if and only if (node == result.Node)
            Debug.Assert((result.Action == RewriteAction.None) ^ (node != result.Node), "rewrite action does not match node object identity");

            // if the original node is an extension node, it should have been rewritten
            Debug.Assert(result.Node.NodeType != ExpressionType.Extension, "extension nodes must be rewritten");

            // if we have Copy, then node type must match
            Debug.Assert(
                result.Action != RewriteAction.Copy || node.NodeType == result.Node.NodeType || node.CanReduce,
                "rewrite action does not match node object kind"
                );

            // New type must be reference assignable to the old type
            // (our rewrites preserve type exactly, but the rules for rewriting
            // an extension node are more lenient, see Expression.ReduceAndCheck())
            Debug.Assert(
                TypeHelper.AreReferenceAssignable(node.Type, result.Node.Type),
                "rewritten object must be reference assignable to the original type"
                );
        }
        // See if this lambda has a return label
        // If so, we'll create it now and mark it as allowing the "ret" opcode
        // This allows us to generate better IL
        private void AddReturnLabel(LambdaExpression lambda)
        {
            var expression = lambda.Body;

            while (true)
            {
                switch (expression.NodeType)
                {
                default:
                    // Didn't find return label
                    return;

                case ExpressionType.Label:
                    // Found the label. We can directly return from this place
                    // only if the label type is reference assignable to the lambda return type.
                    var label = ((LabelExpression)expression).Target;
                    _labelInfo.Add(label, new LabelInfo(_ilg, label, TypeHelper.AreReferenceAssignable(lambda.ReturnType, label.Type)));
                    return;

                case ExpressionType.Block:
                    // Look in the last significant expression of a block
                    var body = (BlockExpression)expression;
                    // omit empty and debuginfo at the end of the block since they
                    // are not going to emit any IL
                    for (int i = body.ExpressionCount - 1; i >= 0; i--)
                    {
                        expression = body.GetExpression(i);
                        if (Significant(expression))
                        {
                            break;
                        }
                    }
                    continue;
                }
            }
        }
Пример #20
0
        private static void ValidateNewArgs(ConstructorInfo constructor, ref ReadOnlyCollection <Expression> arguments, ref ReadOnlyCollection <MemberInfo> members)
        {
            ParameterInfo[] pis;
            if ((pis = constructor.GetParameters()).Length > 0)
            {
                if (arguments.Count != pis.Length)
                {
                    throw Error.IncorrectNumberOfConstructorArguments();
                }
                if (arguments.Count != members.Count)
                {
                    throw Error.IncorrectNumberOfArgumentsForMembers();
                }
                Expression[] newArguments = null;
                MemberInfo[] newMembers   = null;
                var          n            = arguments.Count;
                for (var i = 0; i < n; i++)
                {
                    var arg = arguments[i];
                    RequiresCanRead(arg, "argument");
                    var member = members[i];
                    ContractUtils.RequiresNotNull(member, "member");
                    if (member.DeclaringType != constructor.DeclaringType)
                    {
                        throw Error.ArgumentMemberNotDeclOnType(member.Name, constructor.DeclaringType.Name);
                    }
                    Type memberType;
                    ValidateAnonymousTypeMember(ref member, out memberType);
                    if (!TypeHelper.AreReferenceAssignable(memberType, arg.Type))
                    {
                        if (!TryQuote(memberType, ref arg))
                        {
                            throw Error.ArgumentTypeDoesNotMatchMember(arg.Type, memberType);
                        }
                    }
                    var pi    = pis[i];
                    var pType = pi.ParameterType;
                    if (pType.IsByRef)
                    {
                        pType = pType.GetElementType();
                    }
                    if (!TypeHelper.AreReferenceAssignable(pType, arg.Type))
                    {
                        if (!TryQuote(pType, ref arg))
                        {
                            throw Error.ExpressionTypeDoesNotMatchConstructorParameter(arg.Type, pType);
                        }
                    }
                    if (newArguments == null && arg != arguments[i])
                    {
                        newArguments = new Expression[n];
                        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 = 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();
            }
        }