示例#1
0
        private static Expression ValidateOneArgument(ParameterInfo parameter, Expression expression)
        {
            RequiresCanRead(expression, nameof(expression));

            var pType = parameter.ParameterType;

            // NB: No writeability check is performed; LINQ doesn't either, so you can pass e.g.
            //     a constant by ref, causing the write-back to be discarded. We're just being
            //     consistent here.
            if (pType.IsByRef)
            {
                pType = pType.GetElementType();
            }

            TypeUtils.ValidateType(pType);

            if (!TypeUtils1.AreReferenceAssignable(pType, expression.Type))
            {
                if (!TryQuote(pType, ref expression))
                {
                    throw Error.ExpressionTypeDoesNotMatchParameter(expression.Type, pType);
                }
            }

            return(expression);
        }
        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 LINQ // NB: For C#, we keep await nodes. Reduction happens in a separate step.
            // 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");
#endif

#if LINQ // The C# spiller never returns a Copy action
            // 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"
                );
#endif

            // 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(
                TypeUtils1.AreReferenceAssignable(node.Type, result.Node.Type),
                "rewritten object must be reference assignable to the original type"
                );
        }
        private Expression ReduceStaticAssign(Expression lhs)
        {
            lhs = MakeWriteable(lhs);
            var rhs = Right.Expression;

            if (!TypeUtils1.AreReferenceAssignable(lhs.Type, rhs.Type))
            {
                rhs = DynamicConvert(rhs, lhs.Type, CSharpBinderFlags.None, Context);
            }

            return(Expression.Assign(lhs, rhs));
        }
        public static ConditionalMemberCSharpExpression ConditionalField(Expression expression, FieldInfo field)
        {
            RequiresCanRead(expression, nameof(expression));
            ContractUtils.RequiresNotNull(field, nameof(field));

            if (field.IsStatic)
            {
                throw Error.ConditionalAccessRequiresNonStaticMember();
            }

            var type = expression.Type.GetNonNullReceiverType();

            if (!TypeUtils1.AreReferenceAssignable(field.DeclaringType, type))
            {
                throw LinqError.FieldInfoNotDefinedForType(field.DeclaringType, field.Name, type);
            }

            return(ConditionalMemberCSharpExpression.Make(expression, field));
        }
