BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / ExpressionVisitor.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.ObjectModel;
18 using System.Diagnostics;
19 using System.Dynamic.Utils;
20 using System.Runtime.CompilerServices;
21
22 #if SILVERLIGHT
23 using System.Core;
24 #endif
25
26 #if CLR2
27 namespace Microsoft.Scripting.Ast {
28     using Microsoft.Scripting.Utils;
29 #else
30 namespace System.Linq.Expressions {
31 #endif
32
33     /// <summary>
34     /// Represents a visitor or rewriter for expression trees.
35     /// </summary>
36     /// <remarks>
37     /// This class is designed to be inherited to create more specialized
38     /// classes whose functionality requires traversing, examining or copying
39     /// an expression tree.
40     /// </remarks>
41     public abstract class ExpressionVisitor {
42
43         /// <summary>
44         /// Initializes a new instance of <see cref="ExpressionVisitor"/>.
45         /// </summary>
46         protected ExpressionVisitor() {
47         }
48
49         /// <summary>
50         /// Dispatches the expression to one of the more specialized visit methods in this class.
51         /// </summary>
52         /// <param name="node">The expression to visit.</param>
53         /// <returns>The modified expression, if it or any subexpression was modified;
54         /// otherwise, returns the original expression.</returns>
55         public virtual Expression Visit(Expression node) {
56             if (node != null) {
57                 return node.Accept(this);
58             }
59             return null;
60         }
61
62         /// <summary>
63         /// Dispatches the list of expressions to one of the more specialized visit methods in this class.
64         /// </summary>
65         /// <param name="nodes">The expressions to visit.</param>
66         /// <returns>The modified expression list, if any of the elements were modified;
67         /// otherwise, returns the original expression list.</returns>
68         public ReadOnlyCollection<Expression> Visit(ReadOnlyCollection<Expression> nodes) {
69             Expression[] newNodes = null;
70             for (int i = 0, n = nodes.Count; i < n; i++) {
71                 Expression node = Visit(nodes[i]);
72
73                 if (newNodes != null) {
74                     newNodes[i] = node;
75                 } else if (!object.ReferenceEquals(node, nodes[i])) {
76                     newNodes = new Expression[n];
77                     for (int j = 0; j < i; j++) {
78                         newNodes[j] = nodes[j];
79                     }
80                     newNodes[i] = node;
81                 }
82             }
83             if (newNodes == null) {
84                 return nodes;
85             }
86             return new TrueReadOnlyCollection<Expression>(newNodes);
87         }
88
89         internal Expression[] VisitArguments(IArgumentProvider nodes) {
90             Expression[] newNodes = null;
91             for (int i = 0, n = nodes.ArgumentCount; i < n; i++) {
92                 Expression curNode = nodes.GetArgument(i);
93                 Expression node = Visit(curNode);
94
95                 if (newNodes != null) {
96                     newNodes[i] = node;
97                 } else if (!object.ReferenceEquals(node, curNode)) {
98                     newNodes = new Expression[n];
99                     for (int j = 0; j < i; j++) {
100                         newNodes[j] = nodes.GetArgument(j);
101                     }
102                     newNodes[i] = node;
103                 }
104             }
105             return newNodes;
106         }
107
108         /// <summary>
109         /// Visits all nodes in the collection using a specified element visitor.
110         /// </summary>
111         /// <typeparam name="T">The type of the nodes.</typeparam>
112         /// <param name="nodes">The nodes to visit.</param>
113         /// <param name="elementVisitor">A delegate that visits a single element,
114         /// optionally replacing it with a new element.</param>
115         /// <returns>The modified node list, if any of the elements were modified;
116         /// otherwise, returns the original node list.</returns>
117         public static ReadOnlyCollection<T> Visit<T>(ReadOnlyCollection<T> nodes, Func<T, T> elementVisitor) {
118             T[] newNodes = null;
119             for (int i = 0, n = nodes.Count; i < n; i++) {
120                 T node = elementVisitor(nodes[i]);
121                 if (newNodes != null) {
122                     newNodes[i] = node;
123                 } else if (!object.ReferenceEquals(node, nodes[i])) {
124                     newNodes = new T[n];
125                     for (int j = 0; j < i; j++) {
126                         newNodes[j] = nodes[j];
127                     }
128                     newNodes[i] = node;
129                 }
130             }
131             if (newNodes == null) {
132                 return nodes;
133             }
134             return new TrueReadOnlyCollection<T>(newNodes);
135         }
136
137         /// <summary>
138         /// Visits an expression, casting the result back to the original expression type.
139         /// </summary>
140         /// <typeparam name="T">The type of the expression.</typeparam>
141         /// <param name="node">The expression to visit.</param>
142         /// <param name="callerName">The name of the calling method; used to report to report a better error message.</param>
143         /// <returns>The modified expression, if it or any subexpression was modified;
144         /// otherwise, returns the original expression.</returns>
145         /// <exception cref="InvalidOperationException">The visit method for this node returned a different type.</exception>
146         public T VisitAndConvert<T>(T node, string callerName) where T : Expression {
147             if (node == null) {
148                 return null;
149             }
150             node = Visit(node) as T;
151             if (node == null) {
152                 throw Error.MustRewriteToSameNode(callerName, typeof(T), callerName);
153             }
154             return node;
155         }
156
157         /// <summary>
158         /// Visits an expression, casting the result back to the original expression type.
159         /// </summary>
160         /// <typeparam name="T">The type of the expression.</typeparam>
161         /// <param name="nodes">The expression to visit.</param>
162         /// <param name="callerName">The name of the calling method; used to report to report a better error message.</param>
163         /// <returns>The modified expression, if it or any subexpression was modified;
164         /// otherwise, returns the original expression.</returns>
165         /// <exception cref="InvalidOperationException">The visit method for this node returned a different type.</exception>
166         public ReadOnlyCollection<T> VisitAndConvert<T>(ReadOnlyCollection<T> nodes, string callerName) where T : Expression {
167             T[] newNodes = null;
168             for (int i = 0, n = nodes.Count; i < n; i++) {
169                 T node = Visit(nodes[i]) as T;
170                 if (node == null) {
171                     throw Error.MustRewriteToSameNode(callerName, typeof(T), callerName);
172                 }
173
174                 if (newNodes != null) {
175                     newNodes[i] = node;
176                 } else if (!object.ReferenceEquals(node, nodes[i])) {
177                     newNodes = new T[n];
178                     for (int j = 0; j < i; j++) {
179                         newNodes[j] = nodes[j];
180                     }
181                     newNodes[i] = node;
182                 }
183             }
184             if (newNodes == null) {
185                 return nodes;
186             }
187             return new TrueReadOnlyCollection<T>(newNodes);
188         }
189
190         /// <summary>
191         /// Visits the children of the <see cref="BinaryExpression" />.
192         /// </summary>
193         /// <param name="node">The expression to visit.</param>
194         /// <returns>The modified expression, if it or any subexpression was modified;
195         /// otherwise, returns the original expression.</returns>
196         protected internal virtual Expression VisitBinary(BinaryExpression node) {
197             // Walk children in evaluation order: left, conversion, right
198             return ValidateBinary(
199                 node,
200                 node.Update(
201                     Visit(node.Left),
202                     VisitAndConvert(node.Conversion, "VisitBinary"),
203                     Visit(node.Right)
204                 )
205             );
206         }
207
208         /// <summary>
209         /// Visits the children of the <see cref="BlockExpression" />.
210         /// </summary>
211         /// <param name="node">The expression to visit.</param>
212         /// <returns>The modified expression, if it or any subexpression was modified;
213         /// otherwise, returns the original expression.</returns>
214         protected internal virtual Expression VisitBlock(BlockExpression node) {
215             int count = node.ExpressionCount;
216             Expression[] nodes = null;
217             for (int i = 0; i < count; i++) {
218                 Expression oldNode = node.GetExpression(i);
219                 Expression newNode = Visit(oldNode);
220
221                 if (oldNode != newNode) {
222                     if (nodes == null) {
223                         nodes = new Expression[count];
224                     }
225                     nodes[i] = newNode;
226                 }
227             }
228             var v = VisitAndConvert(node.Variables, "VisitBlock");
229
230             if (v == node.Variables && nodes == null) {
231                 return node;
232             } else {
233                 for (int i = 0; i < count; i++) {
234                     if (nodes[i] == null) {
235                         nodes[i] = node.GetExpression(i);
236                     }
237                 }
238             }
239
240             return node.Rewrite(v, nodes);
241         }
242
243         /// <summary>
244         /// Visits the children of the <see cref="ConditionalExpression" />.
245         /// </summary>
246         /// <param name="node">The expression to visit.</param>
247         /// <returns>The modified expression, if it or any subexpression was modified;
248         /// otherwise, returns the original expression.</returns>
249         protected internal virtual Expression VisitConditional(ConditionalExpression node) {
250             return node.Update(Visit(node.Test), Visit(node.IfTrue), Visit(node.IfFalse));
251         }
252
253         /// <summary>
254         /// Visits the <see cref="ConstantExpression" />.
255         /// </summary>
256         /// <param name="node">The expression to visit.</param>
257         /// <returns>The modified expression, if it or any subexpression was modified;
258         /// otherwise, returns the original expression.</returns>
259         protected internal virtual Expression VisitConstant(ConstantExpression node) {
260             return node;
261         }
262
263         /// <summary>
264         /// Visits the <see cref="DebugInfoExpression" />.
265         /// </summary>
266         /// <param name="node">The expression to visit.</param>
267         /// <returns>The modified expression, if it or any subexpression was modified;
268         /// otherwise, returns the original expression.</returns>
269         protected internal virtual Expression VisitDebugInfo(DebugInfoExpression node) {
270             return node;
271         }
272
273         /// <summary>
274         /// Visits the children of the <see cref="DynamicExpression" />.
275         /// </summary>
276         /// <param name="node">The expression to visit.</param>
277         /// <returns>The modified expression, if it or any subexpression was modified;
278         /// otherwise, returns the original expression.</returns>
279         protected internal virtual Expression VisitDynamic(DynamicExpression node) {
280             Expression[] a = VisitArguments((IArgumentProvider)node);
281             if (a == null) {
282                 return node;
283             }
284
285             return node.Rewrite(a);
286         }
287
288         /// <summary>
289         /// Visits the <see cref="DefaultExpression" />.
290         /// </summary>
291         /// <param name="node">The expression to visit.</param>
292         /// <returns>The modified expression, if it or any subexpression was modified;
293         /// otherwise, returns the original expression.</returns>
294         protected internal virtual Expression VisitDefault(DefaultExpression node) {
295             return node;
296         }
297
298         /// <summary>
299         /// Visits the children of the extension expression.
300         /// </summary>
301         /// <param name="node">The expression to visit.</param>
302         /// <returns>The modified expression, if it or any subexpression was modified;
303         /// otherwise, returns the original expression.</returns>
304         /// <remarks>
305         /// This can be overridden to visit or rewrite specific extension nodes.
306         /// If it is not overridden, this method will call <see cref="Expression.VisitChildren" />,
307         /// which gives the node a chance to walk its children. By default,
308         /// <see cref="Expression.VisitChildren" /> will try to reduce the node.
309         /// </remarks>
310         protected internal virtual Expression VisitExtension(Expression node) {
311             return node.VisitChildren(this);
312         }
313
314         /// <summary>
315         /// Visits the children of the <see cref="GotoExpression" />.
316         /// </summary>
317         /// <param name="node">The expression to visit.</param>
318         /// <returns>The modified expression, if it or any subexpression was modified;
319         /// otherwise, returns the original expression.</returns>
320         protected internal virtual Expression VisitGoto(GotoExpression node) {
321             return node.Update(VisitLabelTarget(node.Target), Visit(node.Value));
322         }
323
324         /// <summary>
325         /// Visits the children of the <see cref="InvocationExpression" />.
326         /// </summary>
327         /// <param name="node">The expression to visit.</param>
328         /// <returns>The modified expression, if it or any subexpression was modified;
329         /// otherwise, returns the original expression.</returns>
330         protected internal virtual Expression VisitInvocation(InvocationExpression node) {
331             Expression e = Visit(node.Expression);
332             Expression[] a = VisitArguments(node);
333             if (e == node.Expression && a == null) {
334                 return node;
335             }
336
337             return node.Rewrite(e, a);
338         }
339
340         /// <summary>
341         /// Visits the <see cref="LabelTarget" />.
342         /// </summary>
343         /// <param name="node">The expression to visit.</param>
344         /// <returns>The modified expression, if it or any subexpression was modified;
345         /// otherwise, returns the original expression.</returns>
346         protected virtual LabelTarget VisitLabelTarget(LabelTarget node) {
347             return node;
348         }
349
350         /// <summary>
351         /// Visits the children of the <see cref="LabelExpression" />.
352         /// </summary>
353         /// <param name="node">The expression to visit.</param>
354         /// <returns>The modified expression, if it or any subexpression was modified;
355         /// otherwise, returns the original expression.</returns>
356         protected internal virtual Expression VisitLabel(LabelExpression node) {
357             return node.Update(VisitLabelTarget(node.Target), Visit(node.DefaultValue));
358         }
359
360         /// <summary>
361         /// Visits the children of the <see cref="Expression&lt;T&gt;" />.
362         /// </summary>
363         /// <typeparam name="T">The type of the delegate.</typeparam>
364         /// <param name="node">The expression to visit.</param>
365         /// <returns>The modified expression, if it or any subexpression was modified;
366         /// otherwise, returns the original expression.</returns>
367         protected internal virtual Expression VisitLambda<T>(Expression<T> node) {
368             return node.Update(Visit(node.Body), VisitAndConvert(node.Parameters, "VisitLambda"));
369         }
370
371         /// <summary>
372         /// Visits the children of the <see cref="LoopExpression" />.
373         /// </summary>
374         /// <param name="node">The expression to visit.</param>
375         /// <returns>The modified expression, if it or any subexpression was modified;
376         /// otherwise, returns the original expression.</returns>
377         protected internal virtual Expression VisitLoop(LoopExpression node) {
378             return node.Update(VisitLabelTarget(node.BreakLabel), VisitLabelTarget(node.ContinueLabel), Visit(node.Body));
379         }
380
381         /// <summary>
382         /// Visits the children of the <see cref="MemberExpression" />.
383         /// </summary>
384         /// <param name="node">The expression to visit.</param>
385         /// <returns>The modified expression, if it or any subexpression was modified;
386         /// otherwise, returns the original expression.</returns>
387         protected internal virtual Expression VisitMember(MemberExpression node) {
388             return node.Update(Visit(node.Expression));
389         }
390
391         /// <summary>
392         /// Visits the children of the <see cref="IndexExpression" />.
393         /// </summary>
394         /// <param name="node">The expression to visit.</param>
395         /// <returns>The modified expression, if it or any subexpression was modified;
396         /// otherwise, returns the original expression.</returns>
397         protected internal virtual Expression VisitIndex(IndexExpression node) {
398             Expression o = Visit(node.Object);
399             Expression[] a = VisitArguments(node);
400             if (o == node.Object && a == null) {
401                 return node;
402             }
403
404             return node.Rewrite(o, a);
405         }
406
407         /// <summary>
408         /// Visits the children of the <see cref="MethodCallExpression" />.
409         /// </summary>
410         /// <param name="node">The expression to visit.</param>
411         /// <returns>The modified expression, if it or any subexpression was modified;
412         /// otherwise, returns the original expression.</returns>
413         protected internal virtual Expression VisitMethodCall(MethodCallExpression node) {
414             Expression o = Visit(node.Object);
415             Expression[] a = VisitArguments((IArgumentProvider)node);
416             if (o == node.Object && a == null) {
417                 return node;
418             }
419
420             return node.Rewrite(o, a);
421         }
422
423         /// <summary>
424         /// Visits the children of the <see cref="NewArrayExpression" />.
425         /// </summary>
426         /// <param name="node">The expression to visit.</param>
427         /// <returns>The modified expression, if it or any subexpression was modified;
428         /// otherwise, returns the original expression.</returns>
429         protected internal virtual Expression VisitNewArray(NewArrayExpression node) {
430             return node.Update(Visit(node.Expressions));
431         }
432
433         /// <summary>
434         /// Visits the children of the <see cref="NewExpression" />.
435         /// </summary>
436         /// <param name="node">The expression to visit.</param>
437         /// <returns>The modified expression, if it or any subexpression was modified;
438         /// otherwise, returns the original expression.</returns>
439         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
440         protected internal virtual Expression VisitNew(NewExpression node) {
441             return node.Update(Visit(node.Arguments));
442         }
443
444         /// <summary>
445         /// Visits the <see cref="ParameterExpression" />.
446         /// </summary>
447         /// <param name="node">The expression to visit.</param>
448         /// <returns>The modified expression, if it or any subexpression was modified;
449         /// otherwise, returns the original expression.</returns>
450         protected internal virtual Expression VisitParameter(ParameterExpression node) {
451             return node;
452         }
453
454         /// <summary>
455         /// Visits the children of the <see cref="RuntimeVariablesExpression" />.
456         /// </summary>
457         /// <param name="node">The expression to visit.</param>
458         /// <returns>The modified expression, if it or any subexpression was modified;
459         /// otherwise, returns the original expression.</returns>
460         protected internal virtual Expression VisitRuntimeVariables(RuntimeVariablesExpression node) {
461             return node.Update(VisitAndConvert(node.Variables, "VisitRuntimeVariables"));
462         }
463
464         /// <summary>
465         /// Visits the children of the <see cref="SwitchCase" />.
466         /// </summary>
467         /// <param name="node">The expression to visit.</param>
468         /// <returns>The modified expression, if it or any subexpression was modified;
469         /// otherwise, returns the original expression.</returns>
470         protected virtual SwitchCase VisitSwitchCase(SwitchCase node) {
471             return node.Update(Visit(node.TestValues), Visit(node.Body));
472         }
473
474         /// <summary>
475         /// Visits the children of the <see cref="SwitchExpression" />.
476         /// </summary>
477         /// <param name="node">The expression to visit.</param>
478         /// <returns>The modified expression, if it or any subexpression was modified;
479         /// otherwise, returns the original expression.</returns>
480         protected internal virtual Expression VisitSwitch(SwitchExpression node) {
481             return ValidateSwitch(
482                 node,
483                 node.Update(
484                     Visit(node.SwitchValue),
485                     Visit(node.Cases, VisitSwitchCase),
486                     Visit(node.DefaultBody)
487                 )
488             );
489         }
490
491         /// <summary>
492         /// Visits the children of the <see cref="CatchBlock" />.
493         /// </summary>
494         /// <param name="node">The expression to visit.</param>
495         /// <returns>The modified expression, if it or any subexpression was modified;
496         /// otherwise, returns the original expression.</returns>
497         protected virtual CatchBlock VisitCatchBlock(CatchBlock node) {
498             return node.Update(VisitAndConvert(node.Variable, "VisitCatchBlock"), Visit(node.Filter), Visit(node.Body));
499         }
500
501         /// <summary>
502         /// Visits the children of the <see cref="TryExpression" />.
503         /// </summary>
504         /// <param name="node">The expression to visit.</param>
505         /// <returns>The modified expression, if it or any subexpression was modified;
506         /// otherwise, returns the original expression.</returns>
507         protected internal virtual Expression VisitTry(TryExpression node) {
508             return node.Update(
509                 Visit(node.Body),
510                 Visit(node.Handlers, VisitCatchBlock),
511                 Visit(node.Finally),
512                 Visit(node.Fault)
513             );
514         }
515
516         /// <summary>
517         /// Visits the children of the <see cref="TypeBinaryExpression" />.
518         /// </summary>
519         /// <param name="node">The expression to visit.</param>
520         /// <returns>The modified expression, if it or any subexpression was modified;
521         /// otherwise, returns the original expression.</returns>
522         protected internal virtual Expression VisitTypeBinary(TypeBinaryExpression node) {
523             return node.Update(Visit(node.Expression));
524         }
525
526         /// <summary>
527         /// Visits the children of the <see cref="UnaryExpression" />.
528         /// </summary>
529         /// <param name="node">The expression to visit.</param>
530         /// <returns>The modified expression, if it or any subexpression was modified;
531         /// otherwise, returns the original expression.</returns>
532         protected internal virtual Expression VisitUnary(UnaryExpression node) {
533             return ValidateUnary(node, node.Update(Visit(node.Operand)));
534         }
535
536         /// <summary>
537         /// Visits the children of the <see cref="MemberInitExpression" />.
538         /// </summary>
539         /// <param name="node">The expression to visit.</param>
540         /// <returns>The modified expression, if it or any subexpression was modified;
541         /// otherwise, returns the original expression.</returns>
542         protected internal virtual Expression VisitMemberInit(MemberInitExpression node) {
543             return node.Update(
544                 VisitAndConvert(node.NewExpression, "VisitMemberInit"),
545                 Visit(node.Bindings, VisitMemberBinding)
546             );
547         }
548
549         /// <summary>
550         /// Visits the children of the <see cref="ListInitExpression" />.
551         /// </summary>
552         /// <param name="node">The expression to visit.</param>
553         /// <returns>The modified expression, if it or any subexpression was modified;
554         /// otherwise, returns the original expression.</returns>
555         protected internal virtual Expression VisitListInit(ListInitExpression node) {
556             return node.Update(
557                 VisitAndConvert(node.NewExpression, "VisitListInit"),
558                 Visit(node.Initializers, VisitElementInit)
559             );
560         }
561
562         /// <summary>
563         /// Visits the children of the <see cref="ElementInit" />.
564         /// </summary>
565         /// <param name="node">The expression to visit.</param>
566         /// <returns>The modified expression, if it or any subexpression was modified;
567         /// otherwise, returns the original expression.</returns>
568         protected virtual ElementInit VisitElementInit(ElementInit node) {
569             return node.Update(Visit(node.Arguments));
570         }
571
572         /// <summary>
573         /// Visits the children of the <see cref="MemberBinding" />.
574         /// </summary>
575         /// <param name="node">The expression to visit.</param>
576         /// <returns>The modified expression, if it or any subexpression was modified;
577         /// otherwise, returns the original expression.</returns>
578         protected virtual MemberBinding VisitMemberBinding(MemberBinding node) {
579             switch (node.BindingType) {
580                 case MemberBindingType.Assignment:
581                     return VisitMemberAssignment((MemberAssignment)node);
582                 case MemberBindingType.MemberBinding:
583                     return VisitMemberMemberBinding((MemberMemberBinding)node);
584                 case MemberBindingType.ListBinding:
585                     return VisitMemberListBinding((MemberListBinding)node);
586                 default:
587                     throw Error.UnhandledBindingType(node.BindingType);
588             }
589         }
590
591         /// <summary>
592         /// Visits the children of the <see cref="MemberAssignment" />.
593         /// </summary>
594         /// <param name="node">The expression to visit.</param>
595         /// <returns>The modified expression, if it or any subexpression was modified;
596         /// otherwise, returns the original expression.</returns>
597         protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment node) {
598             return node.Update(Visit(node.Expression));
599         }
600
601         /// <summary>
602         /// Visits the children of the <see cref="MemberMemberBinding" />.
603         /// </summary>
604         /// <param name="node">The expression to visit.</param>
605         /// <returns>The modified expression, if it or any subexpression was modified;
606         /// otherwise, returns the original expression.</returns>
607         protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding node) {
608             return node.Update(Visit(node.Bindings, VisitMemberBinding));
609         }
610
611         /// <summary>
612         /// Visits the children of the <see cref="MemberListBinding" />.
613         /// </summary>
614         /// <param name="node">The expression to visit.</param>
615         /// <returns>The modified expression, if it or any subexpression was modified;
616         /// otherwise, returns the original expression.</returns>
617         protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding node) {
618             return node.Update(Visit(node.Initializers, VisitElementInit));
619         }
620
621
622         //
623         // Prevent some common cases of invalid rewrites.
624         //
625         // Essentially, we don't want the rewritten node to be semantically
626         // bound by the factory, which may do the wrong thing. Instead we
627         // require derived classes to be explicit about what they want to do if
628         // types change.
629         //
630         private static UnaryExpression ValidateUnary(UnaryExpression before, UnaryExpression after) {
631             if (before != after && before.Method == null) {
632                 if (after.Method != null) {
633                     throw Error.MustRewriteWithoutMethod(after.Method, "VisitUnary");
634                 }
635
636                 // rethrow has null operand
637                 if (before.Operand != null && after.Operand != null) {
638                     ValidateChildType(before.Operand.Type, after.Operand.Type, "VisitUnary");
639                 }
640             }
641             return after;
642         }
643
644         private static BinaryExpression ValidateBinary(BinaryExpression before, BinaryExpression after) {
645             if (before != after && before.Method == null) {
646                 if (after.Method != null) {
647                     throw Error.MustRewriteWithoutMethod(after.Method, "VisitBinary");
648                 }
649
650                 ValidateChildType(before.Left.Type, after.Left.Type, "VisitBinary");
651                 ValidateChildType(before.Right.Type, after.Right.Type, "VisitBinary");
652             }
653             return after;
654         }
655
656         // We wouldn't need this if switch didn't infer the method.
657         private static SwitchExpression ValidateSwitch(SwitchExpression before, SwitchExpression after) {
658             // If we did not have a method, we don't want to bind to one,
659             // it might not be the right thing.
660             if (before.Comparison == null && after.Comparison != null) {
661                 throw Error.MustRewriteWithoutMethod(after.Comparison, "VisitSwitch");
662             }
663             return after;
664         }
665
666         // Value types must stay as the same type, otherwise it's now a
667         // different operation, e.g. adding two doubles vs adding two ints.
668         private static void ValidateChildType(Type before, Type after, string methodName) {
669             if (before.IsValueType) {
670                 if (TypeUtils.AreEquivalent(before, after)) {
671                     // types are the same value type
672                     return;
673                 }
674             } else if (!after.IsValueType) {
675                 // both are reference types
676                 return;
677             }
678
679             // Otherwise, it's an invalid type change.
680             throw Error.MustRewriteChildToSameType(before, after, methodName);
681         }
682     }
683 }