Esempio n. 1
0
        private static void ValidateIndexer(Type instanceType, PropertyInfo indexer)
        {
            // NB: We rely on the LINQ API to do validation of the indexer, including the setter (if any). We
            //     have to validate the setter as well because this node could reduce into an assignment when
            //     used in combination with C# assignment expressions. Note that the LINQ API won't treat our
            //     node as assignable when used with LINQ assignment expressions. Our reduction of assignment
            //     will properly call the setter, thus we have to make sure things are well-typed.

            var parameters = indexer.GetIndexParameters();

            var n    = parameters.Length;
            var args = new Expression[n];

            for (var i = 0; i < n; i++)
            {
                // NB: This is just a trick to be compatible with the signature of ValidateIndexeProperty but
                //     we could change the LINQ APIs to have a variant that just takes in types. Shouldn't be
                //     a big deal though, given that most indexers only have a few parameters.
                args[i] = Expression.Default(parameters[i].ParameterType);
            }

            var original = new TrueReadOnlyCollection <Expression>(args);
            var argList  = (ReadOnlyCollection <Expression>)original;

            ValidateIndexedProperty(Expression.Default(instanceType), indexer, ref argList);

            // NB: We don't expect mutations because all expressions match the corresponding indexer parameter
            //     type. As such, we shouldn't end up quoting any argument.
            Debug.Assert(argList == original);
        }
Esempio n. 2
0
 internal NewExpression(ConstructorInfo constructor, Expression[] arguments, ReadOnlyCollection <MemberInfo> members)
 {
     Constructor = constructor;
     _arguments  = arguments;
     Members     = members;
     _argumentsAsReadOnlyCollection = new TrueReadOnlyCollection <Expression>(_arguments);
 }
        private static MethodCallCSharpExpression MakeAccess(ConditionalReceiver receiver, MethodInfo method, ReadOnlyCollection <ParameterAssignment> arguments)
        {
            if (method.IsStatic && method.IsDefined(typeof(ExtensionAttribute)))
            {
                var thisPar = method.GetParametersCached()[0];
                var thisArg = CSharpExpression.Bind(thisPar, receiver);

                var newArgs = new ParameterAssignment[arguments.Count + 1];
                newArgs[0] = thisArg;

                var i = 1;
                foreach (var arg in arguments)
                {
                    newArgs[i++] = arg;
                }

                var newArguments = new TrueReadOnlyCollection <ParameterAssignment>(newArgs);

                return(CSharpExpression.Call(null, method, newArguments)); // TODO: call ctor directly
            }
            else
            {
                return(CSharpExpression.Call(receiver, method, arguments)); // TODO: call ctor directly
            }
        }
        internal static ReadOnlyCollection <T> ToReadOnly <T>(this IEnumerable <T> enumerable)
        {
            if (enumerable == null)
            {
                return(EmptyReadOnlyCollection <T> .Instance);
            }
            TrueReadOnlyCollection <T> onlys = enumerable as TrueReadOnlyCollection <T>;

            if (onlys != null)
            {
                return(onlys);
            }
            ReadOnlyCollectionBuilder <T> builder = enumerable as ReadOnlyCollectionBuilder <T>;

            if (builder != null)
            {
                return(builder.ToReadOnlyCollection());
            }
            ICollection <T> is2 = enumerable as ICollection <T>;

            if (is2 == null)
            {
                return(new TrueReadOnlyCollection <T>(new List <T>(enumerable).ToArray()));
            }
            int count = is2.Count;

            if (count == 0)
            {
                return(EmptyReadOnlyCollection <T> .Instance);
            }
            T[] array = new T[count];
            is2.CopyTo(array, 0);
            return(new TrueReadOnlyCollection <T>(array));
        }
Esempio n. 5
0
        public static void ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ref ReadOnlyCollection <Expression> arguments)
        {
            Debug.Assert(nodeKind == ExpressionType.Invoke || nodeKind == ExpressionType.Call || nodeKind == ExpressionType.Dynamic || nodeKind == ExpressionType.New);

            ParameterInfo[] pis = GetParametersForValidation(method, nodeKind);

            ValidateArgumentCount(method, nodeKind, arguments.Count, pis);

            Expression[] newArgs = null;
            for (int i = 0, n = pis.Length; i < n; i++)
            {
                Expression    arg = arguments[i];
                ParameterInfo pi  = pis[i];
                arg = ValidateOneArgument(method, nodeKind, arg, pi);

                if (newArgs == null && arg != arguments[i])
                {
                    newArgs = new Expression[arguments.Count];
                    for (int j = 0; j < i; j++)
                    {
                        newArgs[j] = arguments[j];
                    }
                }
                if (newArgs != null)
                {
                    newArgs[i] = arg;
                }
            }
            if (newArgs != null)
            {
                arguments = new TrueReadOnlyCollection <Expression>(newArgs);
            }
        }
