1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Collections.Generic;
7 using System.Diagnostics;
8 using System.Diagnostics.CodeAnalysis;
9 using System.Linq.Expressions;
10 using System.Reflection;
11 using Microsoft.CSharp.RuntimeBinder.Semantics;
12 
13 namespace Microsoft.CSharp.RuntimeBinder
14 {
15     internal sealed class ExpressionTreeCallRewriter : ExprVisitorBase
16     {
17         /////////////////////////////////////////////////////////////////////////////////
18         // Members
19 
20         private sealed class ExpressionExpr : Expr
21         {
22             public readonly Expression Expression;
ExpressionExpr(Expression e)23             public ExpressionExpr(Expression e)
24                 : base(0)
25             {
26                 Expression = e;
27             }
28         }
29 
30         private readonly Dictionary<ExprCall, Expression> _DictionaryOfParameters;
31         private readonly Expression[] _ListOfParameters;
32         private readonly TypeManager _typeManager;
33         // Counts how many EXPRSAVEs we've encountered so we know which index into the
34         // parameter list we should be taking.
35         private int _currentParameterIndex;
36 
37         /////////////////////////////////////////////////////////////////////////////////
38 
ExpressionTreeCallRewriter(TypeManager typeManager, Expression[] listOfParameters)39         private ExpressionTreeCallRewriter(TypeManager typeManager, Expression[] listOfParameters)
40         {
41             _typeManager = typeManager;
42             _DictionaryOfParameters = new Dictionary<ExprCall, Expression>();
43             _ListOfParameters = listOfParameters;
44         }
45 
46         /////////////////////////////////////////////////////////////////////////////////
47 
Rewrite(TypeManager typeManager, ExprBinOp binOp, Expression[] listOfParameters)48         public static Expression Rewrite(TypeManager typeManager, ExprBinOp binOp, Expression[] listOfParameters)
49         {
50             ExpressionTreeCallRewriter rewriter = new ExpressionTreeCallRewriter(typeManager, listOfParameters);
51 
52             // We should have a ExprBinOp that's an EK_SEQUENCE. The RHS of our sequence
53             // should be a call to PM_EXPRESSION_LAMBDA. The LHS of our sequence is the
54             // set of declarations for the parameters that we'll need.
55             // Assert all of these first, and then unwrap them.
56 
57             Debug.Assert(binOp != null);
58             Debug.Assert(binOp.Kind == ExpressionKind.Sequence);
59             Debug.Assert(binOp.OptionalRightChild is ExprCall);
60             Debug.Assert(((ExprCall)binOp.OptionalRightChild).PredefinedMethod == PREDEFMETH.PM_EXPRESSION_LAMBDA);
61             Debug.Assert(binOp.OptionalLeftChild != null);
62 
63             // Visit the left to generate the parameter construction.
64             rewriter.Visit(binOp.OptionalLeftChild);
65             ExprCall call = (ExprCall)binOp.OptionalRightChild;
66 
67             ExpressionExpr e = rewriter.Visit(call) as ExpressionExpr;
68             return e.Expression;
69         }
70 
71         /////////////////////////////////////////////////////////////////////////////////
72 
VisitSAVE(ExprBinOp pExpr)73         protected override Expr VisitSAVE(ExprBinOp pExpr)
74         {
75             // Saves should have a LHS that is a CALL to PM_EXPRESSION_PARAMETER
76             // and a RHS that is a WRAP of that call.
77             ExprCall call = (ExprCall)pExpr.OptionalLeftChild;
78             Debug.Assert(call?.PredefinedMethod == PREDEFMETH.PM_EXPRESSION_PARAMETER);
79             Debug.Assert(pExpr.OptionalRightChild is ExprWrap);
80 
81             Expression parameter = _ListOfParameters[_currentParameterIndex++];
82             _DictionaryOfParameters.Add(call, parameter);
83 
84             return null;
85         }
86 
87         /////////////////////////////////////////////////////////////////////////////////
88 
VisitCALL(ExprCall pExpr)89         protected override Expr VisitCALL(ExprCall pExpr)
90         {
91             if (pExpr.PredefinedMethod == PREDEFMETH.PM_COUNT)
92             {
93                 return pExpr;
94             }
95 
96             Expression exp;
97             switch (pExpr.PredefinedMethod)
98             {
99                 case PREDEFMETH.PM_EXPRESSION_LAMBDA:
100                     return GenerateLambda(pExpr);
101 
102                 case PREDEFMETH.PM_EXPRESSION_CALL:
103                     exp = GenerateCall(pExpr);
104                     break;
105 
106                 case PREDEFMETH.PM_EXPRESSION_ARRAYINDEX:
107                 case PREDEFMETH.PM_EXPRESSION_ARRAYINDEX2:
108                     exp = GenerateArrayIndex(pExpr);
109                     break;
110 
111                 case PREDEFMETH.PM_EXPRESSION_CONVERT:
112                 case PREDEFMETH.PM_EXPRESSION_CONVERT_USER_DEFINED:
113                 case PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED:
114                 case PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED_USER_DEFINED:
115                     exp = GenerateConvert(pExpr);
116                     break;
117 
118                 case PREDEFMETH.PM_EXPRESSION_PROPERTY:
119                     exp = GenerateProperty(pExpr);
120                     break;
121 
122                 case PREDEFMETH.PM_EXPRESSION_FIELD:
123                     exp = GenerateField(pExpr);
124                     break;
125 
126                 case PREDEFMETH.PM_EXPRESSION_INVOKE:
127                     exp = GenerateInvoke(pExpr);
128                     break;
129 
130                 case PREDEFMETH.PM_EXPRESSION_NEW:
131                     exp = GenerateNew(pExpr);
132                     break;
133 
134                 case PREDEFMETH.PM_EXPRESSION_ADD:
135                 case PREDEFMETH.PM_EXPRESSION_AND:
136                 case PREDEFMETH.PM_EXPRESSION_DIVIDE:
137                 case PREDEFMETH.PM_EXPRESSION_EQUAL:
138                 case PREDEFMETH.PM_EXPRESSION_EXCLUSIVEOR:
139                 case PREDEFMETH.PM_EXPRESSION_GREATERTHAN:
140                 case PREDEFMETH.PM_EXPRESSION_GREATERTHANOREQUAL:
141                 case PREDEFMETH.PM_EXPRESSION_LEFTSHIFT:
142                 case PREDEFMETH.PM_EXPRESSION_LESSTHAN:
143                 case PREDEFMETH.PM_EXPRESSION_LESSTHANOREQUAL:
144                 case PREDEFMETH.PM_EXPRESSION_MODULO:
145                 case PREDEFMETH.PM_EXPRESSION_MULTIPLY:
146                 case PREDEFMETH.PM_EXPRESSION_NOTEQUAL:
147                 case PREDEFMETH.PM_EXPRESSION_OR:
148                 case PREDEFMETH.PM_EXPRESSION_RIGHTSHIFT:
149                 case PREDEFMETH.PM_EXPRESSION_SUBTRACT:
150                 case PREDEFMETH.PM_EXPRESSION_ORELSE:
151                 case PREDEFMETH.PM_EXPRESSION_ANDALSO:
152                 // Checked
153                 case PREDEFMETH.PM_EXPRESSION_ADDCHECKED:
154                 case PREDEFMETH.PM_EXPRESSION_MULTIPLYCHECKED:
155                 case PREDEFMETH.PM_EXPRESSION_SUBTRACTCHECKED:
156                     exp = GenerateBinaryOperator(pExpr);
157                     break;
158 
159                 case PREDEFMETH.PM_EXPRESSION_ADD_USER_DEFINED:
160                 case PREDEFMETH.PM_EXPRESSION_AND_USER_DEFINED:
161                 case PREDEFMETH.PM_EXPRESSION_DIVIDE_USER_DEFINED:
162                 case PREDEFMETH.PM_EXPRESSION_EQUAL_USER_DEFINED:
163                 case PREDEFMETH.PM_EXPRESSION_EXCLUSIVEOR_USER_DEFINED:
164                 case PREDEFMETH.PM_EXPRESSION_GREATERTHAN_USER_DEFINED:
165                 case PREDEFMETH.PM_EXPRESSION_GREATERTHANOREQUAL_USER_DEFINED:
166                 case PREDEFMETH.PM_EXPRESSION_LEFTSHIFT_USER_DEFINED:
167                 case PREDEFMETH.PM_EXPRESSION_LESSTHAN_USER_DEFINED:
168                 case PREDEFMETH.PM_EXPRESSION_LESSTHANOREQUAL_USER_DEFINED:
169                 case PREDEFMETH.PM_EXPRESSION_MODULO_USER_DEFINED:
170                 case PREDEFMETH.PM_EXPRESSION_MULTIPLY_USER_DEFINED:
171                 case PREDEFMETH.PM_EXPRESSION_NOTEQUAL_USER_DEFINED:
172                 case PREDEFMETH.PM_EXPRESSION_OR_USER_DEFINED:
173                 case PREDEFMETH.PM_EXPRESSION_RIGHTSHIFT_USER_DEFINED:
174                 case PREDEFMETH.PM_EXPRESSION_SUBTRACT_USER_DEFINED:
175                 case PREDEFMETH.PM_EXPRESSION_ORELSE_USER_DEFINED:
176                 case PREDEFMETH.PM_EXPRESSION_ANDALSO_USER_DEFINED:
177                 // Checked
178                 case PREDEFMETH.PM_EXPRESSION_ADDCHECKED_USER_DEFINED:
179                 case PREDEFMETH.PM_EXPRESSION_MULTIPLYCHECKED_USER_DEFINED:
180                 case PREDEFMETH.PM_EXPRESSION_SUBTRACTCHECKED_USER_DEFINED:
181                     exp = GenerateUserDefinedBinaryOperator(pExpr);
182                     break;
183 
184                 case PREDEFMETH.PM_EXPRESSION_NEGATE:
185                 case PREDEFMETH.PM_EXPRESSION_NOT:
186                 case PREDEFMETH.PM_EXPRESSION_NEGATECHECKED:
187                     exp = GenerateUnaryOperator(pExpr);
188                     break;
189 
190                 case PREDEFMETH.PM_EXPRESSION_UNARYPLUS_USER_DEFINED:
191                 case PREDEFMETH.PM_EXPRESSION_NEGATE_USER_DEFINED:
192                 case PREDEFMETH.PM_EXPRESSION_NOT_USER_DEFINED:
193                 case PREDEFMETH.PM_EXPRESSION_NEGATECHECKED_USER_DEFINED:
194                     exp = GenerateUserDefinedUnaryOperator(pExpr);
195                     break;
196 
197                 case PREDEFMETH.PM_EXPRESSION_CONSTANT_OBJECT_TYPE:
198                     exp = GenerateConstantType(pExpr);
199                     break;
200 
201                 case PREDEFMETH.PM_EXPRESSION_ASSIGN:
202                     exp = GenerateAssignment(pExpr);
203                     break;
204 
205                 default:
206                     Debug.Assert(false, "Invalid Predefined Method in VisitCALL");
207                     throw Error.InternalCompilerError();
208             }
209 
210             return new ExpressionExpr(exp);
211         }
212 
213         // ExpressionTreeRewriter has optimized away identity or up-cast conversions, leaving us with a bare parameter
214         // access. Just get the expression for that parameter so the lambda produced can be p0 => p0
215         protected override Expr VisitWRAP(ExprWrap pExpr) => new ExpressionExpr(GetExpression(pExpr));
216 
217         #region Generators
218         /////////////////////////////////////////////////////////////////////////////////
219 
GenerateLambda(ExprCall pExpr)220         private Expr GenerateLambda(ExprCall pExpr)
221         {
222             // We always call Lambda(body, arrayinit) where the arrayinit
223             // is the initialization of the parameters.
224             return Visit(((ExprList)pExpr.OptionalArguments).OptionalElement);
225 
226             /*
227              * // Do we need to do this?
228             Expression e = (body as ExpressionExpr).Expression;
229             if (e.Type.IsValueType)
230             {
231                 // If we have a value type, convert it to object so that boxing
232                 // can happen.
233 
234                 e = Expression.Convert(body.Expression, typeof(object));
235             }
236              * */
237         }
238 
239         /////////////////////////////////////////////////////////////////////////////////
240 
GenerateCall(ExprCall pExpr)241         private Expression GenerateCall(ExprCall pExpr)
242         {
243             // Our arguments are: object, methodinfo, parameters.
244             // The object is either an EXPRWRAP of a CALL, or a CALL that is a PM_CONVERT, whose
245             // argument is the WRAP of a CALL. Deal with that first.
246 
247             ExprMethodInfo methinfo;
248             ExprArrayInit arrinit;
249 
250             ExprList list = (ExprList)pExpr.OptionalArguments;
251             if (list.OptionalNextListNode is ExprList next)
252             {
253                 methinfo = (ExprMethodInfo)next.OptionalElement;
254                 arrinit = (ExprArrayInit)next.OptionalNextListNode;
255             }
256             else
257             {
258                 methinfo = (ExprMethodInfo)list.OptionalNextListNode;
259                 arrinit = null;
260             }
261 
262             Expression obj = null;
263             MethodInfo m = GetMethodInfoFromExpr(methinfo);
264             Expression[] arguments = GetArgumentsFromArrayInit(arrinit);
265 
266             if (m == null)
267             {
268                 Debug.Assert(false, "How did we get a call that doesn't have a methodinfo?");
269                 throw Error.InternalCompilerError();
270             }
271 
272             // The DLR is expecting the instance for a static invocation to be null. If we have
273             // an instance method, fetch the object.
274             if (!m.IsStatic)
275             {
276                 obj = GetExpression(((ExprList)pExpr.OptionalArguments).OptionalElement);
277             }
278 
279             return Expression.Call(obj, m, arguments);
280         }
281 
282         /////////////////////////////////////////////////////////////////////////////////
283 
GenerateArrayIndex(ExprCall pExpr)284         private Expression GenerateArrayIndex(ExprCall pExpr)
285         {
286             // We have two possibilities here - we're either a single index array, in which
287             // case we'll be PM_EXPRESSION_ARRAYINDEX, or we have multiple dimensions,
288             // in which case we are PM_EXPRESSION_ARRAYINDEX2.
289             //
290             // Our arguments then, are: object, index or object, indices.
291             ExprList list = (ExprList)pExpr.OptionalArguments;
292             Debug.Assert(list != null);
293             Expression obj = GetExpression(list.OptionalElement);
294             Expression[] indices;
295 
296             if (pExpr.PredefinedMethod == PREDEFMETH.PM_EXPRESSION_ARRAYINDEX)
297             {
298                 indices = new[] { GetExpression(list.OptionalNextListNode) };
299             }
300             else
301             {
302                 Debug.Assert(pExpr.PredefinedMethod == PREDEFMETH.PM_EXPRESSION_ARRAYINDEX2);
303                 indices = GetArgumentsFromArrayInit((ExprArrayInit)list.OptionalNextListNode);
304             }
305             return Expression.ArrayAccess(obj, indices);
306         }
307 
308         /////////////////////////////////////////////////////////////////////////////////
309 
GenerateConvert(ExprCall pExpr)310         private Expression GenerateConvert(ExprCall pExpr)
311         {
312             PREDEFMETH pm = pExpr.PredefinedMethod;
313             Expression e;
314             Type t;
315 
316             if (pm == PREDEFMETH.PM_EXPRESSION_CONVERT_USER_DEFINED ||
317                 pm == PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED_USER_DEFINED)
318             {
319                 // If we have a user defined conversion, then we'll have the object
320                 // as the first element, and another list as a second element. This list
321                 // contains a TYPEOF as the first element, and the METHODINFO for the call
322                 // as the second.
323 
324                 ExprList list = (ExprList)pExpr.OptionalArguments;
325                 ExprList list2 = (ExprList)list.OptionalNextListNode;
326                 e = GetExpression(list.OptionalElement);
327                 t = ((ExprTypeOf)list2.OptionalElement).SourceType.AssociatedSystemType;
328 
329                 if (e.Type.MakeByRefType() == t)
330                 {
331                     // We're trying to convert from a type to its by ref type. Don't do that.
332                     return e;
333                 }
334                 Debug.Assert((pExpr.Flags & EXPRFLAG.EXF_UNBOXRUNTIME) == 0);
335 
336                 MethodInfo m = GetMethodInfoFromExpr((ExprMethodInfo)list2.OptionalNextListNode);
337 
338                 if (pm == PREDEFMETH.PM_EXPRESSION_CONVERT_USER_DEFINED)
339                 {
340                     return Expression.Convert(e, t, m);
341                 }
342                 return Expression.ConvertChecked(e, t, m);
343             }
344             else
345             {
346                 Debug.Assert(pm == PREDEFMETH.PM_EXPRESSION_CONVERT ||
347                     pm == PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED);
348 
349                 // If we have a standard conversion, then we'll have some object as
350                 // the first list element (ie a WRAP or a CALL), and then a TYPEOF
351                 // as the second list element.
352                 ExprList list = (ExprList)pExpr.OptionalArguments;
353 
354                 e = GetExpression(list.OptionalElement);
355                 t = ((ExprTypeOf)list.OptionalNextListNode).SourceType.AssociatedSystemType;
356 
357                 if (e.Type.MakeByRefType() == t)
358                 {
359                     // We're trying to convert from a type to its by ref type. Don't do that.
360                     return e;
361                 }
362 
363                 if ((pExpr.Flags & EXPRFLAG.EXF_UNBOXRUNTIME) != 0)
364                 {
365                     // If we want to unbox this thing, return that instead of the convert.
366                     return Expression.Unbox(e, t);
367                 }
368 
369                 if (pm == PREDEFMETH.PM_EXPRESSION_CONVERT)
370                 {
371                     return Expression.Convert(e, t);
372                 }
373                 return Expression.ConvertChecked(e, t);
374             }
375         }
376 
377         /////////////////////////////////////////////////////////////////////////////////
378 
GenerateProperty(ExprCall pExpr)379         private Expression GenerateProperty(ExprCall pExpr)
380         {
381             ExprList list = (ExprList)pExpr.OptionalArguments;
382 
383             Expr instance = list.OptionalElement;
384             Expr nextNode = list.OptionalNextListNode;
385             ExprPropertyInfo propinfo;
386             ExprArrayInit arguments;
387             if (nextNode is ExprList nextList)
388             {
389                 propinfo = nextList.OptionalElement as ExprPropertyInfo;
390                 arguments = nextList.OptionalNextListNode as ExprArrayInit;
391             }
392             else
393             {
394                 propinfo = nextNode as ExprPropertyInfo;
395                 arguments = null;
396             }
397 
398             PropertyInfo p = GetPropertyInfoFromExpr(propinfo);
399 
400             if (p == null)
401             {
402                 Debug.Assert(false, "How did we get a prop that doesn't have a propinfo?");
403                 throw Error.InternalCompilerError();
404             }
405 
406             if (arguments == null)
407             {
408                 return Expression.Property(GetExpression(instance), p);
409             }
410 
411             return Expression.Property(GetExpression(instance), p, GetArgumentsFromArrayInit(arguments));
412         }
413 
414         /////////////////////////////////////////////////////////////////////////////////
415 
GenerateField(ExprCall pExpr)416         private Expression GenerateField(ExprCall pExpr)
417         {
418             ExprList list = (ExprList)pExpr.OptionalArguments;
419             ExprFieldInfo fieldInfo = (ExprFieldInfo)list.OptionalNextListNode;
420             Debug.Assert(fieldInfo != null);
421             Type t = fieldInfo.FieldType.AssociatedSystemType;
422             FieldInfo f = fieldInfo.Field.AssociatedFieldInfo;
423 
424             // This is to ensure that for embedded nopia types, we have the
425             // appropriate local type from the member itself; this is possible
426             // because nopia types are not generic or nested.
427             if (!t.IsGenericType && !t.IsNested)
428             {
429                 t = f.DeclaringType;
430             }
431 
432             // Now find the generic'ed one if we're generic.
433             if (t.IsGenericType)
434             {
435                 f = t.GetField(f.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
436             }
437 
438             return Expression.Field(GetExpression(list.OptionalElement), f);
439         }
440 
441         /////////////////////////////////////////////////////////////////////////////////
442 
GenerateInvoke(ExprCall pExpr)443         private Expression GenerateInvoke(ExprCall pExpr)
444         {
445             ExprList list = (ExprList)pExpr.OptionalArguments;
446 
447             return Expression.Invoke(
448                 GetExpression(list.OptionalElement),
449                 GetArgumentsFromArrayInit(list.OptionalNextListNode as ExprArrayInit));
450         }
451 
452         /////////////////////////////////////////////////////////////////////////////////
453 
GenerateNew(ExprCall pExpr)454         private Expression GenerateNew(ExprCall pExpr)
455         {
456             ExprList list = (ExprList)pExpr.OptionalArguments;
457 
458             var constructor = GetConstructorInfoFromExpr(list.OptionalElement as ExprMethodInfo);
459             var arguments = GetArgumentsFromArrayInit(list.OptionalNextListNode as ExprArrayInit);
460             return Expression.New(constructor, arguments);
461         }
462 
463         /////////////////////////////////////////////////////////////////////////////////
464 
GenerateConstantType(ExprCall pExpr)465         private Expression GenerateConstantType(ExprCall pExpr)
466         {
467             ExprList list = (ExprList)pExpr.OptionalArguments;
468 
469             return Expression.Constant(
470                 GetObject(list.OptionalElement),
471                 ((ExprTypeOf)list.OptionalNextListNode).SourceType.AssociatedSystemType);
472         }
473 
474         /////////////////////////////////////////////////////////////////////////////////
475 
GenerateAssignment(ExprCall pExpr)476         private Expression GenerateAssignment(ExprCall pExpr)
477         {
478             ExprList list = (ExprList)pExpr.OptionalArguments;
479 
480             return Expression.Assign(
481                 GetExpression(list.OptionalElement),
482                 GetExpression(list.OptionalNextListNode));
483         }
484 
485         /////////////////////////////////////////////////////////////////////////////////
486 
GenerateBinaryOperator(ExprCall pExpr)487         private Expression GenerateBinaryOperator(ExprCall pExpr)
488         {
489             ExprList list = (ExprList)pExpr.OptionalArguments;
490             Debug.Assert(list != null);
491             Expression arg1 = GetExpression(list.OptionalElement);
492             Expression arg2 = GetExpression(list.OptionalNextListNode);
493 
494             switch (pExpr.PredefinedMethod)
495             {
496                 case PREDEFMETH.PM_EXPRESSION_ADD:
497                     return Expression.Add(arg1, arg2);
498                 case PREDEFMETH.PM_EXPRESSION_AND:
499                     return Expression.And(arg1, arg2);
500                 case PREDEFMETH.PM_EXPRESSION_DIVIDE:
501                     return Expression.Divide(arg1, arg2);
502                 case PREDEFMETH.PM_EXPRESSION_EQUAL:
503                     return Expression.Equal(arg1, arg2);
504                 case PREDEFMETH.PM_EXPRESSION_EXCLUSIVEOR:
505                     return Expression.ExclusiveOr(arg1, arg2);
506                 case PREDEFMETH.PM_EXPRESSION_GREATERTHAN:
507                     return Expression.GreaterThan(arg1, arg2);
508                 case PREDEFMETH.PM_EXPRESSION_GREATERTHANOREQUAL:
509                     return Expression.GreaterThanOrEqual(arg1, arg2);
510                 case PREDEFMETH.PM_EXPRESSION_LEFTSHIFT:
511                     return Expression.LeftShift(arg1, arg2);
512                 case PREDEFMETH.PM_EXPRESSION_LESSTHAN:
513                     return Expression.LessThan(arg1, arg2);
514                 case PREDEFMETH.PM_EXPRESSION_LESSTHANOREQUAL:
515                     return Expression.LessThanOrEqual(arg1, arg2);
516                 case PREDEFMETH.PM_EXPRESSION_MODULO:
517                     return Expression.Modulo(arg1, arg2);
518                 case PREDEFMETH.PM_EXPRESSION_MULTIPLY:
519                     return Expression.Multiply(arg1, arg2);
520                 case PREDEFMETH.PM_EXPRESSION_NOTEQUAL:
521                     return Expression.NotEqual(arg1, arg2);
522                 case PREDEFMETH.PM_EXPRESSION_OR:
523                     return Expression.Or(arg1, arg2);
524                 case PREDEFMETH.PM_EXPRESSION_RIGHTSHIFT:
525                     return Expression.RightShift(arg1, arg2);
526                 case PREDEFMETH.PM_EXPRESSION_SUBTRACT:
527                     return Expression.Subtract(arg1, arg2);
528                 case PREDEFMETH.PM_EXPRESSION_ORELSE:
529                     return Expression.OrElse(arg1, arg2);
530                 case PREDEFMETH.PM_EXPRESSION_ANDALSO:
531                     return Expression.AndAlso(arg1, arg2);
532 
533                 // Checked
534                 case PREDEFMETH.PM_EXPRESSION_ADDCHECKED:
535                     return Expression.AddChecked(arg1, arg2);
536                 case PREDEFMETH.PM_EXPRESSION_MULTIPLYCHECKED:
537                     return Expression.MultiplyChecked(arg1, arg2);
538                 case PREDEFMETH.PM_EXPRESSION_SUBTRACTCHECKED:
539                     return Expression.SubtractChecked(arg1, arg2);
540 
541                 default:
542                     Debug.Assert(false, "Invalid Predefined Method in GenerateBinaryOperator");
543                     throw Error.InternalCompilerError();
544             }
545         }
546 
547         /////////////////////////////////////////////////////////////////////////////////
548 
GenerateUserDefinedBinaryOperator(ExprCall pExpr)549         private Expression GenerateUserDefinedBinaryOperator(ExprCall pExpr)
550         {
551             ExprList list = (ExprList)pExpr.OptionalArguments;
552             Expression arg1 = GetExpression(list.OptionalElement);
553             Expression arg2 = GetExpression(((ExprList)list.OptionalNextListNode).OptionalElement);
554 
555             list = (ExprList)list.OptionalNextListNode;
556             MethodInfo methodInfo;
557             bool bIsLifted = false;
558             if (list.OptionalNextListNode is ExprList next)
559             {
560                 ExprConstant isLifted = (ExprConstant)next.OptionalElement;
561                 Debug.Assert(isLifted != null);
562                 bIsLifted = isLifted.Val.Int32Val == 1;
563                 methodInfo = GetMethodInfoFromExpr((ExprMethodInfo)next.OptionalNextListNode);
564             }
565             else
566             {
567                 methodInfo = GetMethodInfoFromExpr((ExprMethodInfo)list.OptionalNextListNode);
568             }
569 
570             switch (pExpr.PredefinedMethod)
571             {
572                 case PREDEFMETH.PM_EXPRESSION_ADD_USER_DEFINED:
573                     return Expression.Add(arg1, arg2, methodInfo);
574                 case PREDEFMETH.PM_EXPRESSION_AND_USER_DEFINED:
575                     return Expression.And(arg1, arg2, methodInfo);
576                 case PREDEFMETH.PM_EXPRESSION_DIVIDE_USER_DEFINED:
577                     return Expression.Divide(arg1, arg2, methodInfo);
578                 case PREDEFMETH.PM_EXPRESSION_EQUAL_USER_DEFINED:
579                     return Expression.Equal(arg1, arg2, bIsLifted, methodInfo);
580                 case PREDEFMETH.PM_EXPRESSION_EXCLUSIVEOR_USER_DEFINED:
581                     return Expression.ExclusiveOr(arg1, arg2, methodInfo);
582                 case PREDEFMETH.PM_EXPRESSION_GREATERTHAN_USER_DEFINED:
583                     return Expression.GreaterThan(arg1, arg2, bIsLifted, methodInfo);
584                 case PREDEFMETH.PM_EXPRESSION_GREATERTHANOREQUAL_USER_DEFINED:
585                     return Expression.GreaterThanOrEqual(arg1, arg2, bIsLifted, methodInfo);
586                 case PREDEFMETH.PM_EXPRESSION_LEFTSHIFT_USER_DEFINED:
587                     return Expression.LeftShift(arg1, arg2, methodInfo);
588                 case PREDEFMETH.PM_EXPRESSION_LESSTHAN_USER_DEFINED:
589                     return Expression.LessThan(arg1, arg2, bIsLifted, methodInfo);
590                 case PREDEFMETH.PM_EXPRESSION_LESSTHANOREQUAL_USER_DEFINED:
591                     return Expression.LessThanOrEqual(arg1, arg2, bIsLifted, methodInfo);
592                 case PREDEFMETH.PM_EXPRESSION_MODULO_USER_DEFINED:
593                     return Expression.Modulo(arg1, arg2, methodInfo);
594                 case PREDEFMETH.PM_EXPRESSION_MULTIPLY_USER_DEFINED:
595                     return Expression.Multiply(arg1, arg2, methodInfo);
596                 case PREDEFMETH.PM_EXPRESSION_NOTEQUAL_USER_DEFINED:
597                     return Expression.NotEqual(arg1, arg2, bIsLifted, methodInfo);
598                 case PREDEFMETH.PM_EXPRESSION_OR_USER_DEFINED:
599                     return Expression.Or(arg1, arg2, methodInfo);
600                 case PREDEFMETH.PM_EXPRESSION_RIGHTSHIFT_USER_DEFINED:
601                     return Expression.RightShift(arg1, arg2, methodInfo);
602                 case PREDEFMETH.PM_EXPRESSION_SUBTRACT_USER_DEFINED:
603                     return Expression.Subtract(arg1, arg2, methodInfo);
604                 case PREDEFMETH.PM_EXPRESSION_ORELSE_USER_DEFINED:
605                     return Expression.OrElse(arg1, arg2, methodInfo);
606                 case PREDEFMETH.PM_EXPRESSION_ANDALSO_USER_DEFINED:
607                     return Expression.AndAlso(arg1, arg2, methodInfo);
608 
609                 // Checked
610                 case PREDEFMETH.PM_EXPRESSION_ADDCHECKED_USER_DEFINED:
611                     return Expression.AddChecked(arg1, arg2, methodInfo);
612                 case PREDEFMETH.PM_EXPRESSION_MULTIPLYCHECKED_USER_DEFINED:
613                     return Expression.MultiplyChecked(arg1, arg2, methodInfo);
614                 case PREDEFMETH.PM_EXPRESSION_SUBTRACTCHECKED_USER_DEFINED:
615                     return Expression.SubtractChecked(arg1, arg2, methodInfo);
616 
617                 default:
618                     Debug.Assert(false, "Invalid Predefined Method in GenerateUserDefinedBinaryOperator");
619                     throw Error.InternalCompilerError();
620             }
621         }
622 
623         /////////////////////////////////////////////////////////////////////////////////
624 
GenerateUnaryOperator(ExprCall pExpr)625         private Expression GenerateUnaryOperator(ExprCall pExpr)
626         {
627             PREDEFMETH pm = pExpr.PredefinedMethod;
628             Expression arg = GetExpression(pExpr.OptionalArguments);
629 
630             switch (pm)
631             {
632                 case PREDEFMETH.PM_EXPRESSION_NOT:
633                     return Expression.Not(arg);
634 
635                 case PREDEFMETH.PM_EXPRESSION_NEGATE:
636                     return Expression.Negate(arg);
637 
638                 case PREDEFMETH.PM_EXPRESSION_NEGATECHECKED:
639                     return Expression.NegateChecked(arg);
640 
641                 default:
642                     Debug.Assert(false, "Invalid Predefined Method in GenerateUnaryOperator");
643                     throw Error.InternalCompilerError();
644             }
645         }
646 
647         /////////////////////////////////////////////////////////////////////////////////
648 
GenerateUserDefinedUnaryOperator(ExprCall pExpr)649         private Expression GenerateUserDefinedUnaryOperator(ExprCall pExpr)
650         {
651             PREDEFMETH pm = pExpr.PredefinedMethod;
652             ExprList list = (ExprList)pExpr.OptionalArguments;
653             Expression arg = GetExpression(list.OptionalElement);
654             MethodInfo methodInfo = GetMethodInfoFromExpr((ExprMethodInfo)list.OptionalNextListNode);
655 
656             switch (pm)
657             {
658                 case PREDEFMETH.PM_EXPRESSION_NOT_USER_DEFINED:
659                     return Expression.Not(arg, methodInfo);
660 
661                 case PREDEFMETH.PM_EXPRESSION_NEGATE_USER_DEFINED:
662                     return Expression.Negate(arg, methodInfo);
663 
664                 case PREDEFMETH.PM_EXPRESSION_UNARYPLUS_USER_DEFINED:
665                     return Expression.UnaryPlus(arg, methodInfo);
666 
667                 case PREDEFMETH.PM_EXPRESSION_NEGATECHECKED_USER_DEFINED:
668                     return Expression.NegateChecked(arg, methodInfo);
669 
670                 default:
671                     Debug.Assert(false, "Invalid Predefined Method in GenerateUserDefinedUnaryOperator");
672                     throw Error.InternalCompilerError();
673             }
674         }
675         #endregion
676 
677         #region Helpers
678         /////////////////////////////////////////////////////////////////////////////////
679 
GetExpression(Expr pExpr)680         private Expression GetExpression(Expr pExpr)
681         {
682             if (pExpr is ExprWrap wrap)
683             {
684                 return _DictionaryOfParameters[(ExprCall)wrap.OptionalExpression];
685             }
686             else if (pExpr is ExprConstant)
687             {
688                 Debug.Assert(pExpr.Type is NullType);
689                 return null;
690             }
691             else
692             {
693                 // We can have a convert node or a call of a user defined conversion.
694                 ExprCall call = (ExprCall)pExpr;
695                 Debug.Assert(call != null);
696                 PREDEFMETH pm = call.PredefinedMethod;
697                 Debug.Assert(pm == PREDEFMETH.PM_EXPRESSION_CONVERT ||
698                     pm == PREDEFMETH.PM_EXPRESSION_CONVERT_USER_DEFINED ||
699                     pm == PREDEFMETH.PM_EXPRESSION_NEWARRAYINIT ||
700                     pm == PREDEFMETH.PM_EXPRESSION_CALL ||
701                     pm == PREDEFMETH.PM_EXPRESSION_PROPERTY ||
702                     pm == PREDEFMETH.PM_EXPRESSION_FIELD ||
703                     pm == PREDEFMETH.PM_EXPRESSION_ARRAYINDEX ||
704                     pm == PREDEFMETH.PM_EXPRESSION_ARRAYINDEX2 ||
705                     pm == PREDEFMETH.PM_EXPRESSION_CONSTANT_OBJECT_TYPE ||
706                     pm == PREDEFMETH.PM_EXPRESSION_NEW ||
707 
708                     // Binary operators.
709                     pm == PREDEFMETH.PM_EXPRESSION_ASSIGN ||
710                     pm == PREDEFMETH.PM_EXPRESSION_ADD ||
711                     pm == PREDEFMETH.PM_EXPRESSION_AND ||
712                     pm == PREDEFMETH.PM_EXPRESSION_DIVIDE ||
713                     pm == PREDEFMETH.PM_EXPRESSION_EQUAL ||
714                     pm == PREDEFMETH.PM_EXPRESSION_EXCLUSIVEOR ||
715                     pm == PREDEFMETH.PM_EXPRESSION_GREATERTHAN ||
716                     pm == PREDEFMETH.PM_EXPRESSION_GREATERTHANOREQUAL ||
717                     pm == PREDEFMETH.PM_EXPRESSION_LEFTSHIFT ||
718                     pm == PREDEFMETH.PM_EXPRESSION_LESSTHAN ||
719                     pm == PREDEFMETH.PM_EXPRESSION_LESSTHANOREQUAL ||
720                     pm == PREDEFMETH.PM_EXPRESSION_MODULO ||
721                     pm == PREDEFMETH.PM_EXPRESSION_MULTIPLY ||
722                     pm == PREDEFMETH.PM_EXPRESSION_NOTEQUAL ||
723                     pm == PREDEFMETH.PM_EXPRESSION_OR ||
724                     pm == PREDEFMETH.PM_EXPRESSION_RIGHTSHIFT ||
725                     pm == PREDEFMETH.PM_EXPRESSION_SUBTRACT ||
726                     pm == PREDEFMETH.PM_EXPRESSION_ORELSE ||
727                     pm == PREDEFMETH.PM_EXPRESSION_ANDALSO ||
728                     pm == PREDEFMETH.PM_EXPRESSION_ADD_USER_DEFINED ||
729                     pm == PREDEFMETH.PM_EXPRESSION_AND_USER_DEFINED ||
730                     pm == PREDEFMETH.PM_EXPRESSION_DIVIDE_USER_DEFINED ||
731                     pm == PREDEFMETH.PM_EXPRESSION_EQUAL_USER_DEFINED ||
732                     pm == PREDEFMETH.PM_EXPRESSION_EXCLUSIVEOR_USER_DEFINED ||
733                     pm == PREDEFMETH.PM_EXPRESSION_GREATERTHAN_USER_DEFINED ||
734                     pm == PREDEFMETH.PM_EXPRESSION_GREATERTHANOREQUAL_USER_DEFINED ||
735                     pm == PREDEFMETH.PM_EXPRESSION_LEFTSHIFT_USER_DEFINED ||
736                     pm == PREDEFMETH.PM_EXPRESSION_LESSTHAN_USER_DEFINED ||
737                     pm == PREDEFMETH.PM_EXPRESSION_LESSTHANOREQUAL_USER_DEFINED ||
738                     pm == PREDEFMETH.PM_EXPRESSION_MODULO_USER_DEFINED ||
739                     pm == PREDEFMETH.PM_EXPRESSION_MULTIPLY_USER_DEFINED ||
740                     pm == PREDEFMETH.PM_EXPRESSION_NOTEQUAL_USER_DEFINED ||
741                     pm == PREDEFMETH.PM_EXPRESSION_OR_USER_DEFINED ||
742                     pm == PREDEFMETH.PM_EXPRESSION_RIGHTSHIFT_USER_DEFINED ||
743                     pm == PREDEFMETH.PM_EXPRESSION_SUBTRACT_USER_DEFINED ||
744                     pm == PREDEFMETH.PM_EXPRESSION_ORELSE_USER_DEFINED ||
745                     pm == PREDEFMETH.PM_EXPRESSION_ANDALSO_USER_DEFINED ||
746 
747                     // Checked binary
748                     pm == PREDEFMETH.PM_EXPRESSION_ADDCHECKED ||
749                     pm == PREDEFMETH.PM_EXPRESSION_MULTIPLYCHECKED ||
750                     pm == PREDEFMETH.PM_EXPRESSION_SUBTRACTCHECKED ||
751                     pm == PREDEFMETH.PM_EXPRESSION_ADDCHECKED_USER_DEFINED ||
752                     pm == PREDEFMETH.PM_EXPRESSION_MULTIPLYCHECKED_USER_DEFINED ||
753                     pm == PREDEFMETH.PM_EXPRESSION_SUBTRACTCHECKED_USER_DEFINED ||
754 
755                     // Unary operators.
756                     pm == PREDEFMETH.PM_EXPRESSION_NOT ||
757                     pm == PREDEFMETH.PM_EXPRESSION_NEGATE ||
758                     pm == PREDEFMETH.PM_EXPRESSION_NOT_USER_DEFINED ||
759                     pm == PREDEFMETH.PM_EXPRESSION_NEGATE_USER_DEFINED ||
760                     pm == PREDEFMETH.PM_EXPRESSION_UNARYPLUS_USER_DEFINED ||
761 
762                     // Checked unary
763                     pm == PREDEFMETH.PM_EXPRESSION_NEGATECHECKED ||
764                     pm == PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED ||
765                     pm == PREDEFMETH.PM_EXPRESSION_NEGATECHECKED_USER_DEFINED ||
766                     pm == PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED_USER_DEFINED
767                     );
768 
769                 switch (pm)
770                 {
771                     case PREDEFMETH.PM_EXPRESSION_CALL:
772                         return GenerateCall(call);
773 
774                     case PREDEFMETH.PM_EXPRESSION_CONVERT:
775                     case PREDEFMETH.PM_EXPRESSION_CONVERT_USER_DEFINED:
776                     case PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED:
777                     case PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED_USER_DEFINED:
778                         return GenerateConvert(call);
779 
780                     case PREDEFMETH.PM_EXPRESSION_NEWARRAYINIT:
781                     {
782                         ExprList list = (ExprList)call.OptionalArguments;
783                         return
784                             Expression.NewArrayInit(
785                                 ((ExprTypeOf)list.OptionalElement).SourceType.AssociatedSystemType,
786                                 GetArgumentsFromArrayInit((ExprArrayInit)list.OptionalNextListNode));
787                     }
788 
789                     case PREDEFMETH.PM_EXPRESSION_ARRAYINDEX:
790                     case PREDEFMETH.PM_EXPRESSION_ARRAYINDEX2:
791                         return GenerateArrayIndex(call);
792 
793                     case PREDEFMETH.PM_EXPRESSION_NEW:
794                         return GenerateNew(call);
795 
796                     case PREDEFMETH.PM_EXPRESSION_PROPERTY:
797                         return GenerateProperty(call);
798 
799                     case PREDEFMETH.PM_EXPRESSION_FIELD:
800                         return GenerateField(call);
801 
802                     case PREDEFMETH.PM_EXPRESSION_CONSTANT_OBJECT_TYPE:
803                         return GenerateConstantType(call);
804 
805                     case PREDEFMETH.PM_EXPRESSION_ASSIGN:
806                         return GenerateAssignment(call);
807 
808                     case PREDEFMETH.PM_EXPRESSION_ADD:
809                     case PREDEFMETH.PM_EXPRESSION_AND:
810                     case PREDEFMETH.PM_EXPRESSION_DIVIDE:
811                     case PREDEFMETH.PM_EXPRESSION_EQUAL:
812                     case PREDEFMETH.PM_EXPRESSION_EXCLUSIVEOR:
813                     case PREDEFMETH.PM_EXPRESSION_GREATERTHAN:
814                     case PREDEFMETH.PM_EXPRESSION_GREATERTHANOREQUAL:
815                     case PREDEFMETH.PM_EXPRESSION_LEFTSHIFT:
816                     case PREDEFMETH.PM_EXPRESSION_LESSTHAN:
817                     case PREDEFMETH.PM_EXPRESSION_LESSTHANOREQUAL:
818                     case PREDEFMETH.PM_EXPRESSION_MODULO:
819                     case PREDEFMETH.PM_EXPRESSION_MULTIPLY:
820                     case PREDEFMETH.PM_EXPRESSION_NOTEQUAL:
821                     case PREDEFMETH.PM_EXPRESSION_OR:
822                     case PREDEFMETH.PM_EXPRESSION_RIGHTSHIFT:
823                     case PREDEFMETH.PM_EXPRESSION_SUBTRACT:
824                     case PREDEFMETH.PM_EXPRESSION_ORELSE:
825                     case PREDEFMETH.PM_EXPRESSION_ANDALSO:
826                     // Checked
827                     case PREDEFMETH.PM_EXPRESSION_ADDCHECKED:
828                     case PREDEFMETH.PM_EXPRESSION_MULTIPLYCHECKED:
829                     case PREDEFMETH.PM_EXPRESSION_SUBTRACTCHECKED:
830                         return GenerateBinaryOperator(call);
831 
832                     case PREDEFMETH.PM_EXPRESSION_ADD_USER_DEFINED:
833                     case PREDEFMETH.PM_EXPRESSION_AND_USER_DEFINED:
834                     case PREDEFMETH.PM_EXPRESSION_DIVIDE_USER_DEFINED:
835                     case PREDEFMETH.PM_EXPRESSION_EQUAL_USER_DEFINED:
836                     case PREDEFMETH.PM_EXPRESSION_EXCLUSIVEOR_USER_DEFINED:
837                     case PREDEFMETH.PM_EXPRESSION_GREATERTHAN_USER_DEFINED:
838                     case PREDEFMETH.PM_EXPRESSION_GREATERTHANOREQUAL_USER_DEFINED:
839                     case PREDEFMETH.PM_EXPRESSION_LEFTSHIFT_USER_DEFINED:
840                     case PREDEFMETH.PM_EXPRESSION_LESSTHAN_USER_DEFINED:
841                     case PREDEFMETH.PM_EXPRESSION_LESSTHANOREQUAL_USER_DEFINED:
842                     case PREDEFMETH.PM_EXPRESSION_MODULO_USER_DEFINED:
843                     case PREDEFMETH.PM_EXPRESSION_MULTIPLY_USER_DEFINED:
844                     case PREDEFMETH.PM_EXPRESSION_NOTEQUAL_USER_DEFINED:
845                     case PREDEFMETH.PM_EXPRESSION_OR_USER_DEFINED:
846                     case PREDEFMETH.PM_EXPRESSION_RIGHTSHIFT_USER_DEFINED:
847                     case PREDEFMETH.PM_EXPRESSION_SUBTRACT_USER_DEFINED:
848                     case PREDEFMETH.PM_EXPRESSION_ORELSE_USER_DEFINED:
849                     case PREDEFMETH.PM_EXPRESSION_ANDALSO_USER_DEFINED:
850                     // Checked
851                     case PREDEFMETH.PM_EXPRESSION_ADDCHECKED_USER_DEFINED:
852                     case PREDEFMETH.PM_EXPRESSION_MULTIPLYCHECKED_USER_DEFINED:
853                     case PREDEFMETH.PM_EXPRESSION_SUBTRACTCHECKED_USER_DEFINED:
854                         return GenerateUserDefinedBinaryOperator(call);
855 
856                     case PREDEFMETH.PM_EXPRESSION_NOT:
857                     case PREDEFMETH.PM_EXPRESSION_NEGATE:
858                     case PREDEFMETH.PM_EXPRESSION_NEGATECHECKED:
859                         return GenerateUnaryOperator(call);
860 
861                     case PREDEFMETH.PM_EXPRESSION_NOT_USER_DEFINED:
862                     case PREDEFMETH.PM_EXPRESSION_NEGATE_USER_DEFINED:
863                     case PREDEFMETH.PM_EXPRESSION_UNARYPLUS_USER_DEFINED:
864                     case PREDEFMETH.PM_EXPRESSION_NEGATECHECKED_USER_DEFINED:
865                         return GenerateUserDefinedUnaryOperator(call);
866 
867                     default:
868                         Debug.Assert(false, "Invalid Predefined Method in GetExpression");
869                         throw Error.InternalCompilerError();
870                 }
871             }
872         }
873 
874         /////////////////////////////////////////////////////////////////////////////////
875 
GetObject(Expr pExpr)876         private object GetObject(Expr pExpr)
877         {
878             for (;;)
879             {
880                 if (pExpr is ExprCast cast)
881                 {
882                     pExpr = cast.Argument;
883                 }
884                 else if (pExpr is ExprTypeOf typeOf)
885                 {
886                     return typeOf.SourceType.AssociatedSystemType;
887                 }
888                 else if (pExpr is ExprMethodInfo methodInfo)
889                 {
890                     return GetMethodInfoFromExpr(methodInfo);
891                 }
892                 else if (pExpr is ExprConstant constant)
893                 {
894                     ConstVal val = constant.Val;
895                     CType underlyingType = pExpr.Type;
896                     object objval;
897 
898                     if (pExpr.Type is NullType)
899                     {
900                         return null;
901                     }
902 
903                     if (pExpr.Type.isEnumType())
904                     {
905                         underlyingType = underlyingType.getAggregate().GetUnderlyingType();
906                     }
907 
908                     switch (Type.GetTypeCode(underlyingType.AssociatedSystemType))
909                     {
910                         case TypeCode.Boolean:
911                             objval = val.BooleanVal;
912                             break;
913                         case TypeCode.SByte:
914                             objval = val.SByteVal;
915                             break;
916                         case TypeCode.Byte:
917                             objval = val.ByteVal;
918                             break;
919                         case TypeCode.Int16:
920                             objval = val.Int16Val;
921                             break;
922                         case TypeCode.UInt16:
923                             objval = val.UInt16Val;
924                             break;
925                         case TypeCode.Int32:
926                             objval = val.Int32Val;
927                             break;
928                         case TypeCode.UInt32:
929                             objval = val.UInt32Val;
930                             break;
931                         case TypeCode.Int64:
932                             objval = val.Int64Val;
933                             break;
934                         case TypeCode.UInt64:
935                             objval = val.UInt64Val;
936                             break;
937                         case TypeCode.Single:
938                             objval = val.SingleVal;
939                             break;
940                         case TypeCode.Double:
941                             objval = val.DoubleVal;
942                             break;
943                         case TypeCode.Decimal:
944                             objval = val.DecimalVal;
945                             break;
946                         case TypeCode.Char:
947                             objval = val.CharVal;
948                             break;
949                         case TypeCode.String:
950                             objval = val.StringVal;
951                             break;
952                         default:
953                             objval = val.ObjectVal;
954                             break;
955                     }
956 
957                     return pExpr.Type.isEnumType() ? Enum.ToObject(pExpr.Type.AssociatedSystemType, objval) : objval;
958                 }
959                 else if (pExpr is ExprZeroInit zeroInit)
960                 {
961                     return Activator.CreateInstance(zeroInit.Type.AssociatedSystemType);
962                 }
963                 else
964                 {
965                     Debug.Assert(false, "Invalid Expr in GetObject");
966                     throw Error.InternalCompilerError();
967                 }
968             }
969         }
970 
971         /////////////////////////////////////////////////////////////////////////////////
972 
GetArgumentsFromArrayInit(ExprArrayInit arrinit)973         private Expression[] GetArgumentsFromArrayInit(ExprArrayInit arrinit)
974         {
975             List<Expression> expressions = new List<Expression>();
976 
977             if (arrinit != null)
978             {
979                 Expr list = arrinit.OptionalArguments;
980                 while (list != null)
981                 {
982                     Expr p;
983                     if (list is ExprList pList)
984                     {
985                         p = pList.OptionalElement;
986                         list = pList.OptionalNextListNode;
987                     }
988                     else
989                     {
990                         p = list;
991                         list = null;
992                     }
993 
994                     expressions.Add(GetExpression(p));
995                 }
996 
997                 Debug.Assert(expressions.Count == arrinit.DimensionSizes[0]);
998             }
999 
1000             return expressions.ToArray();
1001         }
1002 
1003         /////////////////////////////////////////////////////////////////////////////////
1004 
GetMethodInfoFromExpr(ExprMethodInfo methinfo)1005         private MethodInfo GetMethodInfoFromExpr(ExprMethodInfo methinfo)
1006         {
1007             // To do this, we need to construct a type array of the parameter types,
1008             // get the parent constructed type, and get the method from it.
1009 
1010             AggregateType aggType = methinfo.Method.Ats;
1011             MethodSymbol methSym = methinfo.Method.Meth();
1012 
1013             TypeArray genericParams = _typeManager.SubstTypeArray(methSym.Params, aggType, methSym.typeVars);
1014             CType genericReturn = _typeManager.SubstType(methSym.RetType, aggType, methSym.typeVars);
1015 
1016             Type type = aggType.AssociatedSystemType;
1017             MethodInfo methodInfo = methSym.AssociatedMemberInfo as MethodInfo;
1018 
1019             // This is to ensure that for embedded nopia types, we have the
1020             // appropriate local type from the member itself; this is possible
1021             // because nopia types are not generic or nested.
1022             if (!type.IsGenericType && !type.IsNested)
1023             {
1024                 type = methodInfo.DeclaringType;
1025             }
1026 
1027             // We need to find the associated methodinfo on the instantiated type.
1028             foreach (MethodInfo m in type.GetRuntimeMethods())
1029             {
1030 #if UNSUPPORTEDAPI
1031                 if ((m.MetadataToken != methodInfo.MetadataToken) || (m.Module != methodInfo.Module))
1032 #else
1033                 if (!m.HasSameMetadataDefinitionAs(methodInfo))
1034 #endif
1035                 {
1036                     continue;
1037                 }
1038 
1039                 Debug.Assert((m.Name == methodInfo.Name) &&
1040                     (m.GetParameters().Length == genericParams.Count) &&
1041                     (TypesAreEqual(m.ReturnType, genericReturn.AssociatedSystemType)));
1042 
1043                 bool bMatch = true;
1044                 ParameterInfo[] parameters = m.GetParameters();
1045                 for (int i = 0; i < genericParams.Count; i++)
1046                 {
1047                     if (!TypesAreEqual(parameters[i].ParameterType, genericParams[i].AssociatedSystemType))
1048                     {
1049                         bMatch = false;
1050                         break;
1051                     }
1052                 }
1053                 if (bMatch)
1054                 {
1055                     if (m.IsGenericMethod)
1056                     {
1057                         int size = methinfo.Method.TypeArgs?.Count ?? 0;
1058                         Type[] typeArgs = new Type[size];
1059                         if (size > 0)
1060                         {
1061                             for (int i = 0; i < methinfo.Method.TypeArgs.Count; i++)
1062                             {
1063                                 typeArgs[i] = methinfo.Method.TypeArgs[i].AssociatedSystemType;
1064                             }
1065                         }
1066                         return m.MakeGenericMethod(typeArgs);
1067                     }
1068 
1069                     return m;
1070                 }
1071             }
1072 
1073             Debug.Assert(false, "Could not find matching method");
1074             throw Error.InternalCompilerError();
1075         }
1076 
1077         /////////////////////////////////////////////////////////////////////////////////
1078 
GetConstructorInfoFromExpr(ExprMethodInfo methinfo)1079         private ConstructorInfo GetConstructorInfoFromExpr(ExprMethodInfo methinfo)
1080         {
1081             // To do this, we need to construct a type array of the parameter types,
1082             // get the parent constructed type, and get the method from it.
1083 
1084             AggregateType aggType = methinfo.Method.Ats;
1085             MethodSymbol methSym = methinfo.Method.Meth();
1086 
1087             TypeArray genericInstanceParams = _typeManager.SubstTypeArray(methSym.Params, aggType);
1088             Type type = aggType.AssociatedSystemType;
1089             ConstructorInfo ctorInfo = (ConstructorInfo)methSym.AssociatedMemberInfo;
1090 
1091             // This is to ensure that for embedded nopia types, we have the
1092             // appropriate local type from the member itself; this is possible
1093             // because nopia types are not generic or nested.
1094             if (!type.IsGenericType && !type.IsNested)
1095             {
1096                 type = ctorInfo.DeclaringType;
1097             }
1098 
1099             foreach (ConstructorInfo c in type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
1100             {
1101 #if UNSUPPORTEDAPI
1102                 if ((c.MetadataToken != ctorInfo.MetadataToken) || (c.Module != ctorInfo.Module))
1103 #else
1104                 if (!c.HasSameMetadataDefinitionAs(ctorInfo))
1105 #endif
1106                 {
1107                     continue;
1108                 }
1109                 Debug.Assert(c.GetParameters() == null || c.GetParameters().Length == genericInstanceParams.Count);
1110 
1111                 bool bMatch = true;
1112                 ParameterInfo[] parameters = c.GetParameters();
1113                 for (int i = 0; i < genericInstanceParams.Count; i++)
1114                 {
1115                     if (!TypesAreEqual(parameters[i].ParameterType, genericInstanceParams[i].AssociatedSystemType))
1116                     {
1117                         bMatch = false;
1118                         break;
1119                     }
1120                 }
1121                 if (bMatch)
1122                 {
1123                     return c;
1124                 }
1125             }
1126 
1127             Debug.Assert(false, "Could not find matching constructor");
1128             throw Error.InternalCompilerError();
1129         }
1130 
1131         /////////////////////////////////////////////////////////////////////////////////
1132 
GetPropertyInfoFromExpr(ExprPropertyInfo propinfo)1133         private PropertyInfo GetPropertyInfoFromExpr(ExprPropertyInfo propinfo)
1134         {
1135             // To do this, we need to construct a type array of the parameter types,
1136             // get the parent constructed type, and get the property from it.
1137 
1138             AggregateType aggType = propinfo.Property.Ats;
1139             PropertySymbol propSym = propinfo.Property.Prop();
1140 
1141             TypeArray genericInstanceParams = _typeManager.SubstTypeArray(propSym.Params, aggType, null);
1142 
1143             Type type = aggType.AssociatedSystemType;
1144             PropertyInfo propertyInfo = propSym.AssociatedPropertyInfo;
1145 
1146             // This is to ensure that for embedded nopia types, we have the
1147             // appropriate local type from the member itself; this is possible
1148             // because nopia types are not generic or nested.
1149             if (!type.IsGenericType && !type.IsNested)
1150             {
1151                 type = propertyInfo.DeclaringType;
1152             }
1153 
1154             foreach (PropertyInfo p in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
1155             {
1156 #if UNSUPPORTEDAPI
1157                 if ((p.MetadataToken != propertyInfo.MetadataToken) || (p.Module != propertyInfo.Module))
1158 #else
1159                 if (!p.HasSameMetadataDefinitionAs(propertyInfo))
1160                 {
1161 #endif
1162                     continue;
1163                 }
1164                 Debug.Assert((p.Name == propertyInfo.Name) &&
1165                     (p.GetIndexParameters() == null || p.GetIndexParameters().Length == genericInstanceParams.Count));
1166 
1167                 bool bMatch = true;
1168                 ParameterInfo[] parameters = p.GetSetMethod(true) != null ?
1169                     p.GetSetMethod(true).GetParameters() : p.GetGetMethod(true).GetParameters();
1170                 for (int i = 0; i < genericInstanceParams.Count; i++)
1171                 {
1172                     if (!TypesAreEqual(parameters[i].ParameterType, genericInstanceParams[i].AssociatedSystemType))
1173                     {
1174                         bMatch = false;
1175                         break;
1176                     }
1177                 }
1178                 if (bMatch)
1179                 {
1180                     return p;
1181                 }
1182             }
1183 
1184             Debug.Assert(false, "Could not find matching property");
1185             throw Error.InternalCompilerError();
1186         }
1187 
1188         /////////////////////////////////////////////////////////////////////////////////
1189 
TypesAreEqual(Type t1, Type t2)1190         private bool TypesAreEqual(Type t1, Type t2)
1191         {
1192             if (t1 == t2)
1193             {
1194                 return true;
1195             }
1196 
1197             return t1.IsEquivalentTo(t2);
1198         }
1199         #endregion
1200     }
1201 }
1202