示例#5
0
        private static void ValidateAsyncLambdaArgs(Type delegateType, ref Expression body, ReadOnlyCollection <ParameterExpression> parameters)
        {
            //ContractUtils.RequiresNotNull(delegateType, nameof(delegateType));

            //TODO: Verify
            //RequiresCanRead(body, nameof(body));

            if (!typeof(MulticastDelegate).IsAssignableFrom(delegateType) || delegateType == typeof(MulticastDelegate))
            {
                throw LinqError.LambdaTypeMustBeDerivedFromSystemDelegate();
            }

            var count = parameters.Count;

            var method           = delegateType.GetMethod("Invoke"); // TODO: use cache from LINQ
            var parametersCached = method.GetParametersCached();

            if (parametersCached.Length != 0)
            {
                if (parametersCached.Length != count)
                {
                    throw LinqError.IncorrectNumberOfLambdaDeclarationParameters();
                }

                var set = new Set <ParameterExpression>(count);

                for (var i = 0; i < count; i++)
                {
                    var parameter = parameters[i];
                    ValidateAsyncParameter(parameter);

                    var parameterType = parametersCached[i].ParameterType;

                    if (!TypeUtils1.AreReferenceAssignable(parameter.Type, parameterType))
                    {
                        throw LinqError.ParameterExpressionNotValidAsDelegate(parameter.Type, parameterType);
                    }

                    if (set.Contains(parameter))
                    {
                        throw LinqError.DuplicateVariable(parameter);
                    }

                    set.Add(parameter);
                }
            }
            else if (count > 0)
            {
                throw LinqError.IncorrectNumberOfLambdaDeclarationParameters();
            }

            var returnType = method.ReturnType;

            if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task <>))
            {
                var resultType = returnType.GetGenericArguments()[0];

                if (!TypeUtils1.AreReferenceAssignable(resultType, body.Type) && !TryQuote(resultType, ref body))
                {
                    throw LinqError.ExpressionTypeDoesNotMatchReturn(body.Type, method.ReturnType);
                }
            }
            else if (returnType != typeof(void) && returnType != typeof(Task))
            {
                throw Error.AsyncLambdaInvalidReturnType(returnType);
            }
        }
        private static AssignBinaryCSharpExpression MakeBinaryAssignCore(CSharpExpressionType binaryType, Expression left, Expression right, MethodInfo method, LambdaExpression finalConversion, LambdaExpression leftConversion)
        {
            Helpers.RequiresCanWrite(left, nameof(left));
            RequiresCanRead(right, nameof(right));

            // NB: We could return a BinaryExpression in case the lhs is not one of our index nodes, but it'd change
            //     the return type to Expression which isn't nice to consume. Also, the Update method would either
            //     have to change to return Expression or we should have an AssignBinary node to hold a Binary node
            //     underneath it. This said, a specialized layout for the case where the custom node trivially wraps
            //     a LINQ node could be useful (just make Left virtual).

            if (binaryType != CSharpExpressionType.Assign)
            {
                var leftType  = left.Type;
                var rightType = right.Type;

                if (leftType == typeof(string))
                {
                    if (method == null)
                    {
                        if (binaryType == CSharpExpressionType.AddAssign || binaryType == CSharpExpressionType.AddAssignChecked)
                        {
                            if (rightType == typeof(string))
                            {
                                method = typeof(string).GetMethod(nameof(string.Concat), new[] { typeof(string), typeof(string) });
                            }
                            else
                            {
                                method = typeof(string).GetMethod(nameof(string.Concat), new[] { typeof(string), typeof(object) });

                                if (!TypeUtils1.AreReferenceAssignable(typeof(object), rightType))
                                {
                                    // DESIGN: Should our factory do this our just reject the input?
                                    right = Expression.Convert(right, typeof(object));
                                }
                            }
                        }
                        else
                        {
                            throw Error.InvalidCompoundAssignment(binaryType, typeof(string));
                        }
                    }
                }
                else if (typeof(MulticastDelegate).IsAssignableFrom(leftType))
                {
                    if (leftType == typeof(MulticastDelegate))
                    {
                        throw Error.InvalidCompoundAssignmentWithOperands(binaryType, leftType, rightType);
                    }

                    // NB: This checks for assignment with variance checks in mind, e.g.
                    //
                    //       Action<string> s = ...;
                    //       Action<object> o = ...;
                    //       s += o;

                    if (!TypeUtils1.AreReferenceAssignable(leftType, rightType))
                    {
                        throw Error.InvalidCompoundAssignmentWithOperands(binaryType, leftType, rightType);
                    }

                    if (method == null)
                    {
                        if (binaryType == CSharpExpressionType.AddAssign || binaryType == CSharpExpressionType.AddAssignChecked)
                        {
                            method = typeof(Delegate).GetMethod(nameof(Delegate.Combine), new[] { typeof(Delegate), typeof(Delegate) });
                        }
                        else if (binaryType == CSharpExpressionType.SubtractAssign || binaryType == CSharpExpressionType.SubtractAssignChecked)
                        {
                            method = typeof(Delegate).GetMethod(nameof(Delegate.Remove), new[] { typeof(Delegate), typeof(Delegate) });
                        }
                        else
                        {
                            throw Error.InvalidCompoundAssignment(binaryType, leftType);
                        }

                        if (finalConversion == null)
                        {
                            var resultParameter = Expression.Parameter(typeof(Delegate), "__result");
                            var convertResult   = Expression.Convert(resultParameter, leftType);
                            finalConversion = Expression.Lambda(convertResult, resultParameter);
                        }
                    }
                }
                else if (IsCSharpSpecificCompoundNumeric(leftType))
                {
                    // NB: If any of these are passed, we'll assume the types all line up. The call to
                    //     the ValidateCustomBinaryAssign method below will check that's indeed the case.

                    if (method == null && leftConversion == null && finalConversion == null)
                    {
                        var isChecked = IsCheckedBinary(binaryType);

                        var isNullabeLeftType = leftType.IsNullableType();
                        var nonNullLeftType   = leftType.GetNonNullableType();
                        var intermediateType  = nonNullLeftType.IsEnum ? nonNullLeftType.GetEnumUnderlyingType() : typeof(int);

                        var leftParameter = Expression.Parameter(leftType, "__left");
                        var convertType   = isNullabeLeftType ? typeof(Nullable <>).MakeGenericType(intermediateType) : intermediateType;
                        var convertLeft   = isChecked ? Expression.ConvertChecked(leftParameter, convertType) : Expression.Convert(leftParameter, convertType);
                        leftConversion = Expression.Lambda(convertLeft, leftParameter);

                        var resultParameter = Expression.Parameter(convertType, "__result");
                        var convertResult   = isChecked ? Expression.ConvertChecked(resultParameter, leftType) : Expression.Convert(resultParameter, leftType);
                        finalConversion = Expression.Lambda(convertResult, resultParameter);

                        if (rightType != convertType)
                        {
                            // DESIGN: Should our factory do this or just reject the input? On the one hand,
                            //         C# allows e.g. byte += byte, so if this is a C#-specific API it may be
                            //         reasonable for the user to expect such a tree can be built. On the
                            //         other hand, it's very unlike the expression tree API to insert nodes
                            //         on behalf of the user in the factories. Note that Roslyn often models
                            //         conversions as properties on a node using a `Conversion` objects
                            //         which would be handy to keep the shape from the tree isomorphic to the
                            //         bound nodes in the compiler. Note though that the RHS of a compound
                            //         assignment doesn't have such a conversion and the compiler will insert
                            //         a convert node in this case, so this is really just a convenience in
                            //         our factory method to mimic that behavior.
                            right = Expression.Convert(right, convertType);
                        }
                    }
                }
            }

            return(AssignBinaryCSharpExpression.Make(binaryType, left, right, method, leftConversion, finalConversion));
        }