Esempio n. 6
0
        internal BlockN(Expression[] expressions)
        {
            Debug.Assert(expressions.Length != 0);

            _expressions = expressions;
            _expressionsAsReadOnlyCollection = new TrueReadOnlyCollection <Expression>(_expressions);
        }
Esempio n. 7
0
        public override TypeSlim ToType(DeserializationDomain domain, TypeSlim[] genericArguments)
        {
            if (_type == null)
            {
                var def = domain.GetType(_genericTypeDefinition).ToType(domain, genericArguments);
                GenericDefinitionTypeSlim genDef;

                switch (def.Kind)
                {
                case TypeSlimKind.Simple:
                    var simple = (SimpleTypeSlim)def;
                    genDef = TypeSlim.GenericDefinition(simple.Assembly, simple.Name);
                    break;

                default:
                    throw new InvalidOperationException("Expected either simple type slim discriminator for generic definition type.");
                }

                var n        = _genericTypeArguments.Length;
                var argsList = new TypeSlim[n];

                for (var i = 0; i < n; i++)
                {
                    var arg     = _genericTypeArguments[i];
                    var argType = domain.GetType(arg).ToType(domain, genericArguments);
                    argsList[i] = argType;
                }

                var args = new TrueReadOnlyCollection <TypeSlim>(/* transfer ownership */ argsList);
                _type = TypeSlim.Generic(genDef, args);
            }

            return(_type);
        }
Esempio n. 8
0
        internal MemberMemberBinding(MemberInfo member, MemberBinding[] bindings)
#pragma warning disable 618
            : base(MemberBindingType.MemberBinding, member)
        {
#pragma warning restore 618
            _bindings = bindings;
            _bindingsAsReadOnlyCollection = new TrueReadOnlyCollection <MemberBinding>(_bindings);
        }
Esempio n. 9
0
 internal TryExpression(Type type, Expression body, Expression @finally, Expression fault, CatchBlock[] handlers)
 {
     Type      = type;
     Body      = body;
     _handlers = handlers;
     Finally   = @finally;
     Fault     = fault;
     _handlersAsReadOnlyCollection = new TrueReadOnlyCollection <CatchBlock>(_handlers);
 }
Esempio n. 10
0
 internal SwitchExpression(Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison, SwitchCase[] cases)
 {
     Type        = type;
     SwitchValue = switchValue;
     DefaultBody = defaultBody;
     Comparison  = comparison;
     _cases      = cases;
     _casesAsReadOnlyCollection = new TrueReadOnlyCollection <SwitchCase>(_cases);
 }
Esempio n. 11
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;
                for (int i = 0, n = indexes.Length; i < n; i++)
                {
                    Expression    arg = arguments[i];
                    ParameterInfo pi  = indexes[i];
                    RequiresCanRead(arg, "arguments");

                    Type pType = pi.ParameterType;
                    if (pType.IsByRef)
                    {
                        throw Error.AccessorsCannotHaveByRefArgs();
                    }
                    TypeUtils.ValidateType(pType);

                    if (!TypeUtils.AreReferenceAssignable(pType, arg.Type))
                    {
                        if (TypeUtils.IsSameOrSubclass(typeof(LambdaExpression), pType) && pType.IsAssignableFrom(arg.GetType()))
                        {
                            arg = Expression.Quote(arg);
                        }
                        else
                        {
                            throw Error.ExpressionTypeDoesNotMatchMethodParameter(arg.Type, pType, method);
                        }
                    }
                    if (newArgs == null && arg != arguments[i])
                    {
                        newArgs = new Expression[arguments.Count];
                        for (int 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);
            }
        }
Esempio n. 12
0
        /// <summary>
        /// Creates a <see cref="NewArrayExpression"/> 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>A <see cref="NewArrayExpression"/> that has the <see cref="NodeType"/> property equal to <see cref="ExpressionType.NewArrayInit"/> and the <see cref="NewArrayExpression.Expressions"/> property set to the specified value.</returns>
        public static NewArrayExpression NewArrayInit(Type type, IEnumerable <Expression> initializers)
        {
            ContractUtils.RequiresNotNull(type, nameof(type));
            ContractUtils.RequiresNotNull(initializers, nameof(initializers));
            if (type == typeof(void))
            {
                throw Error.ArgumentCannotBeOfTypeVoid(nameof(type));
            }

            TypeUtils.ValidateType(type, nameof(type));
            if (type.IsByRef)
            {
                throw Error.TypeMustNotBeByRef(nameof(type));
            }

            if (type.IsPointer)
            {
                throw Error.TypeMustNotBePointer(nameof(type));
            }

            ReadOnlyCollection <Expression> initializerList = initializers.ToReadOnly();

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

                if (!TypeUtils.AreReferenceAssignable(type, expr.Type))
                {
                    if (!TryQuote(type, ref expr))
                    {
                        throw Error.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(NewArrayExpression.Make(ExpressionType.NewArrayInit, type.MakeArrayType(), initializerList));
        }
Esempio n. 13
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);
            }
        }
        /// <summary>
        /// Reduces the expression node to a simpler expression.
        /// </summary>
        /// <returns>The reduced expression.</returns>
        public override Expression Reduce()
        {
            var statements = default(ReadOnlyCollection <Expression>);

            if (ReturnLabel == null)
            {
                if (Statements.Count == 0)
                {
                    // NB: Can ignore variables; there's no expression that can use them anyway, and they don't have side-effects.
                    return(Expression.Empty());
                }
                else
                {
                    statements = Statements;
                }
            }
            else
            {
                var returnLabel = default(LabelExpression);

                if (ReturnLabel.Type != typeof(void))
                {
                    returnLabel = Expression.Label(ReturnLabel, Expression.Default(ReturnLabel.Type));
                }
                else
                {
                    returnLabel = Expression.Label(ReturnLabel);
                }

                if (Statements.Count == 0)
                {
                    // NB: Can ignore variables; there's no expression that can use them anyway, and they don't have side-effects.
                    return(returnLabel);
                }
                else
                {
                    statements = new TrueReadOnlyCollection <Expression>(Statements.AddLast(returnLabel));
                }
            }

            if (Variables.Count == 0)
            {
                return(Expression.Block(Type, statements));
            }
            else
            {
                // REVIEW: Should we ensure all variables get assigned default values? Cf. when it's used
                //         in a loop and the locals don't get reinitialized. Or should we assume there's
                //         definite assignment (or enforce it)?
                return(Expression.Block(Type, Variables, statements));
            }
        }
Esempio n. 15
0
        private static void ValidateAccessorArgumentTypes(MethodInfo method, ParameterInfo[] indexes, ref ReadOnlyCollection <Expression> arguments, string?paramName)
        {
            if (indexes.Length > 0)
            {
                if (indexes.Length != arguments.Count)
                {
                    throw Error.IncorrectNumberOfMethodCallArguments(method, paramName);
                }
                Expression[]? newArgs = null;
                for (int i = 0, n = indexes.Length; i < n; i++)
                {
                    Expression    arg = arguments[i];
                    ParameterInfo pi  = indexes[i];
                    ExpressionUtils.RequiresCanRead(arg, nameof(arguments), i);

                    Type pType = pi.ParameterType;
                    if (pType.IsByRef)
                    {
                        throw Error.AccessorsCannotHaveByRefArgs(nameof(indexes), i);
                    }
                    TypeUtils.ValidateType(pType, nameof(indexes), i);

                    if (!TypeUtils.AreReferenceAssignable(pType, arg.Type))
                    {
                        if (!TryQuote(pType, ref arg))
                        {
                            throw Error.ExpressionTypeDoesNotMatchMethodParameter(arg.Type, pType, method, nameof(arguments), i);
                        }
                    }
                    if (newArgs == null && arg != arguments[i])
                    {
                        newArgs = new Expression[arguments.Count];
                        for (int 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, paramName);
            }
        }
Esempio n. 16
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.Equals(typeof(void)))
            {
                throw Error.ArgumentCannotBeOfTypeVoid();
            }

            ReadOnlyCollection <Expression> initializerList = initializers.ToReadOnly();

            Expression[] newList = null;
            for (int i = 0, n = initializerList.Count; i < n; i++)
            {
                Expression expr = initializerList[i];
                RequiresCanRead(expr, "initializers");

                if (!TypeUtils.AreReferenceAssignable(type, expr.Type))
                {
                    if (TypeUtils.IsSameOrSubclass(typeof(LambdaExpression), type) && type.IsAssignableFrom(expr.GetType()))
                    {
                        expr = Expression.Quote(expr);
                    }
                    else
                    {
                        throw Error.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(NewArrayExpression.Make(ExpressionType.NewArrayInit, type.MakeArrayType(), initializerList));
        }
Esempio n. 17
0
        internal IndexExpression(
            Expression instance,
            PropertyInfo indexer,
            Expression[] arguments)
        {
            if (indexer == null)
            {
                Debug.Assert(instance != null && instance.Type.IsArray);
                Debug.Assert(instance.Type.GetArrayRank() == arguments.Length);
            }

            Object     = instance;
            Indexer    = indexer;
            _arguments = arguments;
            _argumentsAsReadOnlyCollection = new TrueReadOnlyCollection <Expression>(_arguments);
        }
 internal HoistedLocals(HoistedLocals parent, ReadOnlyCollection<ParameterExpression> vars)
 {
     if (parent != null)
     {
         vars = new TrueReadOnlyCollection<ParameterExpression>(vars.AddFirst<ParameterExpression>(parent.SelfVariable));
     }
     Dictionary<Expression, int> dict = new Dictionary<Expression, int>(vars.Count);
     for (int i = 0; i < vars.Count; i++)
     {
         dict.Add(vars[i], i);
     }
     this.SelfVariable = Expression.Variable(typeof(object[]), null);
     this.Parent = parent;
     this.Variables = vars;
     this.Indexes = new ReadOnlyDictionary<Expression, int>(dict);
 }
Esempio n. 19
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));
        }
