PageRenderTime 124ms CodeModel.GetById 48ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 0ms

/Microsoft.Scripting.Core/Ast/BlockExpression.cs

https://bitbucket.org/stefanrusek/xronos
C# | 801 lines | 515 code | 135 blank | 151 comment | 73 complexity | 583a974491360985620f6f72dca2ce01 MD5 | raw file
  1/* ****************************************************************************
  2 *
  3 * Copyright (c) Microsoft Corporation. 
  4 *
  5 * This source code is subject to terms and conditions of the Microsoft Public License. A 
  6 * copy of the license can be found in the License.html file at the root of this distribution. If 
  7 * you cannot locate the  Microsoft Public License, please send an email to 
  8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
  9 * by the terms of the Microsoft Public License.
 10 *
 11 * You must not remove this notice, or any other, from this software.
 12 *
 13 *
 14 * ***************************************************************************/
 15using System; using Microsoft;
 16
 17
 18using System.Collections.Generic;
 19using System.Collections.ObjectModel;
 20using System.Diagnostics;
 21#if CODEPLEX_40
 22using System.Dynamic.Utils;
 23#else
 24using Microsoft.Scripting.Utils;
 25#endif
 26using System.Threading;
 27
 28#if CODEPLEX_40
 29namespace System.Linq.Expressions {
 30#else
 31namespace Microsoft.Linq.Expressions {
 32#endif
 33    /// <summary>
 34    /// Represents a block that contains a sequence of expressions where variables can be defined.
 35    /// </summary>
 36#if !SILVERLIGHT
 37    [DebuggerTypeProxy(typeof(Expression.BlockExpressionProxy))]
 38#endif
 39    public class BlockExpression : Expression {
 40        /// <summary>
 41        /// Gets the expressions in this block.
 42        /// </summary>
 43        public ReadOnlyCollection<Expression> Expressions {
 44            get { return GetOrMakeExpressions(); }
 45        }
 46
 47        /// <summary>
 48        /// Gets the variables defined in this block.
 49        /// </summary>
 50        public ReadOnlyCollection<ParameterExpression> Variables {
 51            get {
 52                return GetOrMakeVariables();
 53            }
 54        }
 55
 56        /// <summary>
 57        /// Gets the last expression in this block.
 58        /// </summary>
 59        public Expression Result {
 60            get {
 61                Debug.Assert(ExpressionCount > 0);
 62                return GetExpression(ExpressionCount - 1);
 63            }
 64        }
 65
 66        internal BlockExpression() {
 67        }
 68
 69        internal override Expression Accept(ExpressionVisitor visitor) {
 70            return visitor.VisitBlock(this);
 71        }
 72
 73        /// <summary>
 74        /// Returns the node type of this Expression. Extension nodes should return
 75        /// ExpressionType.Extension when overriding this method.
 76        /// </summary>
 77        /// <returns>The <see cref="ExpressionType"/> of the expression.</returns>
 78        protected override ExpressionType NodeTypeImpl() {
 79            return ExpressionType.Block;
 80        }
 81
 82        /// <summary>
 83        /// Gets the static type of the expression that this <see cref="Expression" /> represents.
 84        /// </summary>
 85        /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
 86        protected override Type TypeImpl() {
 87            return GetExpression(ExpressionCount - 1).Type;
 88        }
 89
 90        internal virtual Expression GetExpression(int index) {
 91            throw ContractUtils.Unreachable;
 92        }
 93
 94        internal virtual int ExpressionCount {
 95            get {
 96                throw ContractUtils.Unreachable;
 97            }
 98        }
 99
100        internal virtual ReadOnlyCollection<Expression> GetOrMakeExpressions() {
101            throw ContractUtils.Unreachable;
102        }
103
104        internal virtual ParameterExpression GetVariable(int index) {
105            throw ContractUtils.Unreachable;
106        }
107
108        internal virtual int VariableCount {
109            get {
110                return 0;
111            }
112        }
113
114        internal virtual ReadOnlyCollection<ParameterExpression> GetOrMakeVariables() {
115            return EmptyReadOnlyCollection<ParameterExpression>.Instance;
116        }
117
118        /// <summary>
119        /// Makes a copy of this node replacing the parameters/args with the provided values.  The 
120        /// shape of the parameters/args needs to match the shape of the current block - in other
121        /// words there should be the same # of parameters and args.
122        /// 
123        /// parameters can be null in which case the existing parameters are used.
124        /// 
125        /// This helper is provided to allow re-writing of nodes to not depend on the specific optimized
126        /// subclass of BlockExpression which is being used. 
127        /// </summary>
128        internal virtual BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
129            throw ContractUtils.Unreachable;
130        }
131
132        /// <summary>
133        /// Helper used for ensuring we only return 1 instance of a ReadOnlyCollection of T.
134        /// 
135        /// This is similar to the ReturnReadOnly which only takes a single argument. This version
136        /// supports nodes which hold onto 5 Expressions and puts all of the arguments into the
137        /// ReadOnlyCollection.
138        /// 
139        /// Ultimately this means if we create the readonly collection we will be slightly more wasteful as we'll
140        /// have a readonly collection + some fields in the type.  The DLR internally avoids accessing anything
141        /// which would force the readonly collection to be created.
142        /// 
143        /// This is used by BlockExpression5 and MethodCallExpression5.
144        /// </summary>
145        internal static ReadOnlyCollection<Expression> ReturnReadOnlyExpressions(BlockExpression provider, ref object collection) {
146            Expression tObj = collection as Expression;
147            if (tObj != null) {
148                // otherwise make sure only one readonly collection ever gets exposed
149                Interlocked.CompareExchange(
150                    ref collection,
151                    new ReadOnlyCollection<Expression>(new BlockExpressionList(provider, tObj)),
152                    tObj
153                );
154            }
155
156            // and return what is not guaranteed to be a readonly collection
157            return (ReadOnlyCollection<Expression>)collection;
158        }
159    }
160
161    #region Specialized Subclasses
162
163    internal sealed class Block2 : BlockExpression {
164        private object _arg0;                   // storage for the 1st argument or a readonly collection.  See IArgumentProvider
165        private readonly Expression _arg1;      // storage for the 2nd argument.
166
167        internal Block2(Expression arg0, Expression arg1) {
168            _arg0 = arg0;
169            _arg1 = arg1;
170        }
171
172        internal override Expression GetExpression(int index) {
173            switch (index) {
174                case 0: return ReturnObject<Expression>(_arg0);
175                case 1: return _arg1;
176                default: throw new InvalidOperationException();
177            }
178        }
179
180        internal override int ExpressionCount {
181            get {
182                return 2;
183            }
184        }
185
186        internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
187            return ReturnReadOnlyExpressions(this, ref _arg0);
188        }
189
190        internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
191            Debug.Assert(args.Length == 2);
192            Debug.Assert(variables == null || variables.Count == 0);
193
194            return new Block2(args[0], args[1]);
195        }
196    }
197
198    internal sealed class Block3 : BlockExpression {
199        private object _arg0;                       // storage for the 1st argument or a readonly collection.  See IArgumentProvider
200        private readonly Expression _arg1, _arg2;   // storage for the 2nd and 3rd arguments.
201
202        internal Block3(Expression arg0, Expression arg1, Expression arg2) {
203            _arg0 = arg0;
204            _arg1 = arg1;
205            _arg2 = arg2;
206        }
207
208        internal override Expression GetExpression(int index) {
209            switch (index) {
210                case 0: return ReturnObject<Expression>(_arg0);
211                case 1: return _arg1;
212                case 2: return _arg2;
213                default: throw new InvalidOperationException();
214            }
215        }
216
217        internal override int ExpressionCount {
218            get {
219                return 3;
220            }
221        }
222
223        internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
224            return ReturnReadOnlyExpressions(this, ref _arg0);
225        }
226
227        internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
228            Debug.Assert(args.Length == 3);
229            Debug.Assert(variables == null || variables.Count == 0);
230
231            return new Block3(args[0], args[1], args[2]);
232        }
233    }
234
235    internal sealed class Block4 : BlockExpression {
236        private object _arg0;                               // storage for the 1st argument or a readonly collection.  See IArgumentProvider
237        private readonly Expression _arg1, _arg2, _arg3;    // storarg for the 2nd, 3rd, and 4th arguments.
238
239        internal Block4(Expression arg0, Expression arg1, Expression arg2, Expression arg3) {
240            _arg0 = arg0;
241            _arg1 = arg1;
242            _arg2 = arg2;
243            _arg3 = arg3;
244        }
245
246        internal override Expression GetExpression(int index) {
247            switch (index) {
248                case 0: return ReturnObject<Expression>(_arg0);
249                case 1: return _arg1;
250                case 2: return _arg2;
251                case 3: return _arg3;
252                default: throw new InvalidOperationException();
253            }
254        }
255
256        internal override int ExpressionCount {
257            get {
258                return 4;
259            }
260        }
261
262        internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
263            return ReturnReadOnlyExpressions(this, ref _arg0);
264        }
265
266        internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
267            Debug.Assert(args.Length == 4);
268            Debug.Assert(variables == null || variables.Count == 0);
269
270            return new Block4(args[0], args[1], args[2], args[3]);
271        }
272    }
273
274    internal sealed class Block5 : BlockExpression {
275        private object _arg0;                                       // storage for the 1st argument or a readonly collection.  See IArgumentProvider
276        private readonly Expression _arg1, _arg2, _arg3, _arg4;     // storage for the 2nd - 5th args.
277
278        internal Block5(Expression arg0, Expression arg1, Expression arg2, Expression arg3, Expression arg4) {
279            _arg0 = arg0;
280            _arg1 = arg1;
281            _arg2 = arg2;
282            _arg3 = arg3;
283            _arg4 = arg4;
284        }
285
286        internal override Expression GetExpression(int index) {
287            switch (index) {
288                case 0: return ReturnObject<Expression>(_arg0);
289                case 1: return _arg1;
290                case 2: return _arg2;
291                case 3: return _arg3;
292                case 4: return _arg4;
293                default: throw new InvalidOperationException();
294            }
295        }
296
297        internal override int ExpressionCount {
298            get {
299                return 5;
300            }
301        }
302
303        internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
304            return ReturnReadOnlyExpressions(this, ref _arg0);
305        }
306
307        internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
308            Debug.Assert(args.Length == 5);
309            Debug.Assert(variables == null || variables.Count == 0);
310
311            return new Block5(args[0], args[1], args[2], args[3], args[4]);
312        }
313    }
314
315    internal class BlockN : BlockExpression {
316        private IList<Expression> _expressions;         // either the original IList<Expression> or a ReadOnlyCollection if the user has accessed it.
317
318        internal BlockN(IList<Expression> expressions) {
319            Debug.Assert(expressions.Count != 0);
320
321            _expressions = expressions;
322        }
323
324        internal override Expression GetExpression(int index) {
325            Debug.Assert(index >= 0 && index < _expressions.Count);
326
327            return _expressions[index];
328        }
329
330        internal override int ExpressionCount {
331            get {
332                return _expressions.Count;
333            }
334        }
335
336        internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
337            return ReturnReadOnly(ref _expressions);
338        }
339
340        internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
341            Debug.Assert(variables == null || variables.Count == 0);
342
343            return new BlockN(args);
344        }
345    }
346
347    internal class ScopeExpression : BlockExpression {
348        private IList<ParameterExpression> _variables;      // list of variables or ReadOnlyCollection if the user has accessed the readonly collection
349
350        internal ScopeExpression(IList<ParameterExpression> variables) {
351            _variables = variables;
352        }
353
354        internal override int VariableCount {
355            get {
356                return _variables.Count;
357            }
358        }
359
360        internal override ParameterExpression GetVariable(int index) {
361            return _variables[index];
362        }
363
364        internal override ReadOnlyCollection<ParameterExpression> GetOrMakeVariables() {
365            return ReturnReadOnly(ref _variables);
366        }
367
368        protected IList<ParameterExpression> VariablesList {
369            get {
370                return _variables;
371            }
372        }
373
374        // Used for rewrite of the nodes to either reuse existing set of variables if not rewritten.
375        internal IList<ParameterExpression> ReuseOrValidateVariables(ReadOnlyCollection<ParameterExpression> variables) {
376            if (variables != null && variables != VariablesList) {
377                // Need to validate the new variables (uniqueness, not byref)
378                ValidateVariables(variables, "variables");
379                return variables;
380            } else {
381                return VariablesList;
382            }
383        }
384    }
385
386    internal sealed class Scope1 : ScopeExpression {
387        private object _body;
388
389        internal Scope1(IList<ParameterExpression> variables, Expression body)
390            : base(variables) {
391            _body = body;
392        }
393
394        internal override Expression GetExpression(int index) {
395            switch (index) {
396                case 0: return ReturnObject<Expression>(_body);
397                default: throw new InvalidOperationException();
398            }
399        }
400
401        internal override int ExpressionCount {
402            get {
403                return 1;
404            }
405        }
406
407        internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
408            return ReturnReadOnlyExpressions(this, ref _body);
409        }
410
411        internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
412            Debug.Assert(args.Length == 1);
413            Debug.Assert(variables == null || variables.Count == VariableCount);
414
415            return new Scope1(ReuseOrValidateVariables(variables), args[0]);
416        }
417    }
418
419    internal class ScopeN : ScopeExpression {
420        private IList<Expression> _body;
421
422        internal ScopeN(IList<ParameterExpression> variables, IList<Expression> body)
423            : base(variables) {
424            _body = body;
425        }
426
427        internal override Expression GetExpression(int index) {
428            return _body[index];
429        }
430
431        internal override int ExpressionCount {
432            get {
433                return _body.Count;
434            }
435        }
436
437        internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
438            return ReturnReadOnly(ref _body);
439        }
440
441        internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
442            Debug.Assert(args.Length == ExpressionCount);
443            Debug.Assert(variables == null || variables.Count == VariableCount);
444
445            return new ScopeN(ReuseOrValidateVariables(variables), args);
446        }
447    }
448
449    internal class ScopeWithType : ScopeN {
450        private readonly Type _type;
451
452        internal ScopeWithType(IList<ParameterExpression> variables, IList<Expression> expressions, Type type)
453            : base(variables, expressions) {
454            _type = type;
455        }
456
457        protected override Type TypeImpl() {
458            return _type;
459        }
460
461        internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
462            Debug.Assert(args.Length == ExpressionCount);
463            Debug.Assert(variables == null || variables.Count == VariableCount);
464
465            return new ScopeWithType(ReuseOrValidateVariables(variables), args, _type);
466        }
467    }
468
469    #endregion
470
471    #region Block List Classes
472
473    /// <summary>
474    /// Provides a wrapper around an IArgumentProvider which exposes the argument providers
475    /// members out as an IList of Expression.  This is used to avoid allocating an array
476    /// which needs to be stored inside of a ReadOnlyCollection.  Instead this type has
477    /// the same amount of overhead as an array without duplicating the storage of the
478    /// elements.  This ensures that internally we can avoid creating and copying arrays
479    /// while users of the Expression trees also don't pay a size penalty for this internal
480    /// optimization.  See IArgumentProvider for more general information on the Expression
481    /// tree optimizations being used here.
482    /// </summary>
483    internal class BlockExpressionList : IList<Expression> {
484        private readonly BlockExpression _block;
485        private readonly Expression _arg0;
486
487        internal BlockExpressionList(BlockExpression provider, Expression arg0) {
488            _block = provider;
489            _arg0 = arg0;
490        }
491
492        #region IList<Expression> Members
493
494        public int IndexOf(Expression item) {
495            if (_arg0 == item) {
496                return 0;
497            }
498
499            for (int i = 1; i < _block.ExpressionCount; i++) {
500                if (_block.GetExpression(i) == item) {
501                    return i;
502                }
503            }
504
505            return -1;
506        }
507
508        public void Insert(int index, Expression item) {
509            throw ContractUtils.Unreachable;
510        }
511
512        public void RemoveAt(int index) {
513            throw ContractUtils.Unreachable;
514        }
515
516        public Expression this[int index] {
517            get {
518                if (index == 0) {
519                    return _arg0;
520                }
521
522                return _block.GetExpression(index);
523            }
524            set {
525                throw ContractUtils.Unreachable;
526            }
527        }
528
529        #endregion
530
531        #region ICollection<Expression> Members
532
533        public void Add(Expression item) {
534            throw ContractUtils.Unreachable;
535        }
536
537        public void Clear() {
538            throw ContractUtils.Unreachable;
539        }
540
541        public bool Contains(Expression item) {
542            return IndexOf(item) != -1;
543        }
544
545        public void CopyTo(Expression[] array, int arrayIndex) {
546            array[arrayIndex++] = _arg0;
547            for (int i = 1; i < _block.ExpressionCount; i++) {
548                array[arrayIndex++] = _block.GetExpression(i);
549            }
550        }
551
552        public int Count {
553            get { return _block.ExpressionCount; }
554        }
555
556        public bool IsReadOnly {
557            get { return true; }
558        }
559
560        public bool Remove(Expression item) {
561            throw ContractUtils.Unreachable;
562        }
563
564        #endregion
565
566        #region IEnumerable<Expression> Members
567
568        public IEnumerator<Expression> GetEnumerator() {
569            yield return _arg0;
570
571            for (int i = 1; i < _block.ExpressionCount; i++) {
572                yield return _block.GetExpression(i);
573            }
574        }
575
576        #endregion
577
578        #region IEnumerable Members
579
580        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
581            yield return _arg0;
582
583            for (int i = 1; i < _block.ExpressionCount; i++) {
584                yield return _block.GetExpression(i);
585            }
586        }
587
588        #endregion
589    }
590
591    #endregion
592
593    public partial class Expression {
594
595        /// <summary>
596        /// Creates a <see cref="BlockExpression"/> that contains two expressions and has no variables.
597        /// </summary>
598        /// <param name="arg0">The first expression in the block.</param>
599        /// <param name="arg1">The second expression in the block.</param>
600        /// <returns>The created <see cref="BlockExpression"/>.</returns>
601        public static BlockExpression Block(Expression arg0, Expression arg1) {
602            RequiresCanRead(arg0, "arg0");
603            RequiresCanRead(arg1, "arg1");
604
605            return new Block2(arg0, arg1);
606        }
607        /// <summary>
608        /// Creates a <see cref="BlockExpression"/> that contains three expressions and has no variables.
609        /// </summary>
610        /// <param name="arg0">The first expression in the block.</param>
611        /// <param name="arg1">The second expression in the block.</param>
612        /// <param name="arg2">The third expression in the block.</param>
613        /// <returns>The created <see cref="BlockExpression"/>.</returns>
614        public static BlockExpression Block(Expression arg0, Expression arg1, Expression arg2) {
615            RequiresCanRead(arg0, "arg0");
616            RequiresCanRead(arg1, "arg1");
617            RequiresCanRead(arg2, "arg2");
618            return new Block3(arg0, arg1, arg2);
619        }
620
621        /// <summary>
622        /// Creates a <see cref="BlockExpression"/> that contains four expressions and has no variables.
623        /// </summary>
624        /// <param name="arg0">The first expression in the block.</param>
625        /// <param name="arg1">The second expression in the block.</param>
626        /// <param name="arg2">The third expression in the block.</param>
627        /// <param name="arg3">The fourth expression in the block.</param>
628        /// <returns>The created <see cref="BlockExpression"/>.</returns>
629        public static BlockExpression Block(Expression arg0, Expression arg1, Expression arg2, Expression arg3) {
630            RequiresCanRead(arg0, "arg0");
631            RequiresCanRead(arg1, "arg1");
632            RequiresCanRead(arg2, "arg2");
633            RequiresCanRead(arg3, "arg3");
634            return new Block4(arg0, arg1, arg2, arg3);
635        }
636
637        /// <summary>
638        /// Creates a <see cref="BlockExpression"/> that contains five expressions and has no variables.
639        /// </summary>
640        /// <param name="arg0">The first expression in the block.</param>
641        /// <param name="arg1">The second expression in the block.</param>
642        /// <param name="arg2">The third expression in the block.</param>
643        /// <param name="arg3">The fourth expression in the block.</param>
644        /// <param name="arg4">The fifth expression in the block.</param>
645        /// <returns>The created <see cref="BlockExpression"/>.</returns>
646        public static BlockExpression Block(Expression arg0, Expression arg1, Expression arg2, Expression arg3, Expression arg4) {
647            RequiresCanRead(arg0, "arg0");
648            RequiresCanRead(arg1, "arg1");
649            RequiresCanRead(arg2, "arg2");
650            RequiresCanRead(arg3, "arg3");
651            RequiresCanRead(arg4, "arg4");
652
653            return new Block5(arg0, arg1, arg2, arg3, arg4);
654        }
655
656        /// <summary>
657        /// Creates a <see cref="BlockExpression"/> that contains the given expressions and has no variables.
658        /// </summary>
659        /// <param name="expressions">The expressions in the block.</param>
660        /// <returns>The created <see cref="BlockExpression"/>.</returns>
661        public static BlockExpression Block(params Expression[] expressions) {
662            ContractUtils.RequiresNotNull(expressions, "expressions");
663
664            switch (expressions.Length) {
665                case 2: return Block(expressions[0], expressions[1]);
666                case 3: return Block(expressions[0], expressions[1], expressions[2]);
667                case 4: return Block(expressions[0], expressions[1], expressions[2], expressions[3]);
668                case 5: return Block(expressions[0], expressions[1], expressions[2], expressions[3], expressions[4]);
669                default:
670                    ContractUtils.RequiresNotEmpty(expressions, "expressions");
671                    RequiresCanRead(expressions, "expressions");
672                    return new BlockN(expressions.Copy());
673            }
674        }
675
676        /// <summary>
677        /// Creates a <see cref="BlockExpression"/> that contains the given expressions and has no variables.
678        /// </summary>
679        /// <param name="expressions">The expressions in the block.</param>
680        /// <returns>The created <see cref="BlockExpression"/>.</returns>
681        public static BlockExpression Block(IEnumerable<Expression> expressions) {
682            return Block(EmptyReadOnlyCollection<ParameterExpression>.Instance, expressions);
683        }
684
685        /// <summary>
686        /// Creates a <see cref="BlockExpression"/> that contains the given expressions, has no variables and has specific result type.
687        /// </summary>
688        /// <param name="type">The result type of the block.</param>
689        /// <param name="expressions">The expressions in the block.</param>
690        /// <returns>The created <see cref="BlockExpression"/>.</returns>
691        public static BlockExpression Block(Type type, params Expression[] expressions) {
692            ContractUtils.RequiresNotNull(expressions, "expressions");
693            return Block(type, (IEnumerable<Expression>)expressions);
694        }
695
696        /// <summary>
697        /// Creates a <see cref="BlockExpression"/> that contains the given expressions, has no variables and has specific result type.
698        /// </summary>
699        /// <param name="type">The result type of the block.</param>
700        /// <param name="expressions">The expressions in the block.</param>
701        /// <returns>The created <see cref="BlockExpression"/>.</returns>
702        public static BlockExpression Block(Type type, IEnumerable<Expression> expressions) {
703            return Block(type, EmptyReadOnlyCollection<ParameterExpression>.Instance, expressions);
704        }
705
706        /// <summary>
707        /// Creates a <see cref="BlockExpression"/> that contains the given variables and expressions.
708        /// </summary>
709        /// <param name="variables">The variables in the block.</param>
710        /// <param name="expressions">The expressions in the block.</param>
711        /// <returns>The created <see cref="BlockExpression"/>.</returns>
712        public static BlockExpression Block(IEnumerable<ParameterExpression> variables, params Expression[] expressions) {
713            return Block(variables, (IEnumerable<Expression>)expressions);
714        }
715
716        /// <summary>
717        /// Creates a <see cref="BlockExpression"/> that contains the given variables and expressions.
718        /// </summary>
719        /// <param name="type">The result type of the block.</param>
720        /// <param name="variables">The variables in the block.</param>
721        /// <param name="expressions">The expressions in the block.</param>
722        /// <returns>The created <see cref="BlockExpression"/>.</returns>
723        public static BlockExpression Block(Type type, IEnumerable<ParameterExpression> variables, params Expression[] expressions) {
724            return Block(type, variables, (IEnumerable<Expression>)expressions);
725        }
726
727        /// <summary>
728        /// Creates a <see cref="BlockExpression"/> that contains the given variables and expressions.
729        /// </summary>
730        /// <param name="variables">The variables in the block.</param>
731        /// <param name="expressions">The expressions in the block.</param>
732        /// <returns>The created <see cref="BlockExpression"/>.</returns>
733        public static BlockExpression Block(IEnumerable<ParameterExpression> variables, IEnumerable<Expression> expressions) {
734            ContractUtils.RequiresNotNull(expressions, "expressions");
735            var expressionList = expressions.ToReadOnly();
736            ContractUtils.RequiresNotEmpty(expressionList, "expressions");
737            RequiresCanRead(expressionList, "expressions");
738
739            return Block(expressionList.Last().Type, variables, expressionList);
740        }
741
742        /// <summary>
743        /// Creates a <see cref="BlockExpression"/> that contains the given variables and expressions.
744        /// </summary>
745        /// <param name="type">The result type of the block.</param>
746        /// <param name="variables">The variables in the block.</param>
747        /// <param name="expressions">The expressions in the block.</param>
748        /// <returns>The created <see cref="BlockExpression"/>.</returns>
749        public static BlockExpression Block(Type type, IEnumerable<ParameterExpression> variables, IEnumerable<Expression> expressions) {
750            ContractUtils.RequiresNotNull(type, "type");
751            ContractUtils.RequiresNotNull(expressions, "expressions");
752
753            var expressionList = expressions.ToReadOnly();
754            var variableList = variables.ToReadOnly();
755
756            ContractUtils.RequiresNotEmpty(expressionList, "expressions");
757            RequiresCanRead(expressionList, "expressions");
758            ValidateVariables(variableList, "variables");
759
760            Expression last = expressionList.Last();
761            if (type != typeof(void)) {
762                if (!TypeUtils.AreReferenceAssignable(type, last.Type)) {
763                    throw Error.ArgumentTypesMustMatch();
764                }
765            }
766
767            if (type != last.Type) {
768                return new ScopeWithType(variableList, expressionList, type);
769            } else {
770                if (expressionList.Count == 1) {
771                    return new Scope1(variableList, expressionList[0]);
772                } else {
773                    return new ScopeN(variableList, expressionList);
774                }
775            }
776        }
777
778        // Checks that all variables are non-null, not byref, and unique.
779        internal static void ValidateVariables(ReadOnlyCollection<ParameterExpression> varList, string collectionName) {
780            if (varList.Count == 0) {
781                return;
782            }
783
784            int count = varList.Count;
785            var set = new Set<ParameterExpression>(count);
786            for (int i = 0; i < count; i++) {
787                ParameterExpression v = varList[i];
788                if (v == null) {
789                    throw new ArgumentNullException(string.Format(System.Globalization.CultureInfo.CurrentCulture, "{0}[{1}]", collectionName, set.Count));
790                }
791                if (v.IsByRef) {
792                    throw Error.VariableMustNotBeByRef(v, v.Type);
793                }
794                if (set.Contains(v)) {
795                    throw Error.DuplicateVariable(v);
796                }
797                set.Add(v);
798            }
799        }
800    }
801}