示例#7
0
        public static NewMultidimensionalArrayInitCSharpExpression NewMultidimensionalArrayInit(Type type, IEnumerable <int> bounds, IEnumerable <Expression> initializers)
        {
            //ContractUtils.RequiresNotNull(type, nameof(type));
            //ContractUtils.RequiresNotNull(bounds, nameof(bounds));
            //ContractUtils.RequiresNotNull(initializers, nameof(initializers));

            //if (type.Equals(typeof(void)))
            //{
            //    throw LinqError.ArgumentCannotBeOfTypeVoid();
            //}

            var boundsList = bounds.ToReadOnly();

            int dimensions = boundsList.Count;

            if (dimensions <= 0)
            {
                throw LinqError.BoundsCannotBeLessThanOne();
            }

            var length = 1;

            foreach (var bound in boundsList)
            {
                if (bound < 0)
                {
                    throw Error.BoundCannotBeLessThanZero();
                }

                checked
                {
                    length *= bound;
                }
            }

            var initializerList = initializers.ToReadOnly();

            if (initializerList.Count != length)
            {
                throw Error.ArrayBoundsElementCountMismatch();
            }

            var newList = default(Expression[]);

            for (int i = 0, n = initializerList.Count; i < n; i++)
            {
                var expr = initializerList[i];
                //RequiresCanRead(expr, nameof(initializers));

                if (!TypeUtils1.AreReferenceAssignable(type, expr.Type))
                {
                    if (!TryQuote(type, ref expr))
                    {
                        throw LinqError.ExpressionTypeCannotInitializeArrayType(expr.Type, type);
                    }

                    if (newList == null)
                    {
                        newList = new Expression[initializerList.Count];
                        for (int j = 0; j < i; j++)
                        {
                            newList[j] = initializerList[j];
                        }
                    }
                }

                if (newList != null)
                {
                    newList[i] = expr;
                }
            }

            if (newList != null)
            {
                initializerList = new TrueReadOnlyCollection <Expression>(newList);
            }

            return(new NewMultidimensionalArrayInitCSharpExpression(type.MakeArrayType(boundsList.Count), boundsList, initializerList));
        }