internal ForEachCSharpStatement(EnumeratorInfo enumeratorInfo, ReadOnlyCollection <ParameterExpression> variables, Expression collection, Expression body, LabelTarget breakLabel, LabelTarget continueLabel)
     : base(body, breakLabel, continueLabel)
 {
     EnumeratorInfo = enumeratorInfo;
     Variables      = variables;
     Collection     = collection;
 }
        /// <summary>
        /// Creates a new expression that is like this one, but using the supplied children. If all of the children are the same, it will return this expression.
        /// </summary>
        /// <param name="enumeratorInfo">The <see cref="EnumeratorInfo" /> property of the result.</param>
        /// <param name="breakLabel">The <see cref="LoopCSharpStatement.BreakLabel" /> property of the result.</param>
        /// <param name="continueLabel">The <see cref="LoopCSharpStatement.ContinueLabel" /> property of the result.</param>
        /// <param name="variables">The <see cref="Variables" /> property of the result.</param>
        /// <param name="collection">The <see cref="Collection" /> property of the result.</param>
        /// <param name="conversion">The <see cref="Conversion"/> property of the result.</param>
        /// <param name="body">The <see cref="LoopCSharpStatement.Body" /> property of the result.</param>
        /// <param name="deconstruction">The <see cref="Deconstruction"/> property of the result.</param>
        /// <param name="awaitInfo">The <see cref="AwaitInfo"/> property of the result.</param>
        /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
        public ForEachCSharpStatement Update(EnumeratorInfo enumeratorInfo, LabelTarget breakLabel, LabelTarget continueLabel, IEnumerable <ParameterExpression> variables, Expression collection, LambdaExpression conversion, Expression body, LambdaExpression deconstruction, AwaitInfo awaitInfo)
        {
            if (enumeratorInfo == EnumeratorInfo &&
                breakLabel == BreakLabel &&
                continueLabel == ContinueLabel &&
                SameElements(ref variables, Variables) &&
                collection == Collection &&
                conversion == Conversion &&
                body == Body &&
                deconstruction == Deconstruction &&
                awaitInfo == AwaitInfo)
            {
                return(this);
            }

            return(CSharpExpression.ForEach(awaitInfo, variables, collection, body, breakLabel, continueLabel, conversion, deconstruction));
        }
        internal static ForEachCSharpStatement Make(EnumeratorInfo enumeratorInfo, AwaitInfo awaitInfo, ReadOnlyCollection <ParameterExpression> variables, Expression collection, Expression body, LabelTarget breakLabel, LabelTarget continueLabel, LambdaExpression conversion, LambdaExpression deconstruction)
        {
            if (variables.Count == 0)
            {
                throw Error.ForEachNeedsOneOrMoreVariables();
            }

            RequiresNotNullItems(variables, nameof(variables));

            if (!AreReferenceAssignable(enumeratorInfo.CollectionType, collection.Type))
            {
                throw Error.ForEachCollectionTypeNotCompatibleWithCollectionExpression(enumeratorInfo.CollectionType, collection.Type);
            }

            RequiresCanRead(body, nameof(body));

            ValidateLoop(body, breakLabel, continueLabel);

            var firstVariable     = variables[0];
            var firstVariableType = firstVariable.Type;

            if (variables.Count == 1)
            {
                if (deconstruction != null)
                {
                    throw Error.ForEachDeconstructionNotSupportedWithOneVariable();
                }

                ValidateConversion(firstVariableType, enumeratorInfo.ElementType, ref conversion);
            }
            else
            {
                if (deconstruction == null)
                {
                    throw Error.ForEachDeconstructionRequiredForMultipleVariables();
                }

                ValidateDeconstruction(enumeratorInfo.ElementType, ref conversion, deconstruction, variables);
            }

            if (awaitInfo == null)
            {
                if (collection.Type == typeof(string) && variables.Count == 1 && firstVariableType == typeof(char) && conversion == null && deconstruction == null)
                {
                    return(new StringForEachStatement(enumeratorInfo, variables, collection, body, breakLabel, continueLabel));
                }
                else if (collection.Type.IsArray)
                {
                    if (collection.Type.IsVector())
                    {
                        if (conversion == null && deconstruction == null)
                        {
                            return(new SimpleArrayForEachCSharpStatement(enumeratorInfo, variables, collection, body, breakLabel, continueLabel));
                        }
                        else
                        {
                            return(new ArrayForEachCSharpStatement(enumeratorInfo, variables, collection, body, breakLabel, continueLabel, conversion, deconstruction));
                        }
                    }
                    else
                    {
                        return(new MultiDimensionalArrayForEachCSharpStatement(enumeratorInfo, variables, collection, body, breakLabel, continueLabel, conversion, deconstruction));
                    }
                }
            }
            else
            {
                awaitInfo.RequiresCanBind(enumeratorInfo.MoveNext.Body);
            }

            return(new BoundForEachCSharpStatement(enumeratorInfo, variables, collection, body, breakLabel, continueLabel, conversion, deconstruction, awaitInfo));
        }