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