Esempio n. 20
0
        internal HoistedLocals(HoistedLocals parent, ReadOnlyCollection<ParameterExpression> vars) {

            if (parent != null) {
                // Add the parent locals array as the 0th element in the array
                vars = new TrueReadOnlyCollection<ParameterExpression>(vars.AddFirst(parent.SelfVariable));
            }

            Dictionary<Expression, int> indexes = new Dictionary<Expression, int>(vars.Count);
            for (int i = 0; i < vars.Count; i++) {
                indexes.Add(vars[i], i);
            }

            SelfVariable = Expression.Variable(typeof(object[]), null);
            Parent = parent;
            Variables = vars;
            Indexes = new ReadOnlyDictionary<Expression, int>(indexes);
        }
Esempio n. 21
0
        internal HoistedLocals(HoistedLocals parent, ReadOnlyCollection <ParameterExpression> vars)
        {
            if (parent != null)
            {
                vars = new TrueReadOnlyCollection <ParameterExpression>(vars.AddFirst <ParameterExpression>(parent.SelfVariable));
            }
            Dictionary <Expression, int> dict = new Dictionary <Expression, int>(vars.Count);

            for (int i = 0; i < vars.Count; i++)
            {
                dict.Add(vars[i], i);
            }
            this.SelfVariable = Expression.Variable(typeof(object[]), null);
            this.Parent       = parent;
            this.Variables    = vars;
            this.Indexes      = new ReadOnlyDictionary <Expression, int>(dict);
        }
Esempio n. 22
0
        public override MemberInfoSlim ToMember(DeserializationDomain domain)
        {
            // PERF: This is a heavy allocator; should we support caching the result?

            var def = ((GenericDefinitionMethodInfoSlim)domain.GetMember(_genericMethodDefinition));

            var count = _genericArguments.Length;

            var argsList = new TypeSlim[count];

            for (var i = 0; i < count; i++)
            {
                argsList[i] = domain.GetType(_genericArguments[i]).ToType(domain);
            }

            var args = new TrueReadOnlyCollection <TypeSlim>(/* transfer ownership */ argsList);

            return(def.DeclaringType.GetGenericMethod(def, args));
        }
Esempio n. 23
0
        internal HoistedLocals(HoistedLocals parent, ReadOnlyCollection <ParameterExpression> vars)
        {
            if (parent != null)
            {
                // Add the parent locals array as the 0th element in the array
                vars = new TrueReadOnlyCollection <ParameterExpression>(vars.AddFirst(parent.SelfVariable));
            }

            Dictionary <Expression, int> indexes = new Dictionary <Expression, int>(vars.Count);

            for (int i = 0; i < vars.Count; i++)
            {
                indexes.Add(vars[i], i);
            }

            SelfVariable = Expression.Variable(typeof(object[]), null);
            Parent       = parent;
            Variables    = vars;
            Indexes      = new ReadOnlyDictionary <Expression, int>(indexes);
        }
            public void EnsureLonelyDefault()
            {
                if (DefaultCase != null && !IsDefaultLonely)
                {
                    // We have a default case but it's mingled up with other cases, e.g.
                    //
                    //   switch (x)
                    //   {
                    //     case 1:
                    //     case 2:
                    //     default:
                    //       ...
                    //       break;
                    //   }
                    //
                    // We can simply drop the other test values for compilation purposes, e.g.
                    //
                    //  switch (x)
                    //  {
                    //    default:
                    //       ...
                    //       break;
                    //  }

                    var roDefaultTestValues = new TrueReadOnlyCollection <object>(new[] { SwitchCaseDefaultValue });
                    var newDefaultCase      = new CSharpSwitchCase(roDefaultTestValues, DefaultCase.Statements);

                    if (DefaultCase == NullCase)
                    {
                        NullCase     = null;
                        IsNullLonely = false;
                    }

                    DefaultCase     = newDefaultCase;
                    IsDefaultLonely = true;
                }
            }
Esempio n. 25
0
 public InvocationExpressionN(Expression lambda, Expression[] arguments, Type returnType)
     : base(lambda, returnType)
 {
     _arguments           = arguments;
     _argumentsAsReadOnly = new TrueReadOnlyCollection <Expression>(_arguments);
 }
Esempio n. 26
0
 internal ScopeExpression(ParameterExpression[] variables)
 {
     _variables = variables;
     _variablesAsReadOnlyCollection = new TrueReadOnlyCollection <ParameterExpression>(_variables);
 }
Esempio n. 27
0
 internal ScopeN(ParameterExpression[] variables, Expression[] body)
     : base(variables)
 {
     _body = body;
     _bodyAsReadOnlyCollection = new TrueReadOnlyCollection <Expression>(_body);
 }
Esempio n. 28
0
 internal ElementInit(MethodInfo addMethod, Expression[] arguments)
 {
     AddMethod = addMethod;
     _argumentsAsReadOnlyCollection = new TrueReadOnlyCollection <Expression>(arguments);
 }
Esempio n. 29
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.Equals(typeof(void))) {
                throw Error.ArgumentCannotBeOfTypeVoid();
            }

            ReadOnlyCollection<Expression> initializerList = initializers.ToReadOnly();

            Expression[] newList = null;
            for (int i = 0, n = initializerList.Count; i < n; i++) {
                Expression expr = initializerList[i];
                RequiresCanRead(expr, "initializers");

                if (!TypeUtils.AreReferenceAssignable(type, expr.Type)) {
                    if (!TryQuote(type, ref expr)){
                        throw Error.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 NewArrayExpression.Make(ExpressionType.NewArrayInit, type.MakeArrayType(), initializerList);
        }
        private static void ValidateIndexer(Type instanceType, PropertyInfo indexer)
        {
            // NB: We rely on the LINQ API to do validation of the indexer, including the setter (if any). We
            //     have to validate the setter as well because this node could reduce into an assignment when
            //     used in combination with C# assignment expressions. Note that the LINQ API won't treat our
            //     node as assignable when used with LINQ assignment expressions. Our reduction of assignment
            //     will properly call the setter, thus we have to make sure things are well-typed.

            var parameters = indexer.GetIndexParameters();

            var n = parameters.Length;
            var args = new Expression[n];
            for (var i = 0; i < n; i++)
            {
                // NB: This is just a trick to be compatible with the signature of ValidateIndexeProperty but
                //     we could change the LINQ APIs to have a variant that just takes in types. Shouldn't be
                //     a big deal though, given that most indexers only have a few parameters.
                args[i] = Expression.Default(parameters[i].ParameterType);
            }

            var original = new TrueReadOnlyCollection<Expression>(args);
            var argList = (ReadOnlyCollection<Expression>)original;
            ValidateIndexedProperty(Expression.Default(instanceType), indexer, ref argList);

            // NB: We don't expect mutations because all expressions match the corresponding indexer parameter
            //     type. As such, we shouldn't end up quoting any argument.
            Debug.Assert(argList == original);
        }
            public void EnsureLonelyDefault()
            {
                if (DefaultCase != null && !IsDefaultLonely)
                {
                    // We have a default case but it's mingled up with other cases, e.g.
                    //
                    //   switch (x)
                    //   {
                    //     case 1:
                    //     case 2:
                    //     case default:
                    //       ...
                    //       break;
                    //   }
                    //
                    // We can simply drop the other test values for compilation purposes, e.g.
                    //
                    //  switch (x)
                    //  {
                    //    case default:
                    //       ...
                    //       break;
                    //  }

                    var roDefaultTestValues = new TrueReadOnlyCollection<object>(new[] { SwitchCaseDefaultValue });
                    var newDefaultCase = new CSharpSwitchCase(roDefaultTestValues, DefaultCase.Statements);

                    if (DefaultCase == NullCase)
                    {
                        NullCase = null;
                        IsNullLonely = false;
                    }

                    DefaultCase = newDefaultCase;
                    IsDefaultLonely = true;
                }
            }
        /// <summary>
        /// Reduces the expression node to a simpler expression.
        /// </summary>
        /// <returns>The reduced expression.</returns>
        public override Expression Reduce()
        {
            // NB: Unlike the C# compiler, we don't optimize for the case where all elements are constants of a
            //     blittable type. In such a case, the C# compiler will emit a field with the binary representation
            //     of the whole array and emit a call to RuntimeHelpers.InitializeArray. To achieve this, we'd need
            //     to have access to a ModuleBuilder, also tying the reduction path to the compiler and requiring
            //     separate treatment for the interpreter.
            //
            //     This optimization would matter most if many copies of the array are initialized or the array is
            //     really big, and it only contains constants. In the case of a big array, we could argue that the
            //     current expression API has many ineffiencies already, e.g. when emitting closures including lots
            //     of captured variables, which does not create a display class but an array of StrongBox<T> objects.
            //
            //     An alternative, which could be useful if the expression is evaluated many times (creating many
            //     copies), would be to prepare an instance of the array, cache it, and use Array.Clone to create
            //     a copy each time the expression is evaluated. Effectively, the reduced expression would become a
            //     Constant node containing the fully materialized array. This would only be worth the effort if the
            //     cost of creating a clone is sufficiently less compared to element-by-element initialization which
            //     is likely true given it does a memberwise clone underneath. One drawback is that the expression
            //     would root the "prototype" of the array, but this is comparable to the module image containing a
            //     blob containing the array elements from which copies are created through InitializeArray (unless
            //     it employs a copy-on-write approach, haven't checked).
            //
            //     Note that the optimization sketched above could also be applied to ArrayInit nodes in LINQ, by
            //     changing the LambdaCompiler (see ILGen.EmitArray which generates a sequence of stelems). It
            //     doesn't seem like it was considered there, so maybe we can get away without it here as well.
            //
            //     Finally, not that the reduction approach below is likely more expensive than EmitArray used by
            //     the LambdaCompiler which can use dup instructions where we'll have a ldloc instruction for each
            //     element being initialized.
            //
            //     A quick experiment with an optimizer for NewArrayInit nodes with only constants yields the
            //     following result (see Experiment.cs, method ArrayInitOptimization, in Playground):
            //
            //         [RAW] new int[10] x 100000 = 2ms
            //         [OPT] new int[10] x 100000 = 10ms
            //         [RAW] new int[100] x 100000 = 6ms
            //         [OPT] new int[100] x 100000 = 15ms
            //         [RAW] new int[400] x 100000 = 28ms   <<
            //         [OPT] new int[400] x 100000 = 23ms   <<
            //         [RAW] new int[500] x 100000 = 33ms
            //         [OPT] new int[500] x 100000 = 28ms
            //         [RAW] new int[1000] x 100000 = 69ms
            //         [OPT] new int[1000] x 100000 = 43ms
            //
            //     With 100K iterations of evaluating the expression, it takes an array of 400+ elements for the
            //     optimization to pay off. If we run into the need to optimize this, we should likely take such
            //     a measurement into account and only apply the optimization when the expression is contained in
            //     some loop construct and the element count is sufficiently large.

            var n    = Expressions.Count;
            var rank = Bounds.Count;

            var res   = Expression.Parameter(Type, "__array");
            var exprs = new Expression[n + 2];

            // NB: We need the bounds to NewArrayBounds and all values from 0 to each bound for ArrayAccess.
            var consts = Enumerable.Range(0, Bounds.Max() + 1).Select(CreateConstantInt32).ToArray();

            exprs[0] = Expression.Assign(res, Expression.NewArrayBounds(Type.GetElementType(), Bounds.Map(i => consts[i])));

            var indexValues = new int[rank];

            for (var i = 1; i <= n; i++)
            {
                var idx   = i - 1;
                var value = Expressions[idx];

                for (var j = rank - 1; j >= 0; j--)
                {
                    var bound = Bounds[j];
                    indexValues[j] = idx % bound;
                    idx           /= bound;
                }

                var indexes = new TrueReadOnlyCollection <Expression>(indexValues.Map(j => consts[j]));
                var element = Expression.ArrayAccess(res, indexes);

                exprs[i] = Expression.Assign(element, value);
            }

            exprs[n + 1] = res;

            return(Expression.Block(new[] { res }, exprs));
        }
Esempio n. 33
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];
                    RequiresCanRead(arg, "argument");
                    MemberInfo member = members[i];
                    ContractUtils.RequiresNotNull(member, nameof(member));
                    if (!TypeUtils.AreEquivalent(member.DeclaringType, constructor.DeclaringType))
                    {
                        throw Error.ArgumentMemberNotDeclOnType(member.Name, constructor.DeclaringType.Name);
                    }
                    Type memberType;
                    ValidateAnonymousTypeMember(ref member, out memberType);
                    if (!TypeUtils.AreReferenceAssignable(memberType, arg.Type))
                    {
                        if (!TryQuote(memberType, ref arg))
                        {
                            throw Error.ArgumentTypeDoesNotMatchMember(arg.Type, memberType);
                        }
                    }
                    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);
                        }
                    }
                    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();
            }
        }
        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 (!TypeUtils.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));
        }
        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 (!TypeUtils.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);
        }
Esempio n. 36
0
 internal NewArrayExpression(Type type, Expression[] expressions)
 {
     _expressions = expressions;
     Type         = type;
     _expressionsAsReadOnlyCollection = new TrueReadOnlyCollection <Expression>(_expressions);
 }
        private static void ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ref ReadOnlyCollection<Expression> arguments) {
            Debug.Assert(nodeKind == ExpressionType.Invoke || nodeKind == ExpressionType.Call || nodeKind == ExpressionType.Dynamic || nodeKind == ExpressionType.New);

            ParameterInfo[] pis = GetParametersForValidation(method, nodeKind);

            ValidateArgumentCount(method, nodeKind, arguments.Count, pis);

            Expression[] newArgs = null;
            for (int i = 0, n = pis.Length; i < n; i++) {
                Expression arg = arguments[i];
                ParameterInfo pi = pis[i];
                arg = ValidateOneArgument(method, nodeKind, arg, pi);

                if (newArgs == null && arg != arguments[i]) {
                    newArgs = new Expression[arguments.Count];
                    for (int j = 0; j < i; j++) {
                        newArgs[j] = arguments[j];
                    }
                }
                if (newArgs != null) {
                    newArgs[i] = arg;
                }
            }
            if (newArgs != null) {
                arguments = new TrueReadOnlyCollection<Expression>(newArgs);
            }
        }
Esempio n. 38
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;
                for (int i = 0, n = indexes.Length; i < n; i++)
                {
                    Expression arg = arguments[i];
                    ParameterInfo pi = indexes[i];
                    RequiresCanRead(arg, nameof(arguments));

                    Type pType = pi.ParameterType;
                    if (pType.IsByRef) throw Error.AccessorsCannotHaveByRefArgs();
                    TypeUtils.ValidateType(pType);

                    if (!TypeUtils.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 (int 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);
            }
        }
        /// <summary>
        /// Reduces the expression node to a simpler expression.
        /// </summary>
        /// <returns>The reduced expression.</returns>
        public override Expression Reduce()
        {
            // NB: Unlike the C# compiler, we don't optimize for the case where all elements are constants of a
            //     blittable type. In such a case, the C# compiler will emit a field with the binary representation
            //     of the whole array and emit a call to RuntimeHelpers.InitializeArray. To achieve this, we'd need
            //     to have access to a ModuleBuilder, also tying the reduction path to the compiler and requiring
            //     separate treatment for the interpreter.
            //
            //     This optimization would matter most if many copies of the array are initialized or the array is
            //     really big, and it only contains constants. In the case of a big array, we could argue that the
            //     current expression API has many ineffiencies already, e.g. when emitting closures including lots
            //     of captured variables, which does not create a display class but an array of StrongBox<T> objects.
            //
            //     An alternative, which could be useful if the expression is evaluated many times (creating many
            //     copies), would be to prepare an instance of the array, cache it, and use Array.Clone to create
            //     a copy each time the expression is evaluated. Effectively, the reduced expression would become a
            //     Constant node containing the fully materialized array. This would only be worth the effort if the
            //     cost of creating a clone is sufficiently less compared to element-by-element initialization which
            //     is likely true given it does a memberwise clone underneath. One drawback is that the expression
            //     would root the "prototype" of the array, but this is comparable to the module image containing a
            //     blob containing the array elements from which copies are created through InitializeArray (unless
            //     it employs a copy-on-write approach, haven't checked).
            //
            //     Note that the optimization sketched above could also be applied to ArrayInit nodes in LINQ, by
            //     changing the LambdaCompiler (see ILGen.EmitArray which generates a sequence of stelems). It
            //     doesn't seem like it was considered there, so maybe we can get away without it here as well.
            //
            //     Finally, not that the reduction approach below is likely more expensive than EmitArray used by
            //     the LambdaCompiler which can use dup instructions where we'll have a ldloc instruction for each
            //     element being initialized.
            //
            //     A quick experiment with an optimizer for NewArrayInit nodes with only constants yields the
            //     following result (see Experiment.cs, method ArrayInitOptimization, in Playground):
            //
            //         [RAW] new int[10] x 100000 = 2ms
            //         [OPT] new int[10] x 100000 = 10ms
            //         [RAW] new int[100] x 100000 = 6ms
            //         [OPT] new int[100] x 100000 = 15ms
            //         [RAW] new int[400] x 100000 = 28ms   <<
            //         [OPT] new int[400] x 100000 = 23ms   <<
            //         [RAW] new int[500] x 100000 = 33ms
            //         [OPT] new int[500] x 100000 = 28ms
            //         [RAW] new int[1000] x 100000 = 69ms
            //         [OPT] new int[1000] x 100000 = 43ms
            //
            //     With 100K iterations of evaluating the expression, it takes an array of 400+ elements for the
            //     optimization to pay off. If we run into the need to optimize this, we should likely take such
            //     a measurement into account and only apply the optimization when the expression is contained in
            //     some loop construct and the element count is sufficiently large.

            var n = Expressions.Count;
            var rank = Bounds.Count;

            var res = Expression.Parameter(Type, "__array");
            var exprs = new Expression[n + 2];

            // NB: We need the bounds to NewArrayBounds and all values from 0 to each bound for ArrayAccess.
            var consts = Enumerable.Range(0, Bounds.Max() + 1).Select(CreateConstantInt32).ToArray();

            exprs[0] = Expression.Assign(res, Expression.NewArrayBounds(Type.GetElementType(), Bounds.Map(i => consts[i])));

            var indexValues = new int[rank];

            for (var i = 1; i <= n; i++)
            {
                var idx = i - 1;
                var value = Expressions[idx];

                for (var j = rank - 1; j >= 0; j--)
                {
                    var bound = Bounds[j];
                    indexValues[j] = idx % bound;
                    idx /= bound;
                }

                var indexes = new TrueReadOnlyCollection<Expression>(indexValues.Map(j => consts[j]));
                var element = Expression.ArrayAccess(res, indexes);

                exprs[i] = Expression.Assign(element, value);
            }

            exprs[n + 1] = res;

            return Expression.Block(new[] { res }, exprs);
        }
        /// <summary>
        /// Reduces the expression node to a simpler expression.
        /// </summary>
        /// <returns>The reduced expression.</returns>
        public override Expression Reduce()
        {
            var statements = default(ReadOnlyCollection<Expression>);

            if (ReturnLabel == null)
            {
                if (Statements.Count == 0)
                {
                    // NB: Can ignore variables; there's no expression that can use them anyway, and they don't have side-effects.
                    return Expression.Empty();
                }
                else
                {
                    statements = Statements;
                }
            }
            else
            {
                var returnLabel = default(LabelExpression);

                if (ReturnLabel.Type != typeof(void))
                {
                    returnLabel = Expression.Label(ReturnLabel, Expression.Default(ReturnLabel.Type));
                }
                else
                {
                    returnLabel = Expression.Label(ReturnLabel);
                }

                if (Statements.Count == 0)
                {
                    // NB: Can ignore variables; there's no expression that can use them anyway, and they don't have side-effects.
                    return returnLabel;
                }
                else
                {
                    statements = new TrueReadOnlyCollection<Expression>(Statements.AddLast(returnLabel));
                }
            }

            if (Variables.Count == 0)
            {
                return Expression.Block(Type, statements);
            }
            else
            {
                // REVIEW: Should we ensure all variables get assigned default values? Cf. when it's used
                //         in a loop and the locals don't get reinitialized. Or should we assume there's
                //         definite assignment (or enforce it)?
                return Expression.Block(Type, Variables, statements);
            }
        }
Esempio n. 41
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();
            }
        }
Esempio n. 42
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;
                for (int i = 0, n = indexes.Length; i < n; i++) {
                    Expression arg = arguments[i];
                    ParameterInfo pi = indexes[i];
                    RequiresCanRead(arg, "arguments");

                    Type pType = pi.ParameterType;
                    ContractUtils.Requires(!pType.IsByRef, "indexes", Strings.AccessorsCannotHaveByRefArgs);
                    TypeUtils.ValidateType(pType);

                    if (!TypeUtils.AreReferenceAssignable(pType, arg.Type)) {
                        if (TypeUtils.IsSameOrSubclass(typeof(LambdaExpression), pType) && pType.IsAssignableFrom(arg.GetType())) {
                            arg = Expression.Quote(arg);
                        } else {
                            throw Error.ExpressionTypeDoesNotMatchMethodParameter(arg.Type, pType, method);
                        }
                    }
                    if (newArgs == null && arg != arguments[i]) {
                        newArgs = new Expression[arguments.Count];
                        for (int 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);
            }
        }