- Preliminary support for late binding in array access (needs support in
[mono.git] / mcs / mbas / expression.cs
1 //\r
2 // expression.cs: Expression representation for the IL tree.\r
3 //\r
4 // Author:\r
5 //   Miguel de Icaza (miguel@ximian.com)\r
6 //\r
7 // (C) 2001 Ximian, Inc.\r
8 //\r
9 //\r
10 #define USE_OLD\r
11 \r
12 namespace Mono.CSharp {\r
13         using System;\r
14         using System.Collections;\r
15         using System.Reflection;\r
16         using System.Reflection.Emit;\r
17         using System.Text;\r
18 \r
19         /// <summary>\r
20         ///   This is just a helper class, it is generated by Unary, UnaryMutator\r
21         ///   when an overloaded method has been found.  It just emits the code for a\r
22         ///   static call.\r
23         /// </summary>\r
24         public class StaticCallExpr : ExpressionStatement {\r
25                 ArrayList args;\r
26                 MethodInfo mi;\r
27 \r
28                 StaticCallExpr (MethodInfo m, ArrayList a, Location l)\r
29                 {\r
30                         mi = m;\r
31                         args = a;\r
32 \r
33                         type = m.ReturnType;\r
34                         eclass = ExprClass.Value;\r
35                         loc = l;\r
36                 }\r
37 \r
38                 public override Expression DoResolve (EmitContext ec)\r
39                 {\r
40                         //\r
41                         // We are born fully resolved\r
42                         //\r
43                         return this;\r
44                 }\r
45 \r
46                 public override void Emit (EmitContext ec)\r
47                 {\r
48                         if (args != null) \r
49                                 Invocation.EmitArguments (ec, mi, args);\r
50 \r
51                         ec.ig.Emit (OpCodes.Call, mi);\r
52                         return;\r
53                 }\r
54                 \r
55                 static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,\r
56                                                          Expression e, Location loc)\r
57                 {\r
58                         ArrayList args;\r
59                         MethodBase method;\r
60                         \r
61                         args = new ArrayList (1);\r
62                         args.Add (new Argument (e, Argument.AType.Expression));\r
63                         method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, args, loc);\r
64 \r
65                         if (method == null)\r
66                                 return null;\r
67 \r
68                         return new StaticCallExpr ((MethodInfo) method, args, loc);\r
69                 }\r
70 \r
71                 public override void EmitStatement (EmitContext ec)\r
72                 {\r
73                         Emit (ec);\r
74                         if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)\r
75                                 ec.ig.Emit (OpCodes.Pop);\r
76                 }\r
77         }\r
78         \r
79         /// <summary>\r
80         ///   Unary expressions.  \r
81         /// </summary>\r
82         ///\r
83         /// <remarks>\r
84         ///   Unary implements unary expressions.   It derives from\r
85         ///   ExpressionStatement becuase the pre/post increment/decrement\r
86         ///   operators can be used in a statement context.\r
87         /// </remarks>\r
88         public class Unary : Expression {\r
89                 public enum Operator : byte {\r
90                         UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,\r
91                         Indirection, AddressOf,  TOP\r
92                 }\r
93 \r
94                 public Operator Oper;\r
95                 public Expression Expr;\r
96                 \r
97                 public Unary (Operator op, Expression expr, Location loc)\r
98                 {\r
99                         this.Oper = op;\r
100                         this.Expr = expr;\r
101                         this.loc = loc;\r
102                 }\r
103 \r
104                 /// <summary>\r
105                 ///   Returns a stringified representation of the Operator\r
106                 /// </summary>\r
107                 static public string OperName (Operator oper)\r
108                 {\r
109                         switch (oper){\r
110                         case Operator.UnaryPlus:\r
111                                 return "+";\r
112                         case Operator.UnaryNegation:\r
113                                 return "-";\r
114                         case Operator.LogicalNot:\r
115                                 return "!";\r
116                         case Operator.OnesComplement:\r
117                                 return "~";\r
118                         case Operator.AddressOf:\r
119                                 return "&";\r
120                         case Operator.Indirection:\r
121                                 return "*";\r
122                         }\r
123 \r
124                         return oper.ToString ();\r
125                 }\r
126 \r
127                 static string [] oper_names;\r
128 \r
129                 static Unary ()\r
130                 {\r
131                         oper_names = new string [(int)Operator.TOP];\r
132 \r
133                         oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";\r
134                         oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";\r
135                         oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";\r
136                         oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";\r
137                         oper_names [(int) Operator.Indirection] = "op_Indirection";\r
138                         oper_names [(int) Operator.AddressOf] = "op_AddressOf";\r
139                 }\r
140 \r
141                 void Error23 (Type t)\r
142                 {\r
143                         Error (\r
144                                 23, "Operator " + OperName (Oper) +\r
145                                 " cannot be applied to operand of type '" +\r
146                                 TypeManager.CSharpName (t) + "'");\r
147                 }\r
148 \r
149                 /// <remarks>\r
150                 ///   The result has been already resolved:\r
151                 ///\r
152                 ///   FIXME: a minus constant -128 sbyte cant be turned into a\r
153                 ///   constant byte.\r
154                 /// </remarks>\r
155                 static Expression TryReduceNegative (Constant expr)\r
156                 {\r
157                         Expression e = null;\r
158                         \r
159                         if (expr is IntConstant)\r
160                                 e = new IntConstant (-((IntConstant) expr).Value);\r
161                         else if (expr is UIntConstant){\r
162                                 uint value = ((UIntConstant) expr).Value;\r
163 \r
164                                 if (value < 2147483649)\r
165                                         return new IntConstant (-(int)value);\r
166                                 else\r
167                                         e = new LongConstant (value);\r
168                         }\r
169                         else if (expr is LongConstant)\r
170                                 e = new LongConstant (-((LongConstant) expr).Value);\r
171                         else if (expr is ULongConstant){\r
172                                 ulong value = ((ULongConstant) expr).Value;\r
173 \r
174                                 if (value < 9223372036854775809)\r
175                                         return new LongConstant(-(long)value);\r
176                         }\r
177                         else if (expr is FloatConstant)\r
178                                 e = new FloatConstant (-((FloatConstant) expr).Value);\r
179                         else if (expr is DoubleConstant)\r
180                                 e = new DoubleConstant (-((DoubleConstant) expr).Value);\r
181                         else if (expr is DecimalConstant)\r
182                                 e = new DecimalConstant (-((DecimalConstant) expr).Value);\r
183                         else if (expr is ShortConstant)\r
184                                 e = new IntConstant (-((ShortConstant) expr).Value);\r
185                         else if (expr is UShortConstant)\r
186                                 e = new IntConstant (-((UShortConstant) expr).Value);\r
187                         return e;\r
188                 }\r
189 \r
190                 // <summary>\r
191                 //   This routine will attempt to simplify the unary expression when the\r
192                 //   argument is a constant.  The result is returned in 'result' and the\r
193                 //   function returns true or false depending on whether a reduction\r
194                 //   was performed or not\r
195                 // </summary>\r
196                 bool Reduce (EmitContext ec, Constant e, out Expression result)\r
197                 {\r
198                         Type expr_type = e.Type;\r
199                         \r
200                         switch (Oper){\r
201                         case Operator.UnaryPlus:\r
202                                 result = e;\r
203                                 return true;\r
204                                 \r
205                         case Operator.UnaryNegation:\r
206                                 result = TryReduceNegative (e);\r
207                                 return true;\r
208                                 \r
209                         case Operator.LogicalNot:\r
210                                 if (expr_type != TypeManager.bool_type) {\r
211                                         result = null;\r
212                                         Error23 (expr_type);\r
213                                         return false;\r
214                                 }\r
215                                 \r
216                                 BoolConstant b = (BoolConstant) e;\r
217                                 result = new BoolConstant (!(b.Value));\r
218                                 return true;\r
219                                 \r
220                         case Operator.OnesComplement:\r
221                                 if (!((expr_type == TypeManager.int32_type) ||\r
222                                       (expr_type == TypeManager.uint32_type) ||\r
223                                       (expr_type == TypeManager.int64_type) ||\r
224                                       (expr_type == TypeManager.uint64_type) ||\r
225                                       (expr_type.IsSubclassOf (TypeManager.enum_type)))){\r
226                                         result = null;\r
227                                         Error23 (expr_type);\r
228                                         return false;\r
229                                 }\r
230 \r
231                                 if (e is EnumConstant){\r
232                                         EnumConstant enum_constant = (EnumConstant) e;\r
233                                         Expression reduced;\r
234                                         \r
235                                         if (Reduce (ec, enum_constant.Child, out reduced)){\r
236                                                 result = new EnumConstant ((Constant) reduced, enum_constant.Type);\r
237                                                 return true;\r
238                                         } else {\r
239                                                 result = null;\r
240                                                 return false;\r
241                                         }\r
242                                 }\r
243 \r
244                                 if (expr_type == TypeManager.int32_type){\r
245                                         result = new IntConstant (~ ((IntConstant) e).Value);\r
246                                 } else if (expr_type == TypeManager.uint32_type){\r
247                                         result = new UIntConstant (~ ((UIntConstant) e).Value);\r
248                                 } else if (expr_type == TypeManager.int64_type){\r
249                                         result = new LongConstant (~ ((LongConstant) e).Value);\r
250                                 } else if (expr_type == TypeManager.uint64_type){\r
251                                         result = new ULongConstant (~ ((ULongConstant) e).Value);\r
252                                 } else {\r
253                                         result = null;\r
254                                         Error23 (expr_type);\r
255                                         return false;\r
256                                 }\r
257                                 return true;\r
258 \r
259                         case Operator.AddressOf:\r
260                                 result = this;\r
261                                 return false;\r
262 \r
263                         case Operator.Indirection:\r
264                                 result = this;\r
265                                 return false;\r
266                         }\r
267                         throw new Exception ("Can not constant fold: " + Oper.ToString());\r
268                 }\r
269 \r
270                 Expression ResolveOperator (EmitContext ec)\r
271                 {\r
272                         Type expr_type = Expr.Type;\r
273 \r
274                         //\r
275                         // Step 1: Perform Operator Overload location\r
276                         //\r
277                         Expression mg;\r
278                         string op_name;\r
279                         \r
280                         op_name = oper_names [(int) Oper];\r
281 \r
282                         mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);\r
283                         \r
284                         if (mg != null) {\r
285                                 Expression e = StaticCallExpr.MakeSimpleCall (\r
286                                         ec, (MethodGroupExpr) mg, Expr, loc);\r
287 \r
288                                 if (e == null){\r
289                                         Error23 (expr_type);\r
290                                         return null;\r
291                                 }\r
292                                 \r
293                                 return e;\r
294                         }\r
295 \r
296                         // Only perform numeric promotions on:\r
297                         // +, - \r
298 \r
299                         if (expr_type == null)\r
300                                 return null;\r
301                         \r
302                         //\r
303                         // Step 2: Default operations on CLI native types.\r
304                         //\r
305 \r
306                         // Attempt to use a constant folding operation.\r
307                         if (Expr is Constant){\r
308                                 Expression result;\r
309                                 \r
310                                 if (Reduce (ec, (Constant) Expr, out result))\r
311                                         return result;\r
312                         }\r
313 \r
314                         switch (Oper){\r
315                         case Operator.LogicalNot:\r
316                                 if (expr_type != TypeManager.bool_type) {\r
317                                         Error23 (Expr.Type);\r
318                                         return null;\r
319                                 }\r
320                                 \r
321                                 type = TypeManager.bool_type;\r
322                                 return this;\r
323 \r
324                         case Operator.OnesComplement:\r
325                                 if (!((expr_type == TypeManager.int32_type) ||\r
326                                       (expr_type == TypeManager.uint32_type) ||\r
327                                       (expr_type == TypeManager.int64_type) ||\r
328                                       (expr_type == TypeManager.uint64_type) ||\r
329                                       (expr_type.IsSubclassOf (TypeManager.enum_type)))){\r
330                                         Expression e;\r
331 \r
332                                         e = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);\r
333                                         if (e != null){\r
334                                                 type = TypeManager.int32_type;\r
335                                                 return this;\r
336                                         }\r
337                                         e = ConvertImplicit (ec, Expr, TypeManager.uint32_type, loc);\r
338                                         if (e != null){\r
339                                                 type = TypeManager.uint32_type;\r
340                                                 return this;\r
341                                         }\r
342                                         e = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);\r
343                                         if (e != null){\r
344                                                 type = TypeManager.int64_type;\r
345                                                 return this;\r
346                                         }\r
347                                         e = ConvertImplicit (ec, Expr, TypeManager.uint64_type, loc);\r
348                                         if (e != null){\r
349                                                 type = TypeManager.uint64_type;\r
350                                                 return this;\r
351                                         }\r
352                                         Error23 (expr_type);\r
353                                         return null;\r
354                                 }\r
355                                 type = expr_type;\r
356                                 return this;\r
357 \r
358                         case Operator.AddressOf:\r
359                                 if (Expr.eclass != ExprClass.Variable){\r
360                                         Error (211, "Cannot take the address of non-variables");\r
361                                         return null;\r
362                                 }\r
363                                 \r
364                                 if (!ec.InUnsafe) {\r
365                                         UnsafeError (loc); \r
366                                         return null;\r
367                                 }\r
368                                 \r
369                                 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){\r
370                                         return null;\r
371                                 }\r
372                                 \r
373                                 string ptr_type_name = Expr.Type.FullName + "*";\r
374                                 type = TypeManager.LookupType (ptr_type_name);\r
375                                 \r
376                                 return this;\r
377 \r
378                         case Operator.Indirection:\r
379                                 if (!ec.InUnsafe){\r
380                                         UnsafeError (loc);\r
381                                         return null;\r
382                                 }\r
383                                 \r
384                                 if (!expr_type.IsPointer){\r
385                                         Error (\r
386                                                 193,\r
387                                                 "The * or -> operator can only be applied to pointers");\r
388                                         return null;\r
389                                 }\r
390                                 \r
391                                 //\r
392                                 // We create an Indirection expression, because\r
393                                 // it can implement the IMemoryLocation.\r
394                                 // \r
395                                 return new Indirection (Expr, loc);\r
396                         \r
397                         case Operator.UnaryPlus:\r
398                                 //\r
399                                 // A plus in front of something is just a no-op, so return the child.\r
400                                 //\r
401                                 return Expr;\r
402 \r
403                         case Operator.UnaryNegation:\r
404                                 //\r
405                                 // Deals with -literals\r
406                                 // int     operator- (int x)\r
407                                 // long    operator- (long x)\r
408                                 // float   operator- (float f)\r
409                                 // double  operator- (double d)\r
410                                 // decimal operator- (decimal d)\r
411                                 //\r
412                                 Expression expr = null;\r
413 \r
414                                 //\r
415                                 // transform - - expr into expr\r
416                                 //\r
417                                 if (Expr is Unary){\r
418                                         Unary unary = (Unary) Expr;\r
419                                         \r
420                                         if (unary.Oper == Operator.UnaryNegation)\r
421                                                 return unary.Expr;\r
422                                 }\r
423 \r
424                                 //\r
425                                 // perform numeric promotions to int,\r
426                                 // long, double.\r
427                                 //\r
428                                 //\r
429                                 // The following is inneficient, because we call\r
430                                 // ConvertImplicit too many times.\r
431                                 //\r
432                                 // It is also not clear if we should convert to Float\r
433                                 // or Double initially.\r
434                                 //\r
435                                 if (expr_type == TypeManager.uint32_type){\r
436                                         //\r
437                                         // FIXME: handle exception to this rule that\r
438                                         // permits the int value -2147483648 (-2^31) to\r
439                                         // bt wrote as a decimal interger literal\r
440                                         //\r
441                                         type = TypeManager.int64_type;\r
442                                         Expr = ConvertImplicit (ec, Expr, type, loc);\r
443                                         return this;\r
444                                 }\r
445 \r
446                                 if (expr_type == TypeManager.uint64_type){\r
447                                         //\r
448                                         // FIXME: Handle exception of 'long value'\r
449                                         // -92233720368547758087 (-2^63) to be wrote as\r
450                                         // decimal integer literal.\r
451                                         //\r
452                                         Error23 (expr_type);\r
453                                         return null;\r
454                                 }\r
455 \r
456                                 if (expr_type == TypeManager.float_type){\r
457                                         type = expr_type;\r
458                                         return this;\r
459                                 }\r
460                                 \r
461                                 expr = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);\r
462                                 if (expr != null){\r
463                                         Expr = expr;\r
464                                         type = expr.Type;\r
465                                         return this;\r
466                                 } \r
467 \r
468                                 expr = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);\r
469                                 if (expr != null){\r
470                                         Expr = expr;\r
471                                         type = expr.Type;\r
472                                         return this;\r
473                                 }\r
474 \r
475                                 expr = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);\r
476                                 if (expr != null){\r
477                                         Expr = expr;\r
478                                         type = expr.Type;\r
479                                         return this;\r
480                                 }\r
481                                 \r
482                                 Error23 (expr_type);\r
483                                 return null;\r
484                         }\r
485 \r
486                         Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +\r
487                                TypeManager.CSharpName (expr_type) + "'");\r
488                         return null;\r
489                 }\r
490 \r
491                 public override Expression DoResolve (EmitContext ec)\r
492                 {\r
493                         if (Oper == Operator.AddressOf)\r
494                                 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());\r
495                         else\r
496                                 Expr = Expr.Resolve (ec);\r
497                         \r
498                         if (Expr == null)\r
499                                 return null;\r
500 \r
501                         eclass = ExprClass.Value;\r
502                         return ResolveOperator (ec);\r
503                 }\r
504 \r
505                 public override void Emit (EmitContext ec)\r
506                 {\r
507                         ILGenerator ig = ec.ig;\r
508                         Type expr_type = Expr.Type;\r
509                         \r
510                         switch (Oper) {\r
511                         case Operator.UnaryPlus:\r
512                                 throw new Exception ("This should be caught by Resolve");\r
513                                 \r
514                         case Operator.UnaryNegation:\r
515                                 Expr.Emit (ec);\r
516                                 ig.Emit (OpCodes.Neg);\r
517                                 break;\r
518                                 \r
519                         case Operator.LogicalNot:\r
520                                 Expr.Emit (ec);\r
521                                 ig.Emit (OpCodes.Ldc_I4_0);\r
522                                 ig.Emit (OpCodes.Ceq);\r
523                                 break;\r
524                                 \r
525                         case Operator.OnesComplement:\r
526                                 Expr.Emit (ec);\r
527                                 ig.Emit (OpCodes.Not);\r
528                                 break;\r
529                                 \r
530                         case Operator.AddressOf:\r
531                                 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);\r
532                                 break;\r
533                                 \r
534                         default:\r
535                                 throw new Exception ("This should not happen: Operator = "\r
536                                                      + Oper.ToString ());\r
537                         }\r
538                 }\r
539 \r
540                 /// <summary>\r
541                 ///   This will emit the child expression for 'ec' avoiding the logical\r
542                 ///   not.  The parent will take care of changing brfalse/brtrue\r
543                 /// </summary>\r
544                 public void EmitLogicalNot (EmitContext ec)\r
545                 {\r
546                         if (Oper != Operator.LogicalNot)\r
547                                 throw new Exception ("EmitLogicalNot can only be called with !expr");\r
548 \r
549                         Expr.Emit (ec);\r
550                 }\r
551 \r
552                 public override string ToString ()\r
553                 {\r
554                         return "Unary (" + Oper + ", " + Expr + ")";\r
555                 }\r
556                 \r
557         }\r
558 \r
559         //\r
560         // Unary operators are turned into Indirection expressions\r
561         // after semantic analysis (this is so we can take the address\r
562         // of an indirection).\r
563         //\r
564         public class Indirection : Expression, IMemoryLocation, IAssignMethod {\r
565                 Expression expr;\r
566                 LocalTemporary temporary;\r
567                 bool have_temporary;\r
568                 \r
569                 public Indirection (Expression expr, Location l)\r
570                 {\r
571                         this.expr = expr;\r
572                         this.type = TypeManager.TypeToCoreType (expr.Type.GetElementType ());\r
573                         eclass = ExprClass.Variable;\r
574                         loc = l;\r
575                 }\r
576 \r
577                 void LoadExprValue (EmitContext ec)\r
578                 {\r
579                 }\r
580                 \r
581                 public override void Emit (EmitContext ec)\r
582                 {\r
583                         ILGenerator ig = ec.ig;\r
584 \r
585                         if (temporary != null){\r
586                                 if (have_temporary){\r
587                                         temporary.Emit (ec);\r
588                                         return;\r
589                                 }\r
590                                 expr.Emit (ec);\r
591                                 ec.ig.Emit (OpCodes.Dup);\r
592                                 temporary.Store (ec);\r
593                                 have_temporary = true;\r
594                         } else\r
595                                 expr.Emit (ec);\r
596                         \r
597                         LoadFromPtr (ig, Type);\r
598                 }\r
599 \r
600                 public void EmitAssign (EmitContext ec, Expression source)\r
601                 {\r
602                         if (temporary != null){\r
603                                 if (have_temporary){\r
604                                         temporary.Emit (ec);\r
605                                         return;\r
606                                 }\r
607                                 expr.Emit (ec);\r
608                                 ec.ig.Emit (OpCodes.Dup);\r
609                                 temporary.Store (ec);\r
610                                 have_temporary = true;\r
611                         } else\r
612                                 expr.Emit (ec);\r
613 \r
614                         source.Emit (ec);\r
615                         StoreFromPtr (ec.ig, type);\r
616                 }\r
617                 \r
618                 public void AddressOf (EmitContext ec, AddressOp Mode)\r
619                 {\r
620                         if (temporary != null){\r
621                                 if (have_temporary){\r
622                                         temporary.Emit (ec);\r
623                                         return;\r
624                                 }\r
625                                 expr.Emit (ec);\r
626                                 ec.ig.Emit (OpCodes.Dup);\r
627                                 temporary.Store (ec);\r
628                                 have_temporary = true;\r
629                         } else\r
630                                 expr.Emit (ec);\r
631                 }\r
632 \r
633                 public override Expression DoResolve (EmitContext ec)\r
634                 {\r
635                         //\r
636                         // Born fully resolved\r
637                         //\r
638                         return this;\r
639                 }\r
640 \r
641                 public new void CacheTemporaries (EmitContext ec)\r
642                 {\r
643                         temporary = new LocalTemporary (ec, type);\r
644                 }\r
645         }\r
646         \r
647         /// <summary>\r
648         ///   Unary Mutator expressions (pre and post ++ and --)\r
649         /// </summary>\r
650         ///\r
651         /// <remarks>\r
652         ///   UnaryMutator implements ++ and -- expressions.   It derives from\r
653         ///   ExpressionStatement becuase the pre/post increment/decrement\r
654         ///   operators can be used in a statement context.\r
655         ///\r
656         /// FIXME: Idea, we could split this up in two classes, one simpler\r
657         /// for the common case, and one with the extra fields for more complex\r
658         /// classes (indexers require temporary access;  overloaded require method)\r
659         ///\r
660         /// Maybe we should have classes PreIncrement, PostIncrement, PreDecrement,\r
661         /// PostDecrement, that way we could save the 'Mode' byte as well.  \r
662         /// </remarks>\r
663         public class UnaryMutator : ExpressionStatement {\r
664                 public enum Mode : byte {\r
665                         PreIncrement, PreDecrement, PostIncrement, PostDecrement\r
666                 }\r
667                 \r
668                 Mode mode;\r
669                 Expression expr;\r
670                 LocalTemporary temp_storage;\r
671 \r
672                 //\r
673                 // This is expensive for the simplest case.\r
674                 //\r
675                 Expression method;\r
676                         \r
677                 public UnaryMutator (Mode m, Expression e, Location l)\r
678                 {\r
679                         mode = m;\r
680                         loc = l;\r
681                         expr = e;\r
682                 }\r
683 \r
684                 static string OperName (Mode mode)\r
685                 {\r
686                         return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?\r
687                                 "++" : "--";\r
688                 }\r
689                 \r
690                 void Error23 (Type t)\r
691                 {\r
692                         Error (\r
693                                 23, "Operator " + OperName (mode) + \r
694                                 " cannot be applied to operand of type '" +\r
695                                 TypeManager.CSharpName (t) + "'");\r
696                 }\r
697 \r
698                 /// <summary>\r
699                 ///   Returns whether an object of type 't' can be incremented\r
700                 ///   or decremented with add/sub (ie, basically whether we can\r
701                 ///   use pre-post incr-decr operations on it, but it is not a\r
702                 ///   System.Decimal, which we require operator overloading to catch)\r
703                 /// </summary>\r
704                 static bool IsIncrementableNumber (Type t)\r
705                 {\r
706                         return (t == TypeManager.sbyte_type) ||\r
707                                 (t == TypeManager.byte_type) ||\r
708                                 (t == TypeManager.short_type) ||\r
709                                 (t == TypeManager.ushort_type) ||\r
710                                 (t == TypeManager.int32_type) ||\r
711                                 (t == TypeManager.uint32_type) ||\r
712                                 (t == TypeManager.int64_type) ||\r
713                                 (t == TypeManager.uint64_type) ||\r
714                                 (t == TypeManager.char_type) ||\r
715                                 (t.IsSubclassOf (TypeManager.enum_type)) ||\r
716                                 (t == TypeManager.float_type) ||\r
717                                 (t == TypeManager.double_type) ||\r
718                                 (t.IsPointer && t != TypeManager.void_ptr_type);\r
719                 }\r
720 \r
721                 Expression ResolveOperator (EmitContext ec)\r
722                 {\r
723                         Type expr_type = expr.Type;\r
724 \r
725                         //\r
726                         // Step 1: Perform Operator Overload location\r
727                         //\r
728                         Expression mg;\r
729                         string op_name;\r
730                         \r
731                         if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)\r
732                                 op_name = "op_Increment";\r
733                         else \r
734                                 op_name = "op_Decrement";\r
735 \r
736                         mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);\r
737 \r
738                         if (mg == null && expr_type.BaseType != null)\r
739                                 mg = MemberLookup (ec, expr_type.BaseType, op_name,\r
740                                                    MemberTypes.Method, AllBindingFlags, loc);\r
741                         \r
742                         if (mg != null) {\r
743                                 method = StaticCallExpr.MakeSimpleCall (\r
744                                         ec, (MethodGroupExpr) mg, expr, loc);\r
745 \r
746                                 type = method.Type;\r
747                                 return this;\r
748                         }\r
749 \r
750                         //\r
751                         // The operand of the prefix/postfix increment decrement operators\r
752                         // should be an expression that is classified as a variable,\r
753                         // a property access or an indexer access\r
754                         //\r
755                         type = expr_type;\r
756                         if (expr.eclass == ExprClass.Variable){\r
757                                 if (IsIncrementableNumber (expr_type) ||\r
758                                     expr_type == TypeManager.decimal_type){\r
759                                         return this;\r
760                                 }\r
761                         } else if (expr.eclass == ExprClass.IndexerAccess){\r
762                                 IndexerAccess ia = (IndexerAccess) expr;\r
763                                 \r
764                                 temp_storage = new LocalTemporary (ec, expr.Type);\r
765                                 \r
766                                 expr = ia.ResolveLValue (ec, temp_storage);\r
767                                 if (expr == null)\r
768                                         return null;\r
769 \r
770                                 return this;\r
771                         } else if (expr.eclass == ExprClass.PropertyAccess){\r
772                                 PropertyExpr pe = (PropertyExpr) expr;\r
773 \r
774                                 if (pe.VerifyAssignable ())\r
775                                         return this;\r
776 \r
777                                 return null;\r
778                         } else {\r
779                                 expr.Error118 ("variable, indexer or property access");\r
780                                 return null;\r
781                         }\r
782 \r
783                         Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +\r
784                                TypeManager.CSharpName (expr_type) + "'");\r
785                         return null;\r
786                 }\r
787 \r
788                 public override Expression DoResolve (EmitContext ec)\r
789                 {\r
790                         expr = expr.Resolve (ec);\r
791                         \r
792                         if (expr == null)\r
793                                 return null;\r
794 \r
795                         eclass = ExprClass.Value;\r
796                         return ResolveOperator (ec);\r
797                 }\r
798 \r
799                 static int PtrTypeSize (Type t)\r
800                 {\r
801                         return GetTypeSize (t.GetElementType ());\r
802                 }\r
803 \r
804                 //\r
805                 // Loads the proper "1" into the stack based on the type\r
806                 //\r
807                 static void LoadOne (ILGenerator ig, Type t)\r
808                 {\r
809                         if (t == TypeManager.uint64_type || t == TypeManager.int64_type)\r
810                                 ig.Emit (OpCodes.Ldc_I8, 1L);\r
811                         else if (t == TypeManager.double_type)\r
812                                 ig.Emit (OpCodes.Ldc_R8, 1.0);\r
813                         else if (t == TypeManager.float_type)\r
814                                 ig.Emit (OpCodes.Ldc_R4, 1.0F);\r
815                         else if (t.IsPointer){\r
816                                 int n = PtrTypeSize (t);\r
817                                 \r
818                                 if (n == 0)\r
819                                         ig.Emit (OpCodes.Sizeof, t);\r
820                                 else\r
821                                         IntConstant.EmitInt (ig, n);\r
822                         } else \r
823                                 ig.Emit (OpCodes.Ldc_I4_1);\r
824                 }\r
825 \r
826                 \r
827                 //\r
828                 // FIXME: We need some way of avoiding the use of temp_storage\r
829                 // for some types of storage (parameters, local variables,\r
830                 // static fields) and single-dimension array access.\r
831                 //\r
832                 void EmitCode (EmitContext ec, bool is_expr)\r
833                 {\r
834                         ILGenerator ig = ec.ig;\r
835                         IAssignMethod ia = (IAssignMethod) expr;\r
836                         Type expr_type = expr.Type;\r
837                         \r
838                         if (temp_storage == null)\r
839                                 temp_storage = new LocalTemporary (ec, expr_type);\r
840 \r
841                         ia.CacheTemporaries (ec);\r
842                         ig.Emit (OpCodes.Nop);\r
843                         switch (mode){\r
844                         case Mode.PreIncrement:\r
845                         case Mode.PreDecrement:\r
846                                 if (method == null){\r
847                                         expr.Emit (ec);\r
848 \r
849                                         LoadOne (ig, expr_type);\r
850                                         \r
851                                         //\r
852                                         // Select the opcode based on the check state (then the type)\r
853                                         // and the actual operation\r
854                                         //\r
855                                         if (ec.CheckState){\r
856                                                 if (expr_type == TypeManager.int32_type ||\r
857                                                     expr_type == TypeManager.int64_type){\r
858                                                         if (mode == Mode.PreDecrement)\r
859                                                                 ig.Emit (OpCodes.Sub_Ovf);\r
860                                                         else\r
861                                                                 ig.Emit (OpCodes.Add_Ovf);\r
862                                                 } else if (expr_type == TypeManager.uint32_type ||\r
863                                                            expr_type == TypeManager.uint64_type){\r
864                                                         if (mode == Mode.PreDecrement)\r
865                                                                 ig.Emit (OpCodes.Sub_Ovf_Un);\r
866                                                         else\r
867                                                                 ig.Emit (OpCodes.Add_Ovf_Un);\r
868                                                 } else {\r
869                                                         if (mode == Mode.PreDecrement)\r
870                                                                 ig.Emit (OpCodes.Sub_Ovf);\r
871                                                         else\r
872                                                                 ig.Emit (OpCodes.Add_Ovf);\r
873                                                 }\r
874                                         } else {\r
875                                                 if (mode == Mode.PreDecrement)\r
876                                                         ig.Emit (OpCodes.Sub);\r
877                                                 else\r
878                                                         ig.Emit (OpCodes.Add);\r
879                                         }\r
880                                 } else \r
881                                         method.Emit (ec);\r
882 \r
883                                 temp_storage.Store (ec);\r
884                                 ia.EmitAssign (ec, temp_storage);\r
885                                 if (is_expr)\r
886                                         temp_storage.Emit (ec);\r
887                                 break;\r
888                                 \r
889                         case Mode.PostIncrement:\r
890                         case Mode.PostDecrement:\r
891                                 if (is_expr)\r
892                                         expr.Emit (ec);\r
893                                 \r
894                                 if (method == null){\r
895                                         if (!is_expr)\r
896                                                 expr.Emit (ec);\r
897                                         else\r
898                                                 ig.Emit (OpCodes.Dup);\r
899 \r
900                                         LoadOne (ig, expr_type);\r
901                                         \r
902                                         if (ec.CheckState){\r
903                                                 if (expr_type == TypeManager.int32_type ||\r
904                                                     expr_type == TypeManager.int64_type){\r
905                                                         if (mode == Mode.PostDecrement)\r
906                                                                 ig.Emit (OpCodes.Sub_Ovf);\r
907                                                         else\r
908                                                                 ig.Emit (OpCodes.Add_Ovf);\r
909                                                 } else if (expr_type == TypeManager.uint32_type ||\r
910                                                            expr_type == TypeManager.uint64_type){\r
911                                                         if (mode == Mode.PostDecrement)\r
912                                                                 ig.Emit (OpCodes.Sub_Ovf_Un);\r
913                                                         else\r
914                                                                 ig.Emit (OpCodes.Add_Ovf_Un);\r
915                                                 } else {\r
916                                                         if (mode == Mode.PostDecrement)\r
917                                                                 ig.Emit (OpCodes.Sub_Ovf);\r
918                                                         else\r
919                                                                 ig.Emit (OpCodes.Add_Ovf);\r
920                                                 }\r
921                                         } else {\r
922                                                 if (mode == Mode.PostDecrement)\r
923                                                         ig.Emit (OpCodes.Sub);\r
924                                                 else\r
925                                                         ig.Emit (OpCodes.Add);\r
926                                         }\r
927                                 } else {\r
928                                         method.Emit (ec);\r
929                                 }\r
930                                 \r
931                                 temp_storage.Store (ec);\r
932                                 ia.EmitAssign (ec, temp_storage);\r
933                                 break;\r
934                         }\r
935                 }\r
936 \r
937                 public override void Emit (EmitContext ec)\r
938                 {\r
939                         EmitCode (ec, true);\r
940                         \r
941                 }\r
942                 \r
943                 public override void EmitStatement (EmitContext ec)\r
944                 {\r
945                         EmitCode (ec, false);\r
946                 }\r
947 \r
948         }\r
949 \r
950         /// <summary>\r
951         ///   Base class for the 'Is' and 'As' classes. \r
952         /// </summary>\r
953         ///\r
954         /// <remarks>\r
955         ///   FIXME: Split this in two, and we get to save the 'Operator' Oper\r
956         ///   size. \r
957         /// </remarks>\r
958         public abstract class Probe : Expression {\r
959                 public readonly Expression ProbeType;\r
960                 protected Expression expr;\r
961                 protected Type probe_type;\r
962                 \r
963                 public Probe (Expression expr, Expression probe_type, Location l)\r
964                 {\r
965                         ProbeType = probe_type;\r
966                         loc = l;\r
967                         this.expr = expr;\r
968                 }\r
969 \r
970                 public Expression Expr {\r
971                         get {\r
972                                 return expr;\r
973                         }\r
974                 }\r
975 \r
976                 public override Expression DoResolve (EmitContext ec)\r
977                 {\r
978                         probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);\r
979 \r
980                         if (probe_type == null)\r
981                                 return null;\r
982 \r
983                         expr = expr.Resolve (ec);\r
984                         \r
985                         return this;\r
986                 }\r
987         }\r
988 \r
989         /// <summary>\r
990         ///   Implementation of the 'is' operator.\r
991         /// </summary>\r
992         public class Is : Probe {\r
993                 public Is (Expression expr, Expression probe_type, Location l)\r
994                         : base (expr, probe_type, l)\r
995                 {\r
996                 }\r
997 \r
998                 enum Action {\r
999                         AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe\r
1000                 }\r
1001 \r
1002                 Action action;\r
1003                 \r
1004                 public override void Emit (EmitContext ec)\r
1005                 {\r
1006                         ILGenerator ig = ec.ig;\r
1007 \r
1008                         expr.Emit (ec);\r
1009 \r
1010                         switch (action){\r
1011                         case Action.AlwaysFalse:\r
1012                                 ig.Emit (OpCodes.Pop);\r
1013                                 IntConstant.EmitInt (ig, 0);\r
1014                                 return;\r
1015                         case Action.AlwaysTrue:\r
1016                                 ig.Emit (OpCodes.Pop);\r
1017                                 ig.Emit (OpCodes.Nop);\r
1018                                 IntConstant.EmitInt (ig, 1);\r
1019                                 return;\r
1020                         case Action.LeaveOnStack:\r
1021                                 // the 'e != null' rule.\r
1022                                 return;\r
1023                         case Action.Probe:\r
1024                                 ig.Emit (OpCodes.Isinst, probe_type);\r
1025                                 ig.Emit (OpCodes.Ldnull);\r
1026                                 ig.Emit (OpCodes.Cgt_Un);\r
1027                                 return;\r
1028                         }\r
1029                         throw new Exception ("never reached");\r
1030                 }\r
1031 \r
1032                 public override Expression DoResolve (EmitContext ec)\r
1033                 {\r
1034                         Expression e = base.DoResolve (ec);\r
1035 \r
1036                         if ((e == null) || (expr == null))\r
1037                                 return null;\r
1038 \r
1039                         Type etype = expr.Type;\r
1040                         bool warning_always_matches = false;\r
1041                         bool warning_never_matches = false;\r
1042 \r
1043                         type = TypeManager.bool_type;\r
1044                         eclass = ExprClass.Value;\r
1045 \r
1046                         //\r
1047                         // First case, if at compile time, there is an implicit conversion\r
1048                         // then e != null (objects) or true (value types)\r
1049                         //\r
1050                         e = ConvertImplicitStandard (ec, expr, probe_type, loc);\r
1051                         if (e != null){\r
1052                                 expr = e;\r
1053                                 if (etype.IsValueType)\r
1054                                         action = Action.AlwaysTrue;\r
1055                                 else\r
1056                                         action = Action.LeaveOnStack;\r
1057 \r
1058                                 warning_always_matches = true;\r
1059                         } else if (ExplicitReferenceConversionExists (etype, probe_type)){\r
1060                                 //\r
1061                                 // Second case: explicit reference convresion\r
1062                                 //\r
1063                                 if (expr is NullLiteral)\r
1064                                         action = Action.AlwaysFalse;\r
1065                                 else\r
1066                                         action = Action.Probe;\r
1067                         } else {\r
1068                                 action = Action.AlwaysFalse;\r
1069                                 warning_never_matches = true;\r
1070                         }\r
1071                         \r
1072                         if (RootContext.WarningLevel >= 1){\r
1073                                 if (warning_always_matches)\r
1074                                         Warning (\r
1075                                                 183,\r
1076                                                 "The expression is always of type '" +\r
1077                                                 TypeManager.CSharpName (probe_type) + "'");\r
1078                                 else if (warning_never_matches){\r
1079                                         if (!(probe_type.IsInterface || expr.Type.IsInterface))\r
1080                                                 Warning (\r
1081                                                         184,\r
1082                                                         "The expression is never of type '" +\r
1083                                                         TypeManager.CSharpName (probe_type) + "'");\r
1084                                 }\r
1085                         }\r
1086 \r
1087                         return this;\r
1088                 }                               \r
1089         }\r
1090 \r
1091         /// <summary>\r
1092         ///   Implementation of the 'as' operator.\r
1093         /// </summary>\r
1094         public class As : Probe {\r
1095                 public As (Expression expr, Expression probe_type, Location l)\r
1096                         : base (expr, probe_type, l)\r
1097                 {\r
1098                 }\r
1099 \r
1100                 bool do_isinst = false;\r
1101                 \r
1102                 public override void Emit (EmitContext ec)\r
1103                 {\r
1104                         ILGenerator ig = ec.ig;\r
1105 \r
1106                         expr.Emit (ec);\r
1107 \r
1108                         if (do_isinst)\r
1109                                 ig.Emit (OpCodes.Isinst, probe_type);\r
1110                 }\r
1111 \r
1112                 static void Error_CannotConvertType (Type source, Type target, Location loc)\r
1113                 {\r
1114                         Report.Error (\r
1115                                 39, loc, "as operator can not convert from '" +\r
1116                                 TypeManager.CSharpName (source) + "' to '" +\r
1117                                 TypeManager.CSharpName (target) + "'");\r
1118                 }\r
1119                 \r
1120                 public override Expression DoResolve (EmitContext ec)\r
1121                 {\r
1122                         Expression e = base.DoResolve (ec);\r
1123 \r
1124                         if (e == null)\r
1125                                 return null;\r
1126 \r
1127                         type = probe_type;\r
1128                         eclass = ExprClass.Value;\r
1129                         Type etype = expr.Type;\r
1130 \r
1131                         if (TypeManager.IsValueType (probe_type)){\r
1132                                 Report.Error (77, loc, "The as operator should be used with a reference type only (" +\r
1133                                               TypeManager.CSharpName (probe_type) + " is a value type");\r
1134                                 return null;\r
1135                         \r
1136                         }\r
1137                         \r
1138                         e = ConvertImplicit (ec, expr, probe_type, loc);\r
1139                         if (e != null){\r
1140                                 expr = e;\r
1141                                 do_isinst = false;\r
1142                                 return this;\r
1143                         }\r
1144 \r
1145                         if (ExplicitReferenceConversionExists (etype, probe_type)){\r
1146                                 do_isinst = true;\r
1147                                 return this;\r
1148                         }\r
1149 \r
1150                         Error_CannotConvertType (etype, probe_type, loc);\r
1151                         return null;\r
1152                 }                               \r
1153         }\r
1154         \r
1155         /// <summary>\r
1156         ///   This represents a typecast in the source language.\r
1157         ///\r
1158         ///   FIXME: Cast expressions have an unusual set of parsing\r
1159         ///   rules, we need to figure those out.\r
1160         /// </summary>\r
1161         public class Cast : Expression {\r
1162                 Expression target_type;\r
1163                 Expression expr;\r
1164                         \r
1165                 public Cast (Expression cast_type, Expression expr, Location loc)\r
1166                 {\r
1167                         this.target_type = cast_type;\r
1168                         this.expr = expr;\r
1169                         this.loc = loc;\r
1170                 }\r
1171 \r
1172                 public Expression TargetType {\r
1173                         get {\r
1174                                 return target_type;\r
1175                         }\r
1176                 }\r
1177 \r
1178                 public Expression Expr {\r
1179                         get {\r
1180                                 return expr;\r
1181                         }\r
1182                         set {\r
1183                                 expr = value;\r
1184                         }\r
1185                 }\r
1186 \r
1187                 /// <summary>\r
1188                 ///   Attempts to do a compile-time folding of a constant cast.\r
1189                 /// </summary>\r
1190                 Expression TryReduce (EmitContext ec, Type target_type)\r
1191                 {\r
1192                         if (expr is ByteConstant){\r
1193                                 byte v = ((ByteConstant) expr).Value;\r
1194         \r
1195                                 if (target_type == TypeManager.sbyte_type)\r
1196                                         return new SByteConstant ((sbyte) v);\r
1197                                 if (target_type == TypeManager.short_type)\r
1198                                         return new ShortConstant ((short) v);\r
1199                                 if (target_type == TypeManager.ushort_type)\r
1200                                         return new UShortConstant ((ushort) v);\r
1201                                 if (target_type == TypeManager.int32_type)\r
1202                                         return new IntConstant ((int) v);\r
1203                                 if (target_type == TypeManager.uint32_type)\r
1204                                         return new UIntConstant ((uint) v);\r
1205                                 if (target_type == TypeManager.int64_type)\r
1206                                         return new LongConstant ((long) v);\r
1207                                 if (target_type == TypeManager.uint64_type)\r
1208                                         return new ULongConstant ((ulong) v);\r
1209                                 if (target_type == TypeManager.float_type)\r
1210                                         return new FloatConstant ((float) v);\r
1211                                 if (target_type == TypeManager.double_type)\r
1212                                         return new DoubleConstant ((double) v);\r
1213                                 if (target_type == TypeManager.char_type)\r
1214                                         return new CharConstant ((char) v);\r
1215                                 if (target_type == TypeManager.decimal_type)\r
1216                                         return new DecimalConstant ((decimal) v);\r
1217                         }\r
1218                         if (expr is SByteConstant){\r
1219                                 sbyte v = ((SByteConstant) expr).Value;\r
1220         \r
1221                                 if (target_type == TypeManager.byte_type)\r
1222                                         return new ByteConstant ((byte) v);\r
1223                                 if (target_type == TypeManager.short_type)\r
1224                                         return new ShortConstant ((short) v);\r
1225                                 if (target_type == TypeManager.ushort_type)\r
1226                                         return new UShortConstant ((ushort) v);\r
1227                                 if (target_type == TypeManager.int32_type)\r
1228                                         return new IntConstant ((int) v);\r
1229                                 if (target_type == TypeManager.uint32_type)\r
1230                                         return new UIntConstant ((uint) v);\r
1231                                 if (target_type == TypeManager.int64_type)\r
1232                                         return new LongConstant ((long) v);\r
1233                                 if (target_type == TypeManager.uint64_type)\r
1234                                         return new ULongConstant ((ulong) v);\r
1235                                 if (target_type == TypeManager.float_type)\r
1236                                         return new FloatConstant ((float) v);\r
1237                                 if (target_type == TypeManager.double_type)\r
1238                                         return new DoubleConstant ((double) v);\r
1239                                 if (target_type == TypeManager.char_type)\r
1240                                         return new CharConstant ((char) v);\r
1241                                 if (target_type == TypeManager.decimal_type)\r
1242                                         return new DecimalConstant ((decimal) v);\r
1243                         }\r
1244                         if (expr is ShortConstant){\r
1245                                 short v = ((ShortConstant) expr).Value;\r
1246         \r
1247                                 if (target_type == TypeManager.byte_type)\r
1248                                         return new ByteConstant ((byte) v);\r
1249                                 if (target_type == TypeManager.sbyte_type)\r
1250                                         return new SByteConstant ((sbyte) v);\r
1251                                 if (target_type == TypeManager.ushort_type)\r
1252                                         return new UShortConstant ((ushort) v);\r
1253                                 if (target_type == TypeManager.int32_type)\r
1254                                         return new IntConstant ((int) v);\r
1255                                 if (target_type == TypeManager.uint32_type)\r
1256                                         return new UIntConstant ((uint) v);\r
1257                                 if (target_type == TypeManager.int64_type)\r
1258                                         return new LongConstant ((long) v);\r
1259                                 if (target_type == TypeManager.uint64_type)\r
1260                                         return new ULongConstant ((ulong) v);\r
1261                                 if (target_type == TypeManager.float_type)\r
1262                                         return new FloatConstant ((float) v);\r
1263                                 if (target_type == TypeManager.double_type)\r
1264                                         return new DoubleConstant ((double) v);\r
1265                                 if (target_type == TypeManager.char_type)\r
1266                                         return new CharConstant ((char) v);\r
1267                                 if (target_type == TypeManager.decimal_type)\r
1268                                         return new DecimalConstant ((decimal) v);\r
1269                         }\r
1270                         if (expr is UShortConstant){\r
1271                                 ushort v = ((UShortConstant) expr).Value;\r
1272         \r
1273                                 if (target_type == TypeManager.byte_type)\r
1274                                         return new ByteConstant ((byte) v);\r
1275                                 if (target_type == TypeManager.sbyte_type)\r
1276                                         return new SByteConstant ((sbyte) v);\r
1277                                 if (target_type == TypeManager.short_type)\r
1278                                         return new ShortConstant ((short) v);\r
1279                                 if (target_type == TypeManager.int32_type)\r
1280                                         return new IntConstant ((int) v);\r
1281                                 if (target_type == TypeManager.uint32_type)\r
1282                                         return new UIntConstant ((uint) v);\r
1283                                 if (target_type == TypeManager.int64_type)\r
1284                                         return new LongConstant ((long) v);\r
1285                                 if (target_type == TypeManager.uint64_type)\r
1286                                         return new ULongConstant ((ulong) v);\r
1287                                 if (target_type == TypeManager.float_type)\r
1288                                         return new FloatConstant ((float) v);\r
1289                                 if (target_type == TypeManager.double_type)\r
1290                                         return new DoubleConstant ((double) v);\r
1291                                 if (target_type == TypeManager.char_type)\r
1292                                         return new CharConstant ((char) v);\r
1293                                 if (target_type == TypeManager.decimal_type)\r
1294                                         return new DecimalConstant ((decimal) v);\r
1295                         }\r
1296                         if (expr is IntConstant){\r
1297                                 int v = ((IntConstant) expr).Value;\r
1298         \r
1299                                 if (target_type == TypeManager.byte_type)\r
1300                                         return new ByteConstant ((byte) v);\r
1301                                 if (target_type == TypeManager.sbyte_type)\r
1302                                         return new SByteConstant ((sbyte) v);\r
1303                                 if (target_type == TypeManager.short_type)\r
1304                                         return new ShortConstant ((short) v);\r
1305                                 if (target_type == TypeManager.ushort_type)\r
1306                                         return new UShortConstant ((ushort) v);\r
1307                                 if (target_type == TypeManager.uint32_type)\r
1308                                         return new UIntConstant ((uint) v);\r
1309                                 if (target_type == TypeManager.int64_type)\r
1310                                         return new LongConstant ((long) v);\r
1311                                 if (target_type == TypeManager.uint64_type)\r
1312                                         return new ULongConstant ((ulong) v);\r
1313                                 if (target_type == TypeManager.float_type)\r
1314                                         return new FloatConstant ((float) v);\r
1315                                 if (target_type == TypeManager.double_type)\r
1316                                         return new DoubleConstant ((double) v);\r
1317                                 if (target_type == TypeManager.char_type)\r
1318                                         return new CharConstant ((char) v);\r
1319                                 if (target_type == TypeManager.decimal_type)\r
1320                                         return new DecimalConstant ((decimal) v);\r
1321                         }\r
1322                         if (expr is UIntConstant){\r
1323                                 uint v = ((UIntConstant) expr).Value;\r
1324         \r
1325                                 if (target_type == TypeManager.byte_type)\r
1326                                         return new ByteConstant ((byte) v);\r
1327                                 if (target_type == TypeManager.sbyte_type)\r
1328                                         return new SByteConstant ((sbyte) v);\r
1329                                 if (target_type == TypeManager.short_type)\r
1330                                         return new ShortConstant ((short) v);\r
1331                                 if (target_type == TypeManager.ushort_type)\r
1332                                         return new UShortConstant ((ushort) v);\r
1333                                 if (target_type == TypeManager.int32_type)\r
1334                                         return new IntConstant ((int) v);\r
1335                                 if (target_type == TypeManager.int64_type)\r
1336                                         return new LongConstant ((long) v);\r
1337                                 if (target_type == TypeManager.uint64_type)\r
1338                                         return new ULongConstant ((ulong) v);\r
1339                                 if (target_type == TypeManager.float_type)\r
1340                                         return new FloatConstant ((float) v);\r
1341                                 if (target_type == TypeManager.double_type)\r
1342                                         return new DoubleConstant ((double) v);\r
1343                                 if (target_type == TypeManager.char_type)\r
1344                                         return new CharConstant ((char) v);\r
1345                                 if (target_type == TypeManager.decimal_type)\r
1346                                         return new DecimalConstant ((decimal) v);\r
1347                         }\r
1348                         if (expr is LongConstant){\r
1349                                 long v = ((LongConstant) expr).Value;\r
1350         \r
1351                                 if (target_type == TypeManager.byte_type)\r
1352                                         return new ByteConstant ((byte) v);\r
1353                                 if (target_type == TypeManager.sbyte_type)\r
1354                                         return new SByteConstant ((sbyte) v);\r
1355                                 if (target_type == TypeManager.short_type)\r
1356                                         return new ShortConstant ((short) v);\r
1357                                 if (target_type == TypeManager.ushort_type)\r
1358                                         return new UShortConstant ((ushort) v);\r
1359                                 if (target_type == TypeManager.int32_type)\r
1360                                         return new IntConstant ((int) v);\r
1361                                 if (target_type == TypeManager.uint32_type)\r
1362                                         return new UIntConstant ((uint) v);\r
1363                                 if (target_type == TypeManager.uint64_type)\r
1364                                         return new ULongConstant ((ulong) v);\r
1365                                 if (target_type == TypeManager.float_type)\r
1366                                         return new FloatConstant ((float) v);\r
1367                                 if (target_type == TypeManager.double_type)\r
1368                                         return new DoubleConstant ((double) v);\r
1369                                 if (target_type == TypeManager.char_type)\r
1370                                         return new CharConstant ((char) v);\r
1371                                 if (target_type == TypeManager.decimal_type)\r
1372                                         return new DecimalConstant ((decimal) v);\r
1373                         }\r
1374                         if (expr is ULongConstant){\r
1375                                 ulong v = ((ULongConstant) expr).Value;\r
1376         \r
1377                                 if (target_type == TypeManager.byte_type)\r
1378                                         return new ByteConstant ((byte) v);\r
1379                                 if (target_type == TypeManager.sbyte_type)\r
1380                                         return new SByteConstant ((sbyte) v);\r
1381                                 if (target_type == TypeManager.short_type)\r
1382                                         return new ShortConstant ((short) v);\r
1383                                 if (target_type == TypeManager.ushort_type)\r
1384                                         return new UShortConstant ((ushort) v);\r
1385                                 if (target_type == TypeManager.int32_type)\r
1386                                         return new IntConstant ((int) v);\r
1387                                 if (target_type == TypeManager.uint32_type)\r
1388                                         return new UIntConstant ((uint) v);\r
1389                                 if (target_type == TypeManager.int64_type)\r
1390                                         return new LongConstant ((long) v);\r
1391                                 if (target_type == TypeManager.float_type)\r
1392                                         return new FloatConstant ((float) v);\r
1393                                 if (target_type == TypeManager.double_type)\r
1394                                         return new DoubleConstant ((double) v);\r
1395                                 if (target_type == TypeManager.char_type)\r
1396                                         return new CharConstant ((char) v);\r
1397                                 if (target_type == TypeManager.decimal_type)\r
1398                                         return new DecimalConstant ((decimal) v);\r
1399                         }\r
1400                         if (expr is FloatConstant){\r
1401                                 float v = ((FloatConstant) expr).Value;\r
1402         \r
1403                                 if (target_type == TypeManager.byte_type)\r
1404                                         return new ByteConstant ((byte) v);\r
1405                                 if (target_type == TypeManager.sbyte_type)\r
1406                                         return new SByteConstant ((sbyte) v);\r
1407                                 if (target_type == TypeManager.short_type)\r
1408                                         return new ShortConstant ((short) v);\r
1409                                 if (target_type == TypeManager.ushort_type)\r
1410                                         return new UShortConstant ((ushort) v);\r
1411                                 if (target_type == TypeManager.int32_type)\r
1412                                         return new IntConstant ((int) v);\r
1413                                 if (target_type == TypeManager.uint32_type)\r
1414                                         return new UIntConstant ((uint) v);\r
1415                                 if (target_type == TypeManager.int64_type)\r
1416                                         return new LongConstant ((long) v);\r
1417                                 if (target_type == TypeManager.uint64_type)\r
1418                                         return new ULongConstant ((ulong) v);\r
1419                                 if (target_type == TypeManager.double_type)\r
1420                                         return new DoubleConstant ((double) v);\r
1421                                 if (target_type == TypeManager.char_type)\r
1422                                         return new CharConstant ((char) v);\r
1423                                 if (target_type == TypeManager.decimal_type)\r
1424                                         return new DecimalConstant ((decimal) v);\r
1425                         }\r
1426                         if (expr is DoubleConstant){\r
1427                                 double v = ((DoubleConstant) expr).Value;\r
1428         \r
1429                                 if (target_type == TypeManager.byte_type)\r
1430                                         return new ByteConstant ((byte) v);\r
1431                                 if (target_type == TypeManager.sbyte_type)\r
1432                                         return new SByteConstant ((sbyte) v);\r
1433                                 if (target_type == TypeManager.short_type)\r
1434                                         return new ShortConstant ((short) v);\r
1435                                 if (target_type == TypeManager.ushort_type)\r
1436                                         return new UShortConstant ((ushort) v);\r
1437                                 if (target_type == TypeManager.int32_type)\r
1438                                         return new IntConstant ((int) v);\r
1439                                 if (target_type == TypeManager.uint32_type)\r
1440                                         return new UIntConstant ((uint) v);\r
1441                                 if (target_type == TypeManager.int64_type)\r
1442                                         return new LongConstant ((long) v);\r
1443                                 if (target_type == TypeManager.uint64_type)\r
1444                                         return new ULongConstant ((ulong) v);\r
1445                                 if (target_type == TypeManager.float_type)\r
1446                                         return new FloatConstant ((float) v);\r
1447                                 if (target_type == TypeManager.char_type)\r
1448                                         return new CharConstant ((char) v);\r
1449                                 if (target_type == TypeManager.decimal_type)\r
1450                                         return new DecimalConstant ((decimal) v);\r
1451                         }\r
1452 \r
1453                         return null;\r
1454                 }\r
1455                 \r
1456                 public override Expression DoResolve (EmitContext ec)\r
1457                 {\r
1458                         expr = expr.Resolve (ec);\r
1459                         if (expr == null)\r
1460                                 return null;\r
1461 \r
1462                         int errors = Report.Errors;\r
1463 \r
1464                         type = ec.DeclSpace.ResolveType (target_type, false, Location);\r
1465                         \r
1466                         if (type == null)\r
1467                                 return null;\r
1468 \r
1469                         eclass = ExprClass.Value;\r
1470                         \r
1471                         if (expr is Constant){\r
1472                                 Expression e = TryReduce (ec, type);\r
1473 \r
1474                                 if (e != null)\r
1475                                         return e;\r
1476                         }\r
1477                         \r
1478                         expr = ConvertExplicit (ec, expr, type, loc);\r
1479                         return expr;\r
1480                 }\r
1481 \r
1482                 public override void Emit (EmitContext ec)\r
1483                 {\r
1484                         //\r
1485                         // This one will never happen\r
1486                         //\r
1487                         throw new Exception ("Should not happen");\r
1488                 }\r
1489         }\r
1490 \r
1491         /// <summary>\r
1492         ///   Binary operators\r
1493         /// </summary>\r
1494         public class Binary : Expression {\r
1495                 public enum Operator : byte {\r
1496                         Multiply, Division, Modulus,\r
1497                         Addition, Subtraction,\r
1498                         LeftShift, RightShift,\r
1499                         LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual, \r
1500                         Equality, Inequality,\r
1501                         BitwiseAnd,\r
1502                         ExclusiveOr,\r
1503                         BitwiseOr,\r
1504                         LogicalAnd,\r
1505                         LogicalOr,\r
1506                         TOP\r
1507                 }\r
1508 \r
1509                 Operator oper;\r
1510                 Expression left, right;\r
1511 \r
1512                 //\r
1513                 // After resolution, method might contain the operator overload\r
1514                 // method.\r
1515                 //\r
1516                 protected MethodBase method;\r
1517                 ArrayList  Arguments;\r
1518 \r
1519                 bool DelegateOperation;\r
1520 \r
1521                 // This must be kept in sync with Operator!!!\r
1522                 static string [] oper_names;\r
1523 \r
1524                 static Binary ()\r
1525                 {\r
1526                         oper_names = new string [(int) Operator.TOP];\r
1527 \r
1528                         oper_names [(int) Operator.Multiply] = "op_Multiply";\r
1529                         oper_names [(int) Operator.Division] = "op_Division";\r
1530                         oper_names [(int) Operator.Modulus] = "op_Modulus";\r
1531                         oper_names [(int) Operator.Addition] = "op_Addition";\r
1532                         oper_names [(int) Operator.Subtraction] = "op_Subtraction";\r
1533                         oper_names [(int) Operator.LeftShift] = "op_LeftShift";\r
1534                         oper_names [(int) Operator.RightShift] = "op_RightShift";\r
1535                         oper_names [(int) Operator.LessThan] = "op_LessThan";\r
1536                         oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";\r
1537                         oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";\r
1538                         oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";\r
1539                         oper_names [(int) Operator.Equality] = "op_Equality";\r
1540                         oper_names [(int) Operator.Inequality] = "op_Inequality";\r
1541                         oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";\r
1542                         oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";\r
1543                         oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";\r
1544                         oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";\r
1545                         oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";\r
1546                 }\r
1547 \r
1548                 public Binary (Operator oper, Expression left, Expression right, Location loc)\r
1549                 {\r
1550                         this.oper = oper;\r
1551                         this.left = left;\r
1552                         this.right = right;\r
1553                         this.loc = loc;\r
1554                 }\r
1555 \r
1556                 public Operator Oper {\r
1557                         get {\r
1558                                 return oper;\r
1559                         }\r
1560                         set {\r
1561                                 oper = value;\r
1562                         }\r
1563                 }\r
1564                 \r
1565                 public Expression Left {\r
1566                         get {\r
1567                                 return left;\r
1568                         }\r
1569                         set {\r
1570                                 left = value;\r
1571                         }\r
1572                 }\r
1573 \r
1574                 public Expression Right {\r
1575                         get {\r
1576                                 return right;\r
1577                         }\r
1578                         set {\r
1579                                 right = value;\r
1580                         }\r
1581                 }\r
1582 \r
1583 \r
1584                 /// <summary>\r
1585                 ///   Returns a stringified representation of the Operator\r
1586                 /// </summary>\r
1587                 static string OperName (Operator oper)\r
1588                 {\r
1589                         switch (oper){\r
1590                         case Operator.Multiply:\r
1591                                 return "*";\r
1592                         case Operator.Division:\r
1593                                 return "/";\r
1594                         case Operator.Modulus:\r
1595                                 return "%";\r
1596                         case Operator.Addition:\r
1597                                 return "+";\r
1598                         case Operator.Subtraction:\r
1599                                 return "-";\r
1600                         case Operator.LeftShift:\r
1601                                 return "<<";\r
1602                         case Operator.RightShift:\r
1603                                 return ">>";\r
1604                         case Operator.LessThan:\r
1605                                 return "<";\r
1606                         case Operator.GreaterThan:\r
1607                                 return ">";\r
1608                         case Operator.LessThanOrEqual:\r
1609                                 return "<=";\r
1610                         case Operator.GreaterThanOrEqual:\r
1611                                 return ">=";\r
1612                         case Operator.Equality:\r
1613                                 return "==";\r
1614                         case Operator.Inequality:\r
1615                                 return "!=";\r
1616                         case Operator.BitwiseAnd:\r
1617                                 return "&";\r
1618                         case Operator.BitwiseOr:\r
1619                                 return "|";\r
1620                         case Operator.ExclusiveOr:\r
1621                                 return "^";\r
1622                         case Operator.LogicalOr:\r
1623                                 return "||";\r
1624                         case Operator.LogicalAnd:\r
1625                                 return "&&";\r
1626                         }\r
1627 \r
1628                         return oper.ToString ();\r
1629                 }\r
1630 \r
1631                 public override string ToString ()\r
1632                 {\r
1633                         return "operator " + OperName (oper) + "(" + left.ToString () + ", " +\r
1634                                 right.ToString () + ")";\r
1635                 }\r
1636                 \r
1637                 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)\r
1638                 {\r
1639                         if (expr.Type == target_type)\r
1640                                 return expr;\r
1641 \r
1642                         return ConvertImplicit (ec, expr, target_type, Location.Null);\r
1643                 }\r
1644 \r
1645                 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)\r
1646                 {\r
1647                         Report.Error (\r
1648                                 34, loc, "Operator '" + OperName (oper) \r
1649                                 + "' is ambiguous on operands of type '"\r
1650                                 + TypeManager.CSharpName (l) + "' "\r
1651                                 + "and '" + TypeManager.CSharpName (r)\r
1652                                 + "'");\r
1653                 }\r
1654 \r
1655                 //\r
1656                 // Note that handling the case l == Decimal || r == Decimal\r
1657                 // is taken care of by the Step 1 Operator Overload resolution.\r
1658                 //\r
1659                 bool DoNumericPromotions (EmitContext ec, Type l, Type r)\r
1660                 {\r
1661                         if (l == TypeManager.double_type || r == TypeManager.double_type){\r
1662                                 //\r
1663                                 // If either operand is of type double, the other operand is\r
1664                                 // conveted to type double.\r
1665                                 //\r
1666                                 if (r != TypeManager.double_type)\r
1667                                         right = ConvertImplicit (ec, right, TypeManager.double_type, loc);\r
1668                                 if (l != TypeManager.double_type)\r
1669                                         left = ConvertImplicit (ec, left, TypeManager.double_type, loc);\r
1670                                 \r
1671                                 type = TypeManager.double_type;\r
1672                         } else if (l == TypeManager.float_type || r == TypeManager.float_type){\r
1673                                 //\r
1674                                 // if either operand is of type float, the other operand is\r
1675                                 // converted to type float.\r
1676                                 //\r
1677                                 if (r != TypeManager.double_type)\r
1678                                         right = ConvertImplicit (ec, right, TypeManager.float_type, loc);\r
1679                                 if (l != TypeManager.double_type)\r
1680                                         left = ConvertImplicit (ec, left, TypeManager.float_type, loc);\r
1681                                 type = TypeManager.float_type;\r
1682                         } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){\r
1683                                 Expression e;\r
1684                                 Type other;\r
1685                                 //\r
1686                                 // If either operand is of type ulong, the other operand is\r
1687                                 // converted to type ulong.  or an error ocurrs if the other\r
1688                                 // operand is of type sbyte, short, int or long\r
1689                                 //\r
1690                                 if (l == TypeManager.uint64_type){\r
1691                                         if (r != TypeManager.uint64_type){\r
1692                                                 if (right is IntConstant){\r
1693                                                         IntConstant ic = (IntConstant) right;\r
1694                                                         \r
1695                                                         e = TryImplicitIntConversion (l, ic);\r
1696                                                         if (e != null)\r
1697                                                                 right = e;\r
1698                                                 } else if (right is LongConstant){\r
1699                                                         long ll = ((LongConstant) right).Value;\r
1700 \r
1701                                                         if (ll > 0)\r
1702                                                                 right = new ULongConstant ((ulong) ll);\r
1703                                                 } else {\r
1704                                                         e = ImplicitNumericConversion (ec, right, l, loc);\r
1705                                                         if (e != null)\r
1706                                                                 right = e;\r
1707                                                 }\r
1708                                         }\r
1709                                         other = right.Type;\r
1710                                 } else {\r
1711                                         if (left is IntConstant){\r
1712                                                 e = TryImplicitIntConversion (r, (IntConstant) left);\r
1713                                                 if (e != null)\r
1714                                                         left = e;\r
1715                                         } else if (left is LongConstant){\r
1716                                                 long ll = ((LongConstant) left).Value;\r
1717                                                 \r
1718                                                 if (ll > 0)\r
1719                                                         left = new ULongConstant ((ulong) ll);\r
1720                                         } else {\r
1721                                                 e = ImplicitNumericConversion (ec, left, r, loc);\r
1722                                                 if (e != null)\r
1723                                                         left = e;\r
1724                                         }\r
1725                                         other = left.Type;\r
1726                                 }\r
1727 \r
1728                                 if ((other == TypeManager.sbyte_type) ||\r
1729                                     (other == TypeManager.short_type) ||\r
1730                                     (other == TypeManager.int32_type) ||\r
1731                                     (other == TypeManager.int64_type))\r
1732                                         Error_OperatorAmbiguous (loc, oper, l, r);\r
1733                                 type = TypeManager.uint64_type;\r
1734                         } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){\r
1735                                 //\r
1736                                 // If either operand is of type long, the other operand is converted\r
1737                                 // to type long.\r
1738                                 //\r
1739                                 if (l != TypeManager.int64_type)\r
1740                                         left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);\r
1741                                 if (r != TypeManager.int64_type)\r
1742                                         right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);\r
1743                                 \r
1744                                 type = TypeManager.int64_type;\r
1745                         } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){\r
1746                                 //\r
1747                                 // If either operand is of type uint, and the other\r
1748                                 // operand is of type sbyte, short or int, othe operands are\r
1749                                 // converted to type long.\r
1750                                 //\r
1751                                 Type other = null;\r
1752                                 \r
1753                                 if (l == TypeManager.uint32_type){\r
1754                                         if (right is IntConstant){\r
1755                                                 IntConstant ic = (IntConstant) right;\r
1756                                                 int val = ic.Value;\r
1757                                                 \r
1758                                                 if (val >= 0)\r
1759                                                         right = new UIntConstant ((uint) val);\r
1760 \r
1761                                                 type = l;\r
1762                                                 return true;\r
1763                                         }\r
1764                                         other = r;\r
1765                                 } \r
1766                                 else if (r == TypeManager.uint32_type){\r
1767                                         if (left is IntConstant){\r
1768                                                 IntConstant ic = (IntConstant) left;\r
1769                                                 int val = ic.Value;\r
1770                                                 \r
1771                                                 if (val >= 0)\r
1772                                                         left = new UIntConstant ((uint) val);\r
1773 \r
1774                                                 type = r;\r
1775                                                 return true;\r
1776                                         }\r
1777                                         \r
1778                                         other = l;\r
1779                                 }\r
1780 \r
1781                                 if ((other == TypeManager.sbyte_type) ||\r
1782                                     (other == TypeManager.short_type) ||\r
1783                                     (other == TypeManager.int32_type)){\r
1784                                         left = ForceConversion (ec, left, TypeManager.int64_type);\r
1785                                         right = ForceConversion (ec, right, TypeManager.int64_type);\r
1786                                         type = TypeManager.int64_type;\r
1787                                 } else {\r
1788                                         //\r
1789                                         // if either operand is of type uint, the other\r
1790                                         // operand is converd to type uint\r
1791                                         //\r
1792                                         left = ForceConversion (ec, left, TypeManager.uint32_type);\r
1793                                         right = ForceConversion (ec, right, TypeManager.uint32_type);\r
1794                                         type = TypeManager.uint32_type;\r
1795                                 } \r
1796                         } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){\r
1797                                 if (l != TypeManager.decimal_type)\r
1798                                         left = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);\r
1799 \r
1800                                 if (r != TypeManager.decimal_type)\r
1801                                         right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc);\r
1802                                 type = TypeManager.decimal_type;\r
1803                         } else {\r
1804                                 left = ForceConversion (ec, left, TypeManager.int32_type);\r
1805                                 right = ForceConversion (ec, right, TypeManager.int32_type);\r
1806 \r
1807                                 type = TypeManager.int32_type;\r
1808                         }\r
1809 \r
1810                         return (left != null) && (right != null);\r
1811                 }\r
1812 \r
1813                 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)\r
1814                 {\r
1815                         Report.Error (19, loc,\r
1816                                "Operator " + name + " cannot be applied to operands of type '" +\r
1817                                TypeManager.CSharpName (l) + "' and '" +\r
1818                                TypeManager.CSharpName (r) + "'");\r
1819                 }\r
1820                 \r
1821                 void Error_OperatorCannotBeApplied ()\r
1822                 {\r
1823                         Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);\r
1824                 }\r
1825 \r
1826                 static bool is_32_or_64 (Type t)\r
1827                 {\r
1828                         return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||\r
1829                                 t == TypeManager.int64_type || t == TypeManager.uint64_type);\r
1830                 }\r
1831 \r
1832                 static bool is_unsigned (Type t)\r
1833                 {\r
1834                         return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||\r
1835                                 t == TypeManager.short_type || t == TypeManager.byte_type);\r
1836                 }\r
1837                                         \r
1838                 Expression CheckShiftArguments (EmitContext ec)\r
1839                 {\r
1840                         Expression e;\r
1841                         Type l = left.Type;\r
1842                         Type r = right.Type;\r
1843 \r
1844                         e = ForceConversion (ec, right, TypeManager.int32_type);\r
1845                         if (e == null){\r
1846                                 Error_OperatorCannotBeApplied ();\r
1847                                 return null;\r
1848                         }\r
1849                         right = e;\r
1850 \r
1851                         if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||\r
1852                             ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||\r
1853                             ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||\r
1854                             ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){\r
1855                                 left = e;\r
1856                                 type = e.Type;\r
1857 \r
1858                                 return this;\r
1859                         }\r
1860                         Error_OperatorCannotBeApplied ();\r
1861                         return null;\r
1862                 }\r
1863 \r
1864                 Expression ResolveOperator (EmitContext ec)\r
1865                 {\r
1866                         Type l = left.Type;\r
1867                         Type r = right.Type;\r
1868 \r
1869                         bool overload_failed = false;\r
1870 \r
1871                         //\r
1872                         // Step 1: Perform Operator Overload location\r
1873                         //\r
1874                         Expression left_expr, right_expr;\r
1875                                 \r
1876                         string op = oper_names [(int) oper];\r
1877                                 \r
1878                         MethodGroupExpr union;\r
1879                         left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);\r
1880                         if (r != l){\r
1881                                 right_expr = MemberLookup (\r
1882                                         ec, r, op, MemberTypes.Method, AllBindingFlags, loc);\r
1883                                 union = Invocation.MakeUnionSet (left_expr, right_expr, loc);\r
1884                         } else\r
1885                                 union = (MethodGroupExpr) left_expr;\r
1886                                 \r
1887                         if (union != null) {\r
1888                                 Arguments = new ArrayList ();\r
1889                                 Arguments.Add (new Argument (left, Argument.AType.Expression));\r
1890                                 Arguments.Add (new Argument (right, Argument.AType.Expression));\r
1891                                 \r
1892                                 method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);\r
1893                                 if (method != null) {\r
1894                                         MethodInfo mi = (MethodInfo) method;\r
1895                                         \r
1896                                         type = mi.ReturnType;\r
1897                                         return this;\r
1898                                 } else {\r
1899                                         overload_failed = true;\r
1900                                 }\r
1901                         }       \r
1902                         \r
1903                         //\r
1904                         // Step 2: Default operations on CLI native types.\r
1905                         //\r
1906 \r
1907                         //\r
1908                         // Step 0: String concatenation (because overloading will get this wrong)\r
1909                         //\r
1910                         if (oper == Operator.Addition){\r
1911                                 //\r
1912                                 // If any of the arguments is a string, cast to string\r
1913                                 //\r
1914                                 \r
1915                                 if (l == TypeManager.string_type){\r
1916                                         \r
1917                                         if (r == TypeManager.void_type) {\r
1918                                                 Error_OperatorCannotBeApplied ();\r
1919                                                 return null;\r
1920                                         }\r
1921                                         \r
1922                                         if (r == TypeManager.string_type){\r
1923                                                 if (left is Constant && right is Constant){\r
1924                                                         StringConstant ls = (StringConstant) left;\r
1925                                                         StringConstant rs = (StringConstant) right;\r
1926                                                         \r
1927                                                         return new StringConstant (\r
1928                                                                 ls.Value + rs.Value);\r
1929                                                 }\r
1930                                                 \r
1931                                                 // string + string\r
1932                                                 method = TypeManager.string_concat_string_string;\r
1933                                         } else {\r
1934                                                 // string + object\r
1935                                                 method = TypeManager.string_concat_object_object;\r
1936                                                 right = ConvertImplicit (ec, right,\r
1937                                                                          TypeManager.object_type, loc);\r
1938                                                 if (right == null){\r
1939                                                         Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);\r
1940                                                         return null;\r
1941                                                 }\r
1942                                         }\r
1943                                         type = TypeManager.string_type;\r
1944 \r
1945                                         Arguments = new ArrayList ();\r
1946                                         Arguments.Add (new Argument (left, Argument.AType.Expression));\r
1947                                         Arguments.Add (new Argument (right, Argument.AType.Expression));\r
1948 \r
1949                                         return this;\r
1950                                         \r
1951                                 } else if (r == TypeManager.string_type){\r
1952                                         // object + string\r
1953 \r
1954                                         if (l == TypeManager.void_type) {\r
1955                                                 Error_OperatorCannotBeApplied ();\r
1956                                                 return null;\r
1957                                         }\r
1958                                         \r
1959                                         method = TypeManager.string_concat_object_object;\r
1960                                         left = ConvertImplicit (ec, left, TypeManager.object_type, loc);\r
1961                                         if (left == null){\r
1962                                                 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);\r
1963                                                 return null;\r
1964                                         }\r
1965                                         Arguments = new ArrayList ();\r
1966                                         Arguments.Add (new Argument (left, Argument.AType.Expression));\r
1967                                         Arguments.Add (new Argument (right, Argument.AType.Expression));\r
1968 \r
1969                                         type = TypeManager.string_type;\r
1970 \r
1971                                         return this;\r
1972                                 }\r
1973 \r
1974                                 //\r
1975                                 // Transform a + ( - b) into a - b\r
1976                                 //\r
1977                                 if (right is Unary){\r
1978                                         Unary right_unary = (Unary) right;\r
1979 \r
1980                                         if (right_unary.Oper == Unary.Operator.UnaryNegation){\r
1981                                                 oper = Operator.Subtraction;\r
1982                                                 right = right_unary.Expr;\r
1983                                                 r = right.Type;\r
1984                                         }\r
1985                                 }\r
1986                         }\r
1987 \r
1988                         if (oper == Operator.Equality || oper == Operator.Inequality){\r
1989                                 if (l == TypeManager.bool_type || r == TypeManager.bool_type){\r
1990                                         if (r != TypeManager.bool_type || l != TypeManager.bool_type){\r
1991                                                 Error_OperatorCannotBeApplied ();\r
1992                                                 return null;\r
1993                                         }\r
1994                                         \r
1995                                         type = TypeManager.bool_type;\r
1996                                         return this;\r
1997                                 }\r
1998 \r
1999                                 //\r
2000                                 // operator != (object a, object b)\r
2001                                 // operator == (object a, object b)\r
2002                                 //\r
2003                                 // For this to be used, both arguments have to be reference-types.\r
2004                                 // Read the rationale on the spec (14.9.6)\r
2005                                 //\r
2006                                 // Also, if at compile time we know that the classes do not inherit\r
2007                                 // one from the other, then we catch the error there.\r
2008                                 //\r
2009                                 if (!(l.IsValueType || r.IsValueType)){\r
2010                                         type = TypeManager.bool_type;\r
2011 \r
2012                                         if (l == r)\r
2013                                                 return this;\r
2014                                         \r
2015                                         if (l.IsSubclassOf (r) || r.IsSubclassOf (l))\r
2016                                                 return this;\r
2017 \r
2018                                         //\r
2019                                         // Also, a standard conversion must exist from either one\r
2020                                         //\r
2021                                         if (!(StandardConversionExists (left, r) ||\r
2022                                               StandardConversionExists (right, l))){\r
2023                                                 Error_OperatorCannotBeApplied ();\r
2024                                                 return null;\r
2025                                         }\r
2026                                         //\r
2027                                         // We are going to have to convert to an object to compare\r
2028                                         //\r
2029                                         if (l != TypeManager.object_type)\r
2030                                                 left = new EmptyCast (left, TypeManager.object_type);\r
2031                                         if (r != TypeManager.object_type)\r
2032                                                 right = new EmptyCast (right, TypeManager.object_type);\r
2033 \r
2034                                         //\r
2035                                         // FIXME: CSC here catches errors cs254 and cs252\r
2036                                         //\r
2037                                         return this;\r
2038                                 }\r
2039 \r
2040                                 //\r
2041                                 // One of them is a valuetype, but the other one is not.\r
2042                                 //\r
2043                                 if (!l.IsValueType || !r.IsValueType) {\r
2044                                         Error_OperatorCannotBeApplied ();\r
2045                                         return null;\r
2046                                 }\r
2047                         }\r
2048 \r
2049                         // Only perform numeric promotions on:\r
2050                         // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=\r
2051                         //\r
2052                         if (oper == Operator.Addition || oper == Operator.Subtraction) {\r
2053                                 if (l.IsSubclassOf (TypeManager.delegate_type) &&\r
2054                                     r.IsSubclassOf (TypeManager.delegate_type)) {\r
2055                                         \r
2056                                         Arguments = new ArrayList ();\r
2057                                         Arguments.Add (new Argument (left, Argument.AType.Expression));\r
2058                                         Arguments.Add (new Argument (right, Argument.AType.Expression));\r
2059                                         \r
2060                                         if (oper == Operator.Addition)\r
2061                                                 method = TypeManager.delegate_combine_delegate_delegate;\r
2062                                         else\r
2063                                                 method = TypeManager.delegate_remove_delegate_delegate;\r
2064 \r
2065                                         if (l != r) {\r
2066                                                 Error_OperatorCannotBeApplied ();\r
2067                                                 return null;\r
2068                                         }\r
2069 \r
2070                                         DelegateOperation = true;\r
2071                                         type = l;\r
2072                                         return this;\r
2073                                 }\r
2074 \r
2075                                 //\r
2076                                 // Pointer arithmetic:\r
2077                                 //\r
2078                                 // T* operator + (T* x, int y);\r
2079                                 // T* operator + (T* x, uint y);\r
2080                                 // T* operator + (T* x, long y);\r
2081                                 // T* operator + (T* x, ulong y);\r
2082                                 //\r
2083                                 // T* operator + (int y,   T* x);\r
2084                                 // T* operator + (uint y,  T *x);\r
2085                                 // T* operator + (long y,  T *x);\r
2086                                 // T* operator + (ulong y, T *x);\r
2087                                 //\r
2088                                 // T* operator - (T* x, int y);\r
2089                                 // T* operator - (T* x, uint y);\r
2090                                 // T* operator - (T* x, long y);\r
2091                                 // T* operator - (T* x, ulong y);\r
2092                                 //\r
2093                                 // long operator - (T* x, T *y)\r
2094                                 //\r
2095                                 if (l.IsPointer){\r
2096                                         if (r.IsPointer && oper == Operator.Subtraction){\r
2097                                                 if (r == l)\r
2098                                                         return new PointerArithmetic (\r
2099                                                                 false, left, right, TypeManager.int64_type,\r
2100                                                                 loc);\r
2101                                         } else if (is_32_or_64 (r))\r
2102                                                 return new PointerArithmetic (\r
2103                                                         oper == Operator.Addition, left, right, l, loc);\r
2104                                 } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)\r
2105                                         return new PointerArithmetic (\r
2106                                                 true, right, left, r, loc);\r
2107                         }\r
2108                         \r
2109                         //\r
2110                         // Enumeration operators\r
2111                         //\r
2112                         bool lie = TypeManager.IsEnumType (l);\r
2113                         bool rie = TypeManager.IsEnumType (r);\r
2114                         if (lie || rie){\r
2115                                 Expression temp;\r
2116 \r
2117                                 // U operator - (E e, E f)\r
2118                                 if (lie && rie && oper == Operator.Subtraction){\r
2119                                         if (l == r){\r
2120                                                 type = TypeManager.EnumToUnderlying (l);\r
2121                                                 return this;\r
2122                                         } \r
2123                                         Error_OperatorCannotBeApplied ();\r
2124                                         return null;\r
2125                                 }\r
2126                                         \r
2127                                 //\r
2128                                 // operator + (E e, U x)\r
2129                                 // operator - (E e, U x)\r
2130                                 //\r
2131                                 if (oper == Operator.Addition || oper == Operator.Subtraction){\r
2132                                         Type enum_type = lie ? l : r;\r
2133                                         Type other_type = lie ? r : l;\r
2134                                         Type underlying_type = TypeManager.EnumToUnderlying (enum_type);\r
2135 ;\r
2136                                         \r
2137                                         if (underlying_type != other_type){\r
2138                                                 Error_OperatorCannotBeApplied ();\r
2139                                                 return null;\r
2140                                         }\r
2141 \r
2142                                         type = enum_type;\r
2143                                         return this;\r
2144                                 }\r
2145                                 \r
2146                                 if (!rie){\r
2147                                         temp = ConvertImplicit (ec, right, l, loc);\r
2148                                         if (temp != null)\r
2149                                                 right = temp;\r
2150                                         else {\r
2151                                                 Error_OperatorCannotBeApplied ();\r
2152                                                 return null;\r
2153                                         }\r
2154                                 } if (!lie){\r
2155                                         temp = ConvertImplicit (ec, left, r, loc);\r
2156                                         if (temp != null){\r
2157                                                 left = temp;\r
2158                                                 l = r;\r
2159                                         } else {\r
2160                                                 Error_OperatorCannotBeApplied ();\r
2161                                                 return null;\r
2162                                         }\r
2163                                 }\r
2164 \r
2165                                 if (oper == Operator.Equality || oper == Operator.Inequality ||\r
2166                                     oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||\r
2167                                     oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){\r
2168                                         type = TypeManager.bool_type;\r
2169                                         return this;\r
2170                                 }\r
2171 \r
2172                                 if (oper == Operator.BitwiseAnd ||\r
2173                                     oper == Operator.BitwiseOr ||\r
2174                                     oper == Operator.ExclusiveOr){\r
2175                                         type = l;\r
2176                                         return this;\r
2177                                 }\r
2178                                 Error_OperatorCannotBeApplied ();\r
2179                                 return null;\r
2180                         }\r
2181                         \r
2182                         if (oper == Operator.LeftShift || oper == Operator.RightShift)\r
2183                                 return CheckShiftArguments (ec);\r
2184 \r
2185                         if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){\r
2186                                 if (l != TypeManager.bool_type || r != TypeManager.bool_type){\r
2187                                         Error_OperatorCannotBeApplied ();\r
2188                                         return null;\r
2189                                 }\r
2190 \r
2191                                 type = TypeManager.bool_type;\r
2192                                 return this;\r
2193                         } \r
2194 \r
2195                         //\r
2196                         // operator & (bool x, bool y)\r
2197                         // operator | (bool x, bool y)\r
2198                         // operator ^ (bool x, bool y)\r
2199                         //\r
2200                         if (l == TypeManager.bool_type && r == TypeManager.bool_type){\r
2201                                 if (oper == Operator.BitwiseAnd ||\r
2202                                     oper == Operator.BitwiseOr ||\r
2203                                     oper == Operator.ExclusiveOr){\r
2204                                         type = l;\r
2205                                         return this;\r
2206                                 }\r
2207                         }\r
2208                         \r
2209                         //\r
2210                         // Pointer comparison\r
2211                         //\r
2212                         if (l.IsPointer && r.IsPointer){\r
2213                                 if (oper == Operator.Equality || oper == Operator.Inequality ||\r
2214                                     oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||\r
2215                                     oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){\r
2216                                         type = TypeManager.bool_type;\r
2217                                         return this;\r
2218                                 }\r
2219                         }\r
2220                         \r
2221                         //\r
2222                         // We are dealing with numbers\r
2223                         //\r
2224                         if (overload_failed){\r
2225                                 Error_OperatorCannotBeApplied ();\r
2226                                 return null;\r
2227                         }\r
2228 \r
2229                         //\r
2230                         // This will leave left or right set to null if there is an error\r
2231                         //\r
2232                         DoNumericPromotions (ec, l, r);\r
2233                         if (left == null || right == null){\r
2234                                 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);\r
2235                                 return null;\r
2236                         }\r
2237 \r
2238                         //\r
2239                         // reload our cached types if required\r
2240                         //\r
2241                         l = left.Type;\r
2242                         r = right.Type;\r
2243                         \r
2244                         if (oper == Operator.BitwiseAnd ||\r
2245                             oper == Operator.BitwiseOr ||\r
2246                             oper == Operator.ExclusiveOr){\r
2247                                 if (l == r){\r
2248                                         if (!((l == TypeManager.int32_type) ||\r
2249                                               (l == TypeManager.uint32_type) ||\r
2250                                               (l == TypeManager.int64_type) ||\r
2251                                               (l == TypeManager.uint64_type)))\r
2252                                                 type = l;\r
2253                                 } else {\r
2254                                         Error_OperatorCannotBeApplied ();\r
2255                                         return null;\r
2256                                 }\r
2257                         }\r
2258 \r
2259                         if (oper == Operator.Equality ||\r
2260                             oper == Operator.Inequality ||\r
2261                             oper == Operator.LessThanOrEqual ||\r
2262                             oper == Operator.LessThan ||\r
2263                             oper == Operator.GreaterThanOrEqual ||\r
2264                             oper == Operator.GreaterThan){\r
2265                                 type = TypeManager.bool_type;\r
2266                         }\r
2267 \r
2268                         return this;\r
2269                 }\r
2270 \r
2271                 public override Expression DoResolve (EmitContext ec)\r
2272                 {\r
2273                         left = left.Resolve (ec);\r
2274                         right = right.Resolve (ec);\r
2275 \r
2276                         if (left == null || right == null)\r
2277                                 return null;\r
2278 \r
2279                         if (left.Type == null)\r
2280                                 throw new Exception (\r
2281                                         "Resolve returned non null, but did not set the type! (" +\r
2282                                         left + ") at Line: " + loc.Row);\r
2283                         if (right.Type == null)\r
2284                                 throw new Exception (\r
2285                                         "Resolve returned non null, but did not set the type! (" +\r
2286                                         right + ") at Line: "+ loc.Row);\r
2287 \r
2288                         eclass = ExprClass.Value;\r
2289 \r
2290                         if (left is Constant && right is Constant){\r
2291                                 Expression e = ConstantFold.BinaryFold (\r
2292                                         ec, oper, (Constant) left, (Constant) right, loc);\r
2293                                 if (e != null)\r
2294                                         return e;\r
2295                         }\r
2296 \r
2297                         return ResolveOperator (ec);\r
2298                 }\r
2299 \r
2300                 /// <remarks>\r
2301                 ///   EmitBranchable is called from Statement.EmitBoolExpression in the\r
2302                 ///   context of a conditional bool expression.  This function will return\r
2303                 ///   false if it is was possible to use EmitBranchable, or true if it was.\r
2304                 ///\r
2305                 ///   The expression's code is generated, and we will generate a branch to 'target'\r
2306                 ///   if the resulting expression value is equal to isTrue\r
2307                 /// </remarks>\r
2308                 public bool EmitBranchable (EmitContext ec, Label target, bool onTrue)\r
2309                 {\r
2310                         if (method != null)\r
2311                                 return false;\r
2312 \r
2313                         ILGenerator ig = ec.ig;\r
2314 \r
2315                         //\r
2316                         // This is more complicated than it looks, but its just to avoid\r
2317                         // duplicated tests: basically, we allow ==, !=, >, <, >= and <=\r
2318                         // but on top of that we want for == and != to use a special path\r
2319                         // if we are comparing against null\r
2320                         //\r
2321                         if (oper == Operator.Equality || oper == Operator.Inequality){\r
2322                                 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;\r
2323                                 \r
2324                                 if (left is NullLiteral){\r
2325                                         right.Emit (ec);\r
2326                                         if (my_on_true)\r
2327                                                 ig.Emit (OpCodes.Brtrue, target);\r
2328                                         else\r
2329                                                 ig.Emit (OpCodes.Brfalse, target);\r
2330                                         return true;\r
2331                                 } else if (right is NullLiteral){\r
2332                                         left.Emit (ec);\r
2333                                         if (my_on_true)\r
2334                                                 ig.Emit (OpCodes.Brtrue, target);\r
2335                                         else\r
2336                                                 ig.Emit (OpCodes.Brfalse, target);\r
2337                                         return true;\r
2338                                 } \r
2339                         } else if (!(oper == Operator.LessThan ||\r
2340                                       oper == Operator.GreaterThan ||\r
2341                                       oper == Operator.LessThanOrEqual ||\r
2342                                       oper == Operator.GreaterThanOrEqual))\r
2343                                 return false;\r
2344                         \r
2345 \r
2346                         \r
2347                         left.Emit (ec);\r
2348                         right.Emit (ec);\r
2349 \r
2350                         bool isUnsigned = is_unsigned (left.Type);\r
2351 \r
2352                         switch (oper){\r
2353                         case Operator.Equality:\r
2354                                 if (onTrue)\r
2355                                         ig.Emit (OpCodes.Beq, target);\r
2356                                 else\r
2357                                         ig.Emit (OpCodes.Bne_Un, target);\r
2358                                 break;\r
2359 \r
2360                         case Operator.Inequality:\r
2361                                 if (onTrue)\r
2362                                         ig.Emit (OpCodes.Bne_Un, target);\r
2363                                 else\r
2364                                         ig.Emit (OpCodes.Beq, target);\r
2365                                 break;\r
2366 \r
2367                         case Operator.LessThan:\r
2368                                 if (onTrue)\r
2369                                         if (isUnsigned)\r
2370                                                 ig.Emit (OpCodes.Blt_Un, target);\r
2371                                         else\r
2372                                                 ig.Emit (OpCodes.Blt, target);\r
2373                                 else\r
2374                                         if (isUnsigned)\r
2375                                                 ig.Emit (OpCodes.Bge_Un, target);\r
2376                                         else\r
2377                                                 ig.Emit (OpCodes.Bge, target);\r
2378                                 break;\r
2379 \r
2380                         case Operator.GreaterThan:\r
2381                                 if (onTrue)\r
2382                                         if (isUnsigned)\r
2383                                                 ig.Emit (OpCodes.Bgt_Un, target);\r
2384                                         else\r
2385                                                 ig.Emit (OpCodes.Bgt, target);\r
2386                                 else\r
2387                                         if (isUnsigned)\r
2388                                                 ig.Emit (OpCodes.Ble_Un, target);\r
2389                                         else\r
2390                                                 ig.Emit (OpCodes.Ble, target);\r
2391                                 break;\r
2392 \r
2393                         case Operator.LessThanOrEqual:\r
2394                                 if (onTrue)\r
2395                                         if (isUnsigned)\r
2396                                                 ig.Emit (OpCodes.Ble_Un, target);\r
2397                                         else\r
2398                                                 ig.Emit (OpCodes.Ble, target);\r
2399                                 else\r
2400                                         if (isUnsigned)\r
2401                                                 ig.Emit (OpCodes.Bgt_Un, target);\r
2402                                         else\r
2403                                                 ig.Emit (OpCodes.Bgt, target);\r
2404                                 break;\r
2405 \r
2406 \r
2407                         case Operator.GreaterThanOrEqual:\r
2408                                 if (onTrue)\r
2409                                         if (isUnsigned)\r
2410                                                 ig.Emit (OpCodes.Bge_Un, target);\r
2411                                         else\r
2412                                                 ig.Emit (OpCodes.Bge, target);\r
2413                                 else\r
2414                                         if (isUnsigned)\r
2415                                                 ig.Emit (OpCodes.Blt_Un, target);\r
2416                                         else\r
2417                                                 ig.Emit (OpCodes.Blt, target);\r
2418                                 break;\r
2419 \r
2420                         default:\r
2421                                 return false;\r
2422                         }\r
2423                         \r
2424                         return true;\r
2425                 }\r
2426                 \r
2427                 public override void Emit (EmitContext ec)\r
2428                 {\r
2429                         ILGenerator ig = ec.ig;\r
2430                         Type l = left.Type;\r
2431                         Type r = right.Type;\r
2432                         OpCode opcode;\r
2433 \r
2434                         if (method != null) {\r
2435 \r
2436                                 // Note that operators are static anyway\r
2437                                 \r
2438                                 if (Arguments != null) \r
2439                                         Invocation.EmitArguments (ec, method, Arguments);\r
2440                                 \r
2441                                 if (method is MethodInfo)\r
2442                                         ig.Emit (OpCodes.Call, (MethodInfo) method);\r
2443                                 else\r
2444                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);\r
2445 \r
2446                                 if (DelegateOperation)\r
2447                                         ig.Emit (OpCodes.Castclass, type);\r
2448                                         \r
2449                                 return;\r
2450                         }\r
2451 \r
2452                         //\r
2453                         // Handle short-circuit operators differently\r
2454                         // than the rest\r
2455                         //\r
2456                         if (oper == Operator.LogicalAnd){\r
2457                                 Label load_zero = ig.DefineLabel ();\r
2458                                 Label end = ig.DefineLabel ();\r
2459                                 \r
2460                                 left.Emit (ec);\r
2461                                 ig.Emit (OpCodes.Brfalse, load_zero);\r
2462                                 right.Emit (ec);\r
2463                                 ig.Emit (OpCodes.Br, end);\r
2464                                 ig.MarkLabel (load_zero);\r
2465                                 ig.Emit (OpCodes.Ldc_I4_0);\r
2466                                 ig.MarkLabel (end);\r
2467                                 return;\r
2468                         } else if (oper == Operator.LogicalOr){\r
2469                                 Label load_one = ig.DefineLabel ();\r
2470                                 Label end = ig.DefineLabel ();\r
2471                                 \r
2472                                 left.Emit (ec);\r
2473                                 ig.Emit (OpCodes.Brtrue, load_one);\r
2474                                 right.Emit (ec);\r
2475                                 ig.Emit (OpCodes.Br, end);\r
2476                                 ig.MarkLabel (load_one);\r
2477                                 ig.Emit (OpCodes.Ldc_I4_1);\r
2478                                 ig.MarkLabel (end);\r
2479                                 return;\r
2480                         }\r
2481                         \r
2482                         left.Emit (ec);\r
2483                         right.Emit (ec);\r
2484 \r
2485                         switch (oper){\r
2486                         case Operator.Multiply:\r
2487                                 if (ec.CheckState){\r
2488                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)\r
2489                                                 opcode = OpCodes.Mul_Ovf;\r
2490                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)\r
2491                                                 opcode = OpCodes.Mul_Ovf_Un;\r
2492                                         else\r
2493                                                 opcode = OpCodes.Mul;\r
2494                                 } else\r
2495                                         opcode = OpCodes.Mul;\r
2496 \r
2497                                 break;\r
2498 \r
2499                         case Operator.Division:\r
2500                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)\r
2501                                         opcode = OpCodes.Div_Un;\r
2502                                 else\r
2503                                         opcode = OpCodes.Div;\r
2504                                 break;\r
2505 \r
2506                         case Operator.Modulus:\r
2507                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)\r
2508                                         opcode = OpCodes.Rem_Un;\r
2509                                 else\r
2510                                         opcode = OpCodes.Rem;\r
2511                                 break;\r
2512 \r
2513                         case Operator.Addition:\r
2514                                 if (ec.CheckState){\r
2515                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)\r
2516                                                 opcode = OpCodes.Add_Ovf;\r
2517                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)\r
2518                                                 opcode = OpCodes.Add_Ovf_Un;\r
2519                                         else\r
2520                                                 opcode = OpCodes.Add;\r
2521                                 } else\r
2522                                         opcode = OpCodes.Add;\r
2523                                 break;\r
2524 \r
2525                         case Operator.Subtraction:\r
2526                                 if (ec.CheckState){\r
2527                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)\r
2528                                                 opcode = OpCodes.Sub_Ovf;\r
2529                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)\r
2530                                                 opcode = OpCodes.Sub_Ovf_Un;\r
2531                                         else\r
2532                                                 opcode = OpCodes.Sub;\r
2533                                 } else\r
2534                                         opcode = OpCodes.Sub;\r
2535                                 break;\r
2536 \r
2537                         case Operator.RightShift:\r
2538                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)\r
2539                                         opcode = OpCodes.Shr_Un;\r
2540                                 else\r
2541                                         opcode = OpCodes.Shr;\r
2542                                 break;\r
2543                                 \r
2544                         case Operator.LeftShift:\r
2545                                 opcode = OpCodes.Shl;\r
2546                                 break;\r
2547 \r
2548                         case Operator.Equality:\r
2549                                 opcode = OpCodes.Ceq;\r
2550                                 break;\r
2551 \r
2552                         case Operator.Inequality:\r
2553                                 ec.ig.Emit (OpCodes.Ceq);\r
2554                                 ec.ig.Emit (OpCodes.Ldc_I4_0);\r
2555                                 \r
2556                                 opcode = OpCodes.Ceq;\r
2557                                 break;\r
2558 \r
2559                         case Operator.LessThan:\r
2560                                 opcode = OpCodes.Clt;\r
2561                                 break;\r
2562 \r
2563                         case Operator.GreaterThan:\r
2564                                 opcode = OpCodes.Cgt;\r
2565                                 break;\r
2566 \r
2567                         case Operator.LessThanOrEqual:\r
2568                                 ec.ig.Emit (OpCodes.Cgt);\r
2569                                 ec.ig.Emit (OpCodes.Ldc_I4_0);\r
2570                                 \r
2571                                 opcode = OpCodes.Ceq;\r
2572                                 break;\r
2573 \r
2574                         case Operator.GreaterThanOrEqual:\r
2575                                 ec.ig.Emit (OpCodes.Clt);\r
2576                                 ec.ig.Emit (OpCodes.Ldc_I4_1);\r
2577                                 \r
2578                                 opcode = OpCodes.Sub;\r
2579                                 break;\r
2580 \r
2581                         case Operator.BitwiseOr:\r
2582                                 opcode = OpCodes.Or;\r
2583                                 break;\r
2584 \r
2585                         case Operator.BitwiseAnd:\r
2586                                 opcode = OpCodes.And;\r
2587                                 break;\r
2588 \r
2589                         case Operator.ExclusiveOr:\r
2590                                 opcode = OpCodes.Xor;\r
2591                                 break;\r
2592 \r
2593                         default:\r
2594                                 throw new Exception ("This should not happen: Operator = "\r
2595                                                      + oper.ToString ());\r
2596                         }\r
2597 \r
2598                         ig.Emit (opcode);\r
2599                 }\r
2600 \r
2601                 public bool IsBuiltinOperator {\r
2602                         get {\r
2603                                 return method == null;\r
2604                         }\r
2605                 }\r
2606         }\r
2607 \r
2608         public class PointerArithmetic : Expression {\r
2609                 Expression left, right;\r
2610                 bool is_add;\r
2611 \r
2612                 //\r
2613                 // We assume that 'l' is always a pointer\r
2614                 //\r
2615                 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t,\r
2616                                           Location loc)\r
2617                 {\r
2618                         type = t;\r
2619                         eclass = ExprClass.Variable;\r
2620                         this.loc = loc;\r
2621                         left = l;\r
2622                         right = r;\r
2623                         is_add = is_addition;\r
2624                 }\r
2625 \r
2626                 public override Expression DoResolve (EmitContext ec)\r
2627                 {\r
2628                         //\r
2629                         // We are born fully resolved\r
2630                         //\r
2631                         return this;\r
2632                 }\r
2633 \r
2634                 public override void Emit (EmitContext ec)\r
2635                 {\r
2636                         Type op_type = left.Type;\r
2637                         ILGenerator ig = ec.ig;\r
2638                         int size = GetTypeSize (op_type.GetElementType ());\r
2639                         \r
2640                         if (right.Type.IsPointer){\r
2641                                 //\r
2642                                 // handle (pointer - pointer)\r
2643                                 //\r
2644                                 left.Emit (ec);\r
2645                                 right.Emit (ec);\r
2646                                 ig.Emit (OpCodes.Sub);\r
2647 \r
2648                                 if (size != 1){\r
2649                                         if (size == 0)\r
2650                                                 ig.Emit (OpCodes.Sizeof, op_type);\r
2651                                         else \r
2652                                                 IntLiteral.EmitInt (ig, size);\r
2653                                         ig.Emit (OpCodes.Div);\r
2654                                 }\r
2655                                 ig.Emit (OpCodes.Conv_I8);\r
2656                         } else {\r
2657                                 //\r
2658                                 // handle + and - on (pointer op int)\r
2659                                 //\r
2660                                 left.Emit (ec);\r
2661                                 ig.Emit (OpCodes.Conv_I);\r
2662                                 right.Emit (ec);\r
2663                                 if (size != 1){\r
2664                                         if (size == 0)\r
2665                                                 ig.Emit (OpCodes.Sizeof, op_type);\r
2666                                         else \r
2667                                                 IntLiteral.EmitInt (ig, size);\r
2668                                         ig.Emit (OpCodes.Mul);\r
2669                                 }\r
2670                                 if (is_add)\r
2671                                         ig.Emit (OpCodes.Add);\r
2672                                 else\r
2673                                         ig.Emit (OpCodes.Sub);\r
2674                         }\r
2675                 }\r
2676         }\r
2677         \r
2678         /// <summary>\r
2679         ///   Implements the ternary conditional operator (?:)\r
2680         /// </summary>\r
2681         public class Conditional : Expression {\r
2682                 Expression expr, trueExpr, falseExpr;\r
2683                 \r
2684                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)\r
2685                 {\r
2686                         this.expr = expr;\r
2687                         this.trueExpr = trueExpr;\r
2688                         this.falseExpr = falseExpr;\r
2689                         this.loc = l;\r
2690                 }\r
2691 \r
2692                 public Expression Expr {\r
2693                         get {\r
2694                                 return expr;\r
2695                         }\r
2696                 }\r
2697 \r
2698                 public Expression TrueExpr {\r
2699                         get {\r
2700                                 return trueExpr;\r
2701                         }\r
2702                 }\r
2703 \r
2704                 public Expression FalseExpr {\r
2705                         get {\r
2706                                 return falseExpr;\r
2707                         }\r
2708                 }\r
2709 \r
2710                 public override Expression DoResolve (EmitContext ec)\r
2711                 {\r
2712                         expr = expr.Resolve (ec);\r
2713 \r
2714                         if (expr == null)\r
2715                                 return null;\r
2716                         \r
2717                         if (expr.Type != TypeManager.bool_type)\r
2718                                 expr = Expression.ConvertImplicitRequired (\r
2719                                         ec, expr, TypeManager.bool_type, loc);\r
2720                         \r
2721                         trueExpr = trueExpr.Resolve (ec);\r
2722                         falseExpr = falseExpr.Resolve (ec);\r
2723 \r
2724                         if (trueExpr == null || falseExpr == null)\r
2725                                 return null;\r
2726 \r
2727                         eclass = ExprClass.Value;\r
2728                         if (trueExpr.Type == falseExpr.Type)\r
2729                                 type = trueExpr.Type;\r
2730                         else {\r
2731                                 Expression conv;\r
2732                                 Type true_type = trueExpr.Type;\r
2733                                 Type false_type = falseExpr.Type;\r
2734 \r
2735                                 if (trueExpr is NullLiteral){\r
2736                                         type = false_type;\r
2737                                         return this;\r
2738                                 } else if (falseExpr is NullLiteral){\r
2739                                         type = true_type;\r
2740                                         return this;\r
2741                                 }\r
2742                                 \r
2743                                 //\r
2744                                 // First, if an implicit conversion exists from trueExpr\r
2745                                 // to falseExpr, then the result type is of type falseExpr.Type\r
2746                                 //\r
2747                                 conv = ConvertImplicit (ec, trueExpr, false_type, loc);\r
2748                                 if (conv != null){\r
2749                                         //\r
2750                                         // Check if both can convert implicitl to each other's type\r
2751                                         //\r
2752                                         if (ConvertImplicit (ec, falseExpr, true_type, loc) != null){\r
2753                                                 Error (172,\r
2754                                                        "Can not compute type of conditional expression " +\r
2755                                                        "as '" + TypeManager.CSharpName (trueExpr.Type) +\r
2756                                                        "' and '" + TypeManager.CSharpName (falseExpr.Type) +\r
2757                                                        "' convert implicitly to each other");\r
2758                                                 return null;\r
2759                                         }\r
2760                                         type = false_type;\r
2761                                         trueExpr = conv;\r
2762                                 } else if ((conv = ConvertImplicit(ec, falseExpr, true_type,loc))!= null){\r
2763                                         type = true_type;\r
2764                                         falseExpr = conv;\r
2765                                 } else {\r
2766                                         Error (173, "The type of the conditional expression can " +\r
2767                                                "not be computed because there is no implicit conversion" +\r
2768                                                " from '" + TypeManager.CSharpName (trueExpr.Type) + "'" +\r
2769                                                " and '" + TypeManager.CSharpName (falseExpr.Type) + "'");\r
2770                                         return null;\r
2771                                 }\r
2772                         }\r
2773 \r
2774                         if (expr is BoolConstant){\r
2775                                 BoolConstant bc = (BoolConstant) expr;\r
2776 \r
2777                                 if (bc.Value)\r
2778                                         return trueExpr;\r
2779                                 else\r
2780                                         return falseExpr;\r
2781                         }\r
2782 \r
2783                         return this;\r
2784                 }\r
2785 \r
2786                 public override void Emit (EmitContext ec)\r
2787                 {\r
2788                         ILGenerator ig = ec.ig;\r
2789                         Label false_target = ig.DefineLabel ();\r
2790                         Label end_target = ig.DefineLabel ();\r
2791 \r
2792                         Statement.EmitBoolExpression (ec, expr, false_target, false);\r
2793                         trueExpr.Emit (ec);\r
2794                         ig.Emit (OpCodes.Br, end_target);\r
2795                         ig.MarkLabel (false_target);\r
2796                         falseExpr.Emit (ec);\r
2797                         ig.MarkLabel (end_target);\r
2798                 }\r
2799 \r
2800         }\r
2801 \r
2802         /// <summary>\r
2803         ///   Local variables\r
2804         /// </summary>\r
2805         public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {\r
2806                 public readonly string Name;\r
2807                 public readonly Block Block;\r
2808                 VariableInfo variable_info;\r
2809                 bool is_readonly;\r
2810                 \r
2811                 public LocalVariableReference (Block block, string name, Location l)\r
2812                 {\r
2813                         Block = block;\r
2814                         Name = name;\r
2815                         loc = l;\r
2816                         eclass = ExprClass.Variable;\r
2817                 }\r
2818 \r
2819                 // Setting 'is_readonly' to false will allow you to create a writable\r
2820                 // reference to a read-only variable.  This is used by foreach and using.\r
2821                 public LocalVariableReference (Block block, string name, Location l,\r
2822                                                VariableInfo variable_info, bool is_readonly)\r
2823                         : this (block, name, l)\r
2824                 {\r
2825                         this.variable_info = variable_info;\r
2826                         this.is_readonly = is_readonly;\r
2827                 }\r
2828 \r
2829                 public VariableInfo VariableInfo {\r
2830                         get {\r
2831                                 if (variable_info == null) {\r
2832                                         variable_info = Block.GetVariableInfo (Name);\r
2833                                         is_readonly = variable_info.ReadOnly;\r
2834                                 }\r
2835                                 return variable_info;\r
2836                         }\r
2837                 }\r
2838 \r
2839                 public bool IsAssigned (EmitContext ec, Location loc)\r
2840                 {\r
2841                         return VariableInfo.IsAssigned (ec, loc);\r
2842                 }\r
2843 \r
2844                 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)\r
2845                 {\r
2846                         return VariableInfo.IsFieldAssigned (ec, name, loc);\r
2847                 }\r
2848 \r
2849                 public void SetAssigned (EmitContext ec)\r
2850                 {\r
2851                         VariableInfo.SetAssigned (ec);\r
2852                 }\r
2853 \r
2854                 public void SetFieldAssigned (EmitContext ec, string name)\r
2855                 {\r
2856                         VariableInfo.SetFieldAssigned (ec, name);\r
2857                 }\r
2858 \r
2859                 public bool IsReadOnly {\r
2860                         get {\r
2861                                 if (variable_info == null) {\r
2862                                         variable_info = Block.GetVariableInfo (Name);\r
2863                                         is_readonly = variable_info.ReadOnly;\r
2864                                 }\r
2865                                 return is_readonly;\r
2866                         }\r
2867                 }\r
2868                 \r
2869                 public override Expression DoResolve (EmitContext ec)\r
2870                 {\r
2871                         VariableInfo vi = VariableInfo;\r
2872 \r
2873                         if (Block.IsConstant (Name)) {\r
2874                                 Expression e = Block.GetConstantExpression (Name);\r
2875 \r
2876                                 vi.Used = true;\r
2877                                 return e;\r
2878                         }\r
2879 \r
2880                         if (ec.DoFlowAnalysis && !IsAssigned (ec, loc))\r
2881                                 return null;\r
2882 \r
2883                         type = vi.VariableType;\r
2884                         return this;\r
2885                 }\r
2886 \r
2887                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)\r
2888                 {\r
2889                         VariableInfo vi = VariableInfo;\r
2890 \r
2891                         if (ec.DoFlowAnalysis)\r
2892                                 ec.SetVariableAssigned (vi);\r
2893 \r
2894                         Expression e = DoResolve (ec);\r
2895 \r
2896                         if (e == null)\r
2897                                 return null;\r
2898 \r
2899                         if (is_readonly){\r
2900                                 Error (1604, "cannot assign to '" + Name + "' because it is readonly");\r
2901                                 return null;\r
2902                         }\r
2903                         \r
2904                         return this;\r
2905                 }\r
2906 \r
2907                 public override void Emit (EmitContext ec)\r
2908                 {\r
2909                         VariableInfo vi = VariableInfo;\r
2910                         ILGenerator ig = ec.ig;\r
2911 \r
2912                         ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);\r
2913                         vi.Used = true;\r
2914                 }\r
2915                 \r
2916                 public void EmitAssign (EmitContext ec, Expression source)\r
2917                 {\r
2918                         ILGenerator ig = ec.ig;\r
2919                         VariableInfo vi = VariableInfo;\r
2920 \r
2921                         vi.Assigned = true;\r
2922 \r
2923                         source.Emit (ec);\r
2924                         \r
2925                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);\r
2926                 }\r
2927                 \r
2928                 public void AddressOf (EmitContext ec, AddressOp mode)\r
2929                 {\r
2930                         VariableInfo vi = VariableInfo;\r
2931 \r
2932                         ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);\r
2933                 }\r
2934         }\r
2935 \r
2936         /// <summary>\r
2937         ///   This represents a reference to a parameter in the intermediate\r
2938         ///   representation.\r
2939         /// </summary>\r
2940         public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {\r
2941                 Parameters pars;\r
2942                 String name;\r
2943                 int idx;\r
2944                 public Parameter.Modifier mod;\r
2945                 public bool is_ref, is_out;\r
2946                 \r
2947                 public ParameterReference (Parameters pars, int idx, string name, Location loc)\r
2948                 {\r
2949                         this.pars = pars;\r
2950                         this.idx  = idx;\r
2951                         this.name = name;\r
2952                         this.loc = loc;\r
2953                         eclass = ExprClass.Variable;\r
2954                 }\r
2955 \r
2956                 public bool IsAssigned (EmitContext ec, Location loc)\r
2957                 {\r
2958                         if (!is_out || !ec.DoFlowAnalysis)\r
2959                                 return true;\r
2960 \r
2961                         if (!ec.CurrentBranching.IsParameterAssigned (idx)) {\r
2962                                 Report.Error (165, loc,\r
2963                                               "Use of unassigned local variable '" + name + "'");\r
2964                                 return false;\r
2965                         }\r
2966 \r
2967                         return true;\r
2968                 }\r
2969 \r
2970                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)\r
2971                 {\r
2972                         if (!is_out || !ec.DoFlowAnalysis)\r
2973                                 return true;\r
2974 \r
2975                         if (ec.CurrentBranching.IsParameterAssigned (idx))\r
2976                                 return true;\r
2977 \r
2978                         if (!ec.CurrentBranching.IsParameterAssigned (idx, field_name)) {\r
2979                                 Report.Error (170, loc,\r
2980                                               "Use of possibly unassigned field '" + field_name + "'");\r
2981                                 return false;\r
2982                         }\r
2983 \r
2984                         return true;\r
2985                 }\r
2986 \r
2987                 public void SetAssigned (EmitContext ec)\r
2988                 {\r
2989                         if (is_out && ec.DoFlowAnalysis)\r
2990                                 ec.CurrentBranching.SetParameterAssigned (idx);\r
2991                 }\r
2992 \r
2993                 public void SetFieldAssigned (EmitContext ec, string field_name)\r
2994                 {\r
2995                         if (is_out && ec.DoFlowAnalysis)\r
2996                                 ec.CurrentBranching.SetParameterAssigned (idx, field_name);\r
2997                 }\r
2998 \r
2999                 //\r
3000                 // Notice that for ref/out parameters, the type exposed is not the\r
3001                 // same type exposed externally.\r
3002                 //\r
3003                 // for "ref int a":\r
3004                 //   externally we expose "int&"\r
3005                 //   here we expose       "int".\r
3006                 //\r
3007                 // We record this in "is_ref".  This means that the type system can treat\r
3008                 // the type as it is expected, but when we generate the code, we generate\r
3009                 // the alternate kind of code.\r
3010                 //\r
3011                 public override Expression DoResolve (EmitContext ec)\r
3012                 {\r
3013                         type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);\r
3014                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;\r
3015                         is_out = (mod & Parameter.Modifier.OUT) != 0;\r
3016                         eclass = ExprClass.Variable;\r
3017 \r
3018                         if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))\r
3019                                 return null;\r
3020 \r
3021                         return this;\r
3022                 }\r
3023 \r
3024                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)\r
3025                 {\r
3026                         type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);\r
3027                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;\r
3028                         is_out = (mod & Parameter.Modifier.OUT) != 0;\r
3029                         eclass = ExprClass.Variable;\r
3030 \r
3031                         if (is_out && ec.DoFlowAnalysis)\r
3032                                 ec.SetParameterAssigned (idx);\r
3033 \r
3034                         return this;\r
3035                 }\r
3036 \r
3037                 static void EmitLdArg (ILGenerator ig, int x)\r
3038                 {\r
3039                         if (x <= 255){\r
3040                                 switch (x){\r
3041                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;\r
3042                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;\r
3043                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;\r
3044                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;\r
3045                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;\r
3046                                 }\r
3047                         } else\r
3048                                 ig.Emit (OpCodes.Ldarg, x);\r
3049                 }\r
3050                 \r
3051                 //\r
3052                 // This method is used by parameters that are references, that are\r
3053                 // being passed as references:  we only want to pass the pointer (that\r
3054                 // is already stored in the parameter, not the address of the pointer,\r
3055                 // and not the value of the variable).\r
3056                 //\r
3057                 public void EmitLoad (EmitContext ec)\r
3058                 {\r
3059                         ILGenerator ig = ec.ig;\r
3060                         int arg_idx = idx;\r
3061 \r
3062                         if (!ec.IsStatic)\r
3063                                 arg_idx++;\r
3064 \r
3065                         EmitLdArg (ig, arg_idx);\r
3066                 }\r
3067                 \r
3068                 public override void Emit (EmitContext ec)\r
3069                 {\r
3070                         ILGenerator ig = ec.ig;\r
3071                         int arg_idx = idx;\r
3072 \r
3073                         if (!ec.IsStatic)\r
3074                                 arg_idx++;\r
3075 \r
3076                         EmitLdArg (ig, arg_idx);\r
3077 \r
3078                         if (!is_ref)\r
3079                                 return;\r
3080 \r
3081                         //\r
3082                         // If we are a reference, we loaded on the stack a pointer\r
3083                         // Now lets load the real value\r
3084                         //\r
3085                         LoadFromPtr (ig, type);\r
3086                 }\r
3087 \r
3088                 public void EmitAssign (EmitContext ec, Expression source)\r
3089                 {\r
3090                         ILGenerator ig = ec.ig;\r
3091                         int arg_idx = idx;\r
3092 \r
3093                         if (!ec.IsStatic)\r
3094                                 arg_idx++;\r
3095 \r
3096                         if (is_ref)\r
3097                                 EmitLdArg (ig, arg_idx);\r
3098                         \r
3099                         source.Emit (ec);\r
3100 \r
3101                         if (is_ref)\r
3102                                 StoreFromPtr (ig, type);\r
3103                         else {\r
3104                                 if (arg_idx <= 255)\r
3105                                         ig.Emit (OpCodes.Starg_S, (byte) arg_idx);\r
3106                                 else\r
3107                                         ig.Emit (OpCodes.Starg, arg_idx);\r
3108                         }\r
3109                 }\r
3110 \r
3111                 public void AddressOf (EmitContext ec, AddressOp mode)\r
3112                 {\r
3113                         int arg_idx = idx;\r
3114 \r
3115                         if (!ec.IsStatic)\r
3116                                 arg_idx++;\r
3117 \r
3118                         if (is_ref){\r
3119                                 if (arg_idx <= 255)\r
3120                                         ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);\r
3121                                 else\r
3122                                         ec.ig.Emit (OpCodes.Ldarg, arg_idx);\r
3123                         } else {\r
3124                                 if (arg_idx <= 255)\r
3125                                         ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);\r
3126                                 else\r
3127                                         ec.ig.Emit (OpCodes.Ldarga, arg_idx);\r
3128                         }\r
3129                 }\r
3130         }\r
3131         \r
3132         \r
3133         /// <summary>\r
3134         ///   Invocation of methods or delegates.\r
3135         /// </summary>\r
3136         public class Invocation : ExpressionStatement {\r
3137                 public ArrayList Arguments;\r
3138 \r
3139                 Expression expr;\r
3140                 MethodBase method = null;\r
3141                 bool is_base;\r
3142 \r
3143                 static Hashtable method_parameter_cache;\r
3144                 static MemberFilter CompareName;\r
3145 \r
3146                 static Invocation ()\r
3147                 {\r
3148                         method_parameter_cache = new PtrHashtable ();\r
3149                 }\r
3150                         \r
3151                 //\r
3152                 // arguments is an ArrayList, but we do not want to typecast,\r
3153                 // as it might be null.\r
3154                 //\r
3155                 // FIXME: only allow expr to be a method invocation or a\r
3156                 // delegate invocation (7.5.5)\r
3157                 //\r
3158                 public Invocation (Expression expr, ArrayList arguments, Location l)\r
3159                 {\r
3160                         this.expr = expr;\r
3161                         Arguments = arguments;\r
3162                         loc = l;\r
3163                         CompareName = new MemberFilter (compare_name_filter);\r
3164                 }\r
3165 \r
3166                 public Expression Expr {\r
3167                         get {\r
3168                                 return expr;\r
3169                         }\r
3170                 }\r
3171 \r
3172                 /// <summary>\r
3173                 ///   Returns the Parameters (a ParameterData interface) for the\r
3174                 ///   Method 'mb'\r
3175                 /// </summary>\r
3176                 public static ParameterData GetParameterData (MethodBase mb)\r
3177                 {\r
3178                         object pd = method_parameter_cache [mb];\r
3179                         object ip;\r
3180                         \r
3181                         if (pd != null)\r
3182                                 return (ParameterData) pd;\r
3183 \r
3184                         \r
3185                         ip = TypeManager.LookupParametersByBuilder (mb);\r
3186                         if (ip != null){\r
3187                                 method_parameter_cache [mb] = ip;\r
3188 \r
3189                                 return (ParameterData) ip;\r
3190                         } else {\r
3191                                 ParameterInfo [] pi = mb.GetParameters ();\r
3192                                 ReflectionParameters rp = new ReflectionParameters (pi);\r
3193                                 method_parameter_cache [mb] = rp;\r
3194 \r
3195                                 return (ParameterData) rp;\r
3196                         }\r
3197                 }\r
3198 \r
3199                 /// <summary>\r
3200                 ///  Determines "better conversion" as specified in 7.4.2.3\r
3201                 ///  Returns : 1 if a->p is better\r
3202                 ///            0 if a->q or neither is better \r
3203                 /// </summary>\r
3204                 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)\r
3205                 {\r
3206                         Type argument_type = a.Type;\r
3207                         Expression argument_expr = a.Expr;\r
3208 \r
3209                         if (argument_type == null)\r
3210                                 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");\r
3211 \r
3212                         //\r
3213                         // This is a special case since csc behaves this way. I can't find\r
3214                         // it anywhere in the spec but oh well ...\r
3215                         //\r
3216                         if (argument_expr is NullLiteral && p == TypeManager.string_type && q == TypeManager.object_type)\r
3217                                 return 1;\r
3218                         else if (argument_expr is NullLiteral && p == TypeManager.object_type && q == TypeManager.string_type)\r
3219                                 return 0;\r
3220                         \r
3221                         if (p == q)\r
3222                                 return 0;\r
3223                         \r
3224                         if (argument_type == p)\r
3225                                 return 1;\r
3226 \r
3227                         if (argument_type == q)\r
3228                                 return 0;\r
3229 \r
3230                         //\r
3231                         // Now probe whether an implicit constant expression conversion\r
3232                         // can be used.\r
3233                         //\r
3234                         // An implicit constant expression conversion permits the following\r
3235                         // conversions:\r
3236                         //\r
3237                         //    * A constant-expression of type 'int' can be converted to type\r
3238                         //      sbyte, byute, short, ushort, uint, ulong provided the value of\r
3239                         //      of the expression is withing the range of the destination type.\r
3240                         //\r
3241                         //    * A constant-expression of type long can be converted to type\r
3242                         //      ulong, provided the value of the constant expression is not negative\r
3243                         //\r
3244                         // FIXME: Note that this assumes that constant folding has\r
3245                         // taken place.  We dont do constant folding yet.\r
3246                         //\r
3247 \r
3248                         if (argument_expr is IntConstant){\r
3249                                 IntConstant ei = (IntConstant) argument_expr;\r
3250                                 int value = ei.Value;\r
3251                                 \r
3252                                 if (p == TypeManager.sbyte_type){\r
3253                                         if (value >= SByte.MinValue && value <= SByte.MaxValue)\r
3254                                                 return 1;\r
3255                                 } else if (p == TypeManager.byte_type){\r
3256                                         if (Byte.MinValue >= 0 && value <= Byte.MaxValue)\r
3257                                                 return 1;\r
3258                                 } else if (p == TypeManager.short_type){\r
3259                                         if (value >= Int16.MinValue && value <= Int16.MaxValue)\r
3260                                                 return 1;\r
3261                                 } else if (p == TypeManager.ushort_type){\r
3262                                         if (value >= UInt16.MinValue && value <= UInt16.MaxValue)\r
3263                                                 return 1;\r
3264                                 } else if (p == TypeManager.uint32_type){\r
3265                                         //\r
3266                                         // we can optimize this case: a positive int32\r
3267                                         // always fits on a uint32\r
3268                                         //\r
3269                                         if (value >= 0)\r
3270                                                 return 1;\r
3271                                 } else if (p == TypeManager.uint64_type){\r
3272                                         //\r
3273                                         // we can optimize this case: a positive int32\r
3274                                         // always fits on a uint64\r
3275                                         //\r
3276                                         if (value >= 0)\r
3277                                                 return 1;\r
3278                                 }\r
3279                         } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){\r
3280                                 LongConstant lc = (LongConstant) argument_expr;\r
3281                                 \r
3282                                 if (p == TypeManager.uint64_type){\r
3283                                         if (lc.Value > 0)\r
3284                                                 return 1;\r
3285                                 }\r
3286                         }\r
3287 \r
3288                         if (q == null) {\r
3289                                 Expression tmp = ConvertImplicit (ec, argument_expr, p, loc);\r
3290                                 \r
3291                                 if (tmp != null)\r
3292                                         return 1;\r
3293                                 else\r
3294                                         return 0;\r
3295                         }\r
3296 \r
3297                         Expression p_tmp = new EmptyExpression (p);\r
3298                         Expression q_tmp = new EmptyExpression (q);\r
3299                         \r
3300                         if (StandardConversionExists (p_tmp, q) == true &&\r
3301                             StandardConversionExists (q_tmp, p) == false)\r
3302                                 return 1;\r
3303 \r
3304                         if (p == TypeManager.sbyte_type)\r
3305                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||\r
3306                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)\r
3307                                         return 1;\r
3308 \r
3309                         if (p == TypeManager.short_type)\r
3310                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||\r
3311                                     q == TypeManager.uint64_type)\r
3312                                         return 1;\r
3313 \r
3314                         if (p == TypeManager.int32_type)\r
3315                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)\r
3316                                         return 1;\r
3317 \r
3318                         if (p == TypeManager.int64_type)\r
3319                                 if (q == TypeManager.uint64_type)\r
3320                                         return 1;\r
3321 \r
3322                         return 0;\r
3323                 }\r
3324                 \r
3325                 /// <summary>\r
3326                 ///  Determines "Better function"\r
3327                 /// </summary>\r
3328                 /// <remarks>\r
3329                 ///    and returns an integer indicating :\r
3330                 ///    0 if candidate ain't better\r
3331                 ///    1 if candidate is better than the current best match\r
3332                 /// </remarks>\r
3333                 static int BetterFunction (EmitContext ec, ArrayList args,\r
3334                                            MethodBase candidate, MethodBase best,\r
3335                                            bool expanded_form, Location loc)\r
3336                 {\r
3337                         ParameterData candidate_pd = GetParameterData (candidate);\r
3338                         ParameterData best_pd;\r
3339                         int argument_count;\r
3340                 \r
3341                         if (args == null)\r
3342                                 argument_count = 0;\r
3343                         else\r
3344                                 argument_count = args.Count;\r
3345 \r
3346                         int cand_count = candidate_pd.Count;\r
3347 \r
3348                         if (cand_count == 0 && argument_count == 0)\r
3349                                 return 1;\r
3350 \r
3351                         if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)\r
3352                                 if (cand_count != argument_count)\r
3353                                         return 0;\r
3354                         \r
3355                         if (best == null) {\r
3356                                 int x = 0;\r
3357 \r
3358                                 if (argument_count == 0 && cand_count == 1 &&\r
3359                                     candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)\r
3360                                         return 1;\r
3361                                 \r
3362                                 for (int j = argument_count; j > 0;) {\r
3363                                         j--;\r
3364 \r
3365                                         Argument a = (Argument) args [j];\r
3366                                         Type t = candidate_pd.ParameterType (j);\r
3367 \r
3368                                         if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)\r
3369                                                 if (expanded_form)\r
3370                                                         t = t.GetElementType ();\r
3371 \r
3372                                         x = BetterConversion (ec, a, t, null, loc);\r
3373                                         \r
3374                                         if (x <= 0)\r
3375                                                 break;\r
3376                                 }\r
3377 \r
3378                                 if (x > 0)\r
3379                                         return 1;\r
3380                                 else\r
3381                                         return 0;\r
3382                         }\r
3383 \r
3384                         best_pd = GetParameterData (best);\r
3385 \r
3386                         int rating1 = 0, rating2 = 0;\r
3387                         \r
3388                         for (int j = 0; j < argument_count; ++j) {\r
3389                                 int x, y;\r
3390                                 \r
3391                                 Argument a = (Argument) args [j];\r
3392 \r
3393                                 Type ct = candidate_pd.ParameterType (j);\r
3394                                 Type bt = best_pd.ParameterType (j);\r
3395 \r
3396                                 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)\r
3397                                         if (expanded_form)\r
3398                                                 ct = ct.GetElementType ();\r
3399 \r
3400                                 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)\r
3401                                         if (expanded_form)\r
3402                                                 bt = bt.GetElementType ();\r
3403                                 \r
3404                                 x = BetterConversion (ec, a, ct, bt, loc);\r
3405                                 y = BetterConversion (ec, a, bt, ct, loc);\r
3406 \r
3407                                 if (x < y)\r
3408                                         return 0;\r
3409                                 \r
3410                                 rating1 += x;\r
3411                                 rating2 += y;\r
3412                         }\r
3413 \r
3414                         if (rating1 > rating2)\r
3415                                 return 1;\r
3416                         else\r
3417                                 return 0;\r
3418                 }\r
3419 \r
3420                 public static string FullMethodDesc (MethodBase mb)\r
3421                 {\r
3422                         string ret_type = "";\r
3423 \r
3424                         if (mb is MethodInfo)\r
3425                                 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType) + " ";\r
3426                         \r
3427                         StringBuilder sb = new StringBuilder (ret_type + mb.Name);\r
3428                         ParameterData pd = GetParameterData (mb);\r
3429 \r
3430                         int count = pd.Count;\r
3431                         sb.Append (" (");\r
3432                         \r
3433                         for (int i = count; i > 0; ) {\r
3434                                 i--;\r
3435 \r
3436                                 sb.Append (pd.ParameterDesc (count - i - 1));\r
3437                                 if (i != 0)\r
3438                                         sb.Append (", ");\r
3439                         }\r
3440                         \r
3441                         sb.Append (")");\r
3442                         return sb.ToString ();\r
3443                 }\r
3444 \r
3445                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)\r
3446                 {\r
3447                         MemberInfo [] miset;\r
3448                         MethodGroupExpr union;\r
3449 \r
3450                         if (mg1 == null){\r
3451                                 if (mg2 == null)\r
3452                                         return null;\r
3453                                 return (MethodGroupExpr) mg2;\r
3454                         } else {\r
3455                                 if (mg2 == null)\r
3456                                         return (MethodGroupExpr) mg1;\r
3457                         }\r
3458                         \r
3459                         MethodGroupExpr left_set = null, right_set = null;\r
3460                         int length1 = 0, length2 = 0;\r
3461                         \r
3462                         left_set = (MethodGroupExpr) mg1;\r
3463                         length1 = left_set.Methods.Length;\r
3464                         \r
3465                         right_set = (MethodGroupExpr) mg2;\r
3466                         length2 = right_set.Methods.Length;\r
3467                         \r
3468                         ArrayList common = new ArrayList ();\r
3469 \r
3470                         foreach (MethodBase l in left_set.Methods){\r
3471                                 foreach (MethodBase r in right_set.Methods){\r
3472                                         if (l != r)\r
3473                                                 continue;\r
3474                                         common.Add (r);\r
3475                                         break;\r
3476                                 }\r
3477                         }\r
3478                         \r
3479                         miset = new MemberInfo [length1 + length2 - common.Count];\r
3480                         left_set.Methods.CopyTo (miset, 0);\r
3481                         \r
3482                         int k = length1;\r
3483 \r
3484                         foreach (MemberInfo mi in right_set.Methods){\r
3485                                 if (!common.Contains (mi))\r
3486                                         miset [k++] = mi;\r
3487                         }\r
3488                         \r
3489                         union = new MethodGroupExpr (miset, loc);\r
3490                         \r
3491                         return union;\r
3492                 }\r
3493 \r
3494                 /// <summary>\r
3495                 ///  Determines is the candidate method, if a params method, is applicable\r
3496                 ///  in its expanded form to the given set of arguments\r
3497                 /// </summary>\r
3498                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)\r
3499                 {\r
3500                         int arg_count;\r
3501                         \r
3502                         if (arguments == null)\r
3503                                 arg_count = 0;\r
3504                         else\r
3505                                 arg_count = arguments.Count;\r
3506                         \r
3507                         ParameterData pd = GetParameterData (candidate);\r
3508                         \r
3509                         int pd_count = pd.Count;\r
3510 \r
3511                         if (pd_count == 0)\r
3512                                 return false;\r
3513                         \r
3514                         if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)\r
3515                                 return false;\r
3516                         \r
3517                         if (pd_count - 1 > arg_count)\r
3518                                 return false;\r
3519                         \r
3520                         if (pd_count == 1 && arg_count == 0)\r
3521                                 return true;\r
3522 \r
3523                         //\r
3524                         // If we have come this far, the case which remains is when the number of parameters\r
3525                         // is less than or equal to the argument count.\r
3526                         //\r
3527                         for (int i = 0; i < pd_count - 1; ++i) {\r
3528 \r
3529                                 Argument a = (Argument) arguments [i];\r
3530 \r
3531                                 Parameter.Modifier a_mod = a.GetParameterModifier () &\r
3532                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);\r
3533                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &\r
3534                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);\r
3535 \r
3536                                 if (a_mod == p_mod) {\r
3537 \r
3538                                         if (a_mod == Parameter.Modifier.NONE)\r
3539                                                 if (!ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))\r
3540                                                         return false;\r
3541                                                                                 \r
3542                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {\r
3543                                                 Type pt = pd.ParameterType (i);\r
3544 \r
3545                                                 if (!pt.IsByRef)\r
3546                                                         pt = TypeManager.LookupType (pt.FullName + "&");\r
3547                                                 \r
3548                                                 if (pt != a.Type)\r
3549                                                         return false;\r
3550                                         }\r
3551                                 } else\r
3552                                         return false;\r
3553                                 \r
3554                         }\r
3555 \r
3556                         Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();\r
3557 \r
3558                         for (int i = pd_count - 1; i < arg_count; i++) {\r
3559                                 Argument a = (Argument) arguments [i];\r
3560                                 \r
3561                                 if (!StandardConversionExists (a.Expr, element_type))\r
3562                                         return false;\r
3563                         }\r
3564                         \r
3565                         return true;\r
3566                 }\r
3567 \r
3568                 static bool CheckParameterAgainstArgument (EmitContext ec, ParameterData pd, int i, Argument a, Type ptype)\r
3569                 {\r
3570                         Parameter.Modifier a_mod = a.GetParameterModifier () &\r
3571                                 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);\r
3572                         Parameter.Modifier p_mod = pd.ParameterModifier (i) &\r
3573                                 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);\r
3574 \r
3575                         if (a_mod == p_mod || (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {\r
3576                                 if (a_mod == Parameter.Modifier.NONE)\r
3577                                         if (!ImplicitConversionExists (ec, a.Expr, ptype))\r
3578                                                 return false;\r
3579                                 \r
3580                                 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {\r
3581                                         Type pt = pd.ParameterType (i);\r
3582                                         \r
3583                                         if (!pt.IsByRef)\r
3584                                                 pt = TypeManager.LookupType (pt.FullName + "&");\r
3585 \r
3586                                         if (pt != a.Type)\r
3587                                                 return false;\r
3588                                 }\r
3589                         } else\r
3590                                 return false;           \r
3591                                 \r
3592                         return true;                                    \r
3593                 }\r
3594                 \r
3595                 /// <summary>\r
3596                 ///  Determines if the candidate method is applicable (section 14.4.2.1)\r
3597                 ///  to the given set of arguments\r
3598                 /// </summary>\r
3599                 static bool IsApplicable (EmitContext ec, ref ArrayList arguments, MethodBase candidate)\r
3600                 {\r
3601                         int arg_count, ps_count, po_count;\r
3602                         Type param_type;\r
3603                         \r
3604                         if (arguments == null)\r
3605                                 arg_count = 0;\r
3606                         else\r
3607                                 arg_count = arguments.Count;\r
3608 \r
3609                         ParameterData pd = GetParameterData (candidate);\r
3610                         Parameters ps = GetFullParameters (candidate);\r
3611                         \r
3612                         if (ps == null) {\r
3613                                 ps_count = 0;\r
3614                                 po_count = 0;\r
3615                         }\r
3616                         else\r
3617                         {\r
3618                                 ps_count = ps.CountStandardParams();                    \r
3619                                 po_count = ps.CountOptionalParams();\r
3620                         }\r
3621                         int pd_count = pd.Count;\r
3622 \r
3623                         // Validate argument count\r
3624                         if (po_count == 0) {\r
3625                                 if (arg_count != pd.Count)\r
3626                                         return false;\r
3627                         }\r
3628                         else\r
3629                         {\r
3630                                 if ((arg_count < ps_count) || (arg_count > pd_count))\r
3631                                         return false;   \r
3632                         }       \r
3633                         \r
3634                         if (arg_count > 0) {\r
3635                                 for (int i = arg_count; i > 0 ; ) {\r
3636                                         i--;\r
3637 \r
3638                                         Argument a = (Argument) arguments [i];\r
3639                                         if (a.ArgType == Argument.AType.NoArg)\r
3640                                         {\r
3641                                                 Parameter p = (Parameter) ps.FixedParameters[i];\r
3642                                                 a = new Argument (p.ParameterInitializer, Argument.AType.Expression);\r
3643                                                 param_type = p.ParameterInitializer.Type;\r
3644                                         }\r
3645                                         else \r
3646                                         {\r
3647                                                 param_type = pd.ParameterType (i);\r
3648                                                 if (ps != null) {\r
3649                                                         Parameter p = (Parameter) ps.FixedParameters[i];\r
3650                                                         \r
3651                                                         if ((p.ModFlags & Parameter.Modifier.REF) != 0) \r
3652                                                         {\r
3653                                                                 a = new Argument (a.Expr, Argument.AType.Ref);\r
3654                                                                 if (!a.Resolve(ec,Location.Null))\r
3655                                                                         return false;\r
3656                                                         }\r
3657                                                 }\r
3658                                         }       \r
3659         \r
3660                                         if (!CheckParameterAgainstArgument (ec, pd, i, a, param_type))\r
3661                                                 return (false);\r
3662                                 }\r
3663                         }\r
3664                         else\r
3665                         {\r
3666                                 // If we have no arguments AND the first parameter is optional\r
3667                                 // we must check for a candidate (the loop above wouldn't)      \r
3668                                 if (po_count > 0) {\r
3669                                         ArrayList arglist = new ArrayList();\r
3670                                         \r
3671                                         // Since we got so far, there's no need to check if\r
3672                                         // arguments are optional; we simply retrieve\r
3673                                         // parameter default values and build a brand-new \r
3674                                         // argument list.\r
3675                                         \r
3676                                         for (int i = 0; i < ps.FixedParameters.Length; i++) {\r
3677                                                 Parameter p = ps.FixedParameters[i];\r
3678                                                 Argument a = new Argument (p.ParameterInitializer, Argument.AType.Expression);\r
3679                                                 a.Resolve(ec, Location.Null);\r
3680                                                 arglist.Add (a);\r
3681                                         }\r
3682                                         arguments = arglist;\r
3683                                         return true;\r
3684                                 }\r
3685                         }\r
3686                         // We've found a candidate, so we exchange the dummy NoArg arguments\r
3687                         // with new arguments containing the default value for that parameter\r
3688                         ArrayList newarglist = new ArrayList();\r
3689                         for (int i = 0; i < arg_count; i++) {\r
3690                                 Argument a = (Argument) arguments [i];\r
3691                                 Parameter p = null;\r
3692 \r
3693                                 if (ps != null)\r
3694                                         p = (Parameter) ps.FixedParameters[i];\r
3695 \r
3696                                 if (a.ArgType == Argument.AType.NoArg){\r
3697                                         a = new Argument (p.ParameterInitializer, Argument.AType.Expression);\r
3698                                         a.Resolve(ec, Location.Null);\r
3699                                 }               \r
3700                                 \r
3701                                 if ((p != null) && ((p.ModFlags & Parameter.Modifier.REF) != 0))\r
3702                                 {\r
3703                                         a.ArgType = Argument.AType.Ref;\r
3704                                         a.Resolve(ec, Location.Null);\r
3705                                 }       \r
3706                                 newarglist.Add(a);\r
3707                                 int n = pd_count - arg_count;\r
3708                                 if (n > 0) \r
3709                                 {\r
3710                                         for (int x = 0; x < n; x++) \r
3711                                         {\r
3712                                                 Parameter op = (Parameter) ps.FixedParameters[x + arg_count];\r
3713                                                 Argument b = new Argument (op.ParameterInitializer, Argument.AType.Expression);\r
3714                                                 b.Resolve(ec, Location.Null);\r
3715                                                 newarglist.Add (b);\r
3716                                         }\r
3717                                 }\r
3718                         }\r
3719                         arguments = newarglist;\r
3720                         return true;\r
3721                 }\r
3722                 \r
3723                 static bool compare_name_filter (MemberInfo m, object filterCriteria)\r
3724                 {\r
3725                         return (m.Name == ((string) filterCriteria));\r
3726                 }\r
3727 \r
3728                 static Parameters GetFullParameters (MethodBase mb)\r
3729                 {\r
3730                         TypeContainer tc = TypeManager.LookupTypeContainer (mb.DeclaringType);\r
3731                         InternalParameters ip = TypeManager.LookupParametersByBuilder(mb);\r
3732                         \r
3733                         return (ip != null) ? ip.Parameters : null;\r
3734                 }\r
3735                 \r
3736                 // We need an overload for OverloadResolve because Invocation.DoResolve\r
3737                 // must pass Arguments by reference, since a later call to IsApplicable\r
3738                 // can change the argument list if optional parameters are defined\r
3739                 // in the method declaration\r
3740                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,\r
3741                                                           ArrayList Arguments, Location loc)\r
3742                 {\r
3743                         ArrayList a = Arguments;\r
3744                         return OverloadResolve (ec, me, ref a, loc);    \r
3745                 }\r
3746                 \r
3747                 /// <summary>\r
3748                 ///   Find the Applicable Function Members (7.4.2.1)\r
3749                 ///\r
3750                 ///   me: Method Group expression with the members to select.\r
3751                 ///       it might contain constructors or methods (or anything\r
3752                 ///       that maps to a method).\r
3753                 ///\r
3754                 ///   Arguments: ArrayList containing resolved Argument objects.\r
3755                 ///\r
3756                 ///   loc: The location if we want an error to be reported, or a Null\r
3757                 ///        location for "probing" purposes.\r
3758                 ///\r
3759                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)\r
3760                 ///            that is the best match of me on Arguments.\r
3761                 ///\r
3762                 /// </summary>\r
3763                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,\r
3764                                                           ref ArrayList Arguments, Location loc)\r
3765                 {\r
3766                         ArrayList afm = new ArrayList ();\r
3767                         MethodBase method = null;\r
3768                         Type current_type = null;\r
3769                         int argument_count;\r
3770                         ArrayList candidates = new ArrayList ();\r
3771 \r
3772                         foreach (MethodBase candidate in me.Methods){\r
3773                                 int x;\r
3774 \r
3775                                 // If we're going one level higher in the class hierarchy, abort if\r
3776                                 // we already found an applicable method.\r
3777                                 if (candidate.DeclaringType != current_type) {\r
3778                                         current_type = candidate.DeclaringType;\r
3779                                         if (method != null)\r
3780                                                 break;\r
3781                                 }\r
3782 \r
3783                                 // Check if candidate is applicable (section 14.4.2.1)\r
3784                                 if (!IsApplicable (ec, ref Arguments, candidate))\r
3785                                         continue;\r
3786 \r
3787                                 candidates.Add (candidate);\r
3788                                 x = BetterFunction (ec, Arguments, candidate, method, false, loc);\r
3789                                 \r
3790                                 if (x == 0)\r
3791                                         continue;\r
3792 \r
3793                                 method = candidate;\r
3794                         }\r
3795 \r
3796                         if (Arguments == null)\r
3797                                 argument_count = 0;\r
3798                         else\r
3799                                 argument_count = Arguments.Count;\r
3800                         \r
3801                         \r
3802                         //\r
3803                         // Now we see if we can find params functions, applicable in their expanded form\r
3804                         // since if they were applicable in their normal form, they would have been selected\r
3805                         // above anyways\r
3806                         //\r
3807                         bool chose_params_expanded = false;\r
3808                         \r
3809                         if (method == null) {\r
3810                                 candidates = new ArrayList ();\r
3811                                 foreach (MethodBase candidate in me.Methods){\r
3812                                         if (!IsParamsMethodApplicable (ec, Arguments, candidate))\r
3813                                                 continue;\r
3814 \r
3815                                         candidates.Add (candidate);\r
3816 \r
3817                                         int x = BetterFunction (ec, Arguments, candidate, method, true, loc);\r
3818                                         if (x == 0)\r
3819                                                 continue;\r
3820 \r
3821                                         method = candidate; \r
3822                                         chose_params_expanded = true;\r
3823                                 }\r
3824                         }\r
3825 \r
3826                         if (method == null) {\r
3827                                 //\r
3828                                 // Okay so we have failed to find anything so we\r
3829                                 // return by providing info about the closest match\r
3830                                 //\r
3831                                 for (int i = 0; i < me.Methods.Length; ++i) {\r
3832 \r
3833                                         MethodBase c = (MethodBase) me.Methods [i];\r
3834                                         ParameterData pd = GetParameterData (c);\r
3835 \r
3836                                         if (pd.Count != argument_count)\r
3837                                                 continue;\r
3838 \r
3839                                         VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,\r
3840                                                                null, loc);\r
3841                                 }\r
3842                                 \r
3843                                 return null;\r
3844                         }\r
3845 \r
3846                         //\r
3847                         // Now check that there are no ambiguities i.e the selected method\r
3848                         // should be better than all the others\r
3849                         //\r
3850 \r
3851                         foreach (MethodBase candidate in candidates){\r
3852                                 if (candidate == method)\r
3853                                         continue;\r
3854 \r
3855                                 //\r
3856                                 // If a normal method is applicable in the sense that it has the same\r
3857                                 // number of arguments, then the expanded params method is never applicable\r
3858                                 // so we debar the params method.\r
3859                                 //\r
3860                                 if (IsParamsMethodApplicable (ec, Arguments, candidate) &&\r
3861                                     IsApplicable (ec, ref Arguments, method))\r
3862                                         continue;\r
3863                                         \r
3864                                 int x = BetterFunction (ec, Arguments, method, candidate,\r
3865                                                         chose_params_expanded, loc);\r
3866 \r
3867                                 if (x != 1) {\r
3868                                         Report.Error (\r
3869                                                 121, loc,\r
3870                                                 "Ambiguous call when selecting function due to implicit casts");\r
3871                                         return null;\r
3872                                 }\r
3873                         }\r
3874 \r
3875                         //\r
3876                         // And now check if the arguments are all compatible, perform conversions\r
3877                         // if necessary etc. and return if everything is all right\r
3878                         //\r
3879                         if (VerifyArgumentsCompat (ec, Arguments, argument_count, method,\r
3880                                                    chose_params_expanded, null, loc))\r
3881                                 return method;\r
3882                         else\r
3883                                 return null;\r
3884                 }\r
3885 \r
3886                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,\r
3887                         int argument_count,\r
3888                         MethodBase method, \r
3889                         bool chose_params_expanded,\r
3890                         Type delegate_type,\r
3891                         Location loc)\r
3892                 {\r
3893                         return (VerifyArgumentsCompat (ec, Arguments, argument_count,\r
3894                                 method, chose_params_expanded, delegate_type, loc, null));\r
3895                 }\r
3896                                                                                   \r
3897                 public static bool VerifyArgumentsCompat (EmitContext ec, \r
3898                                                           ArrayList Arguments,\r
3899                                                           int argument_count,\r
3900                                                           MethodBase method, \r
3901                                                           bool chose_params_expanded,\r
3902                                                           Type delegate_type,\r
3903                                                           Location loc,\r
3904                                                           string InvokingProperty)\r
3905                 {\r
3906                         ParameterData pd = GetParameterData (method);\r
3907                         int pd_count = pd.Count;\r
3908 \r
3909                         for (int j = 0; j < argument_count; j++) {\r
3910                                 Argument a = (Argument) Arguments [j];\r
3911                                 Expression a_expr = a.Expr;\r
3912                                 Type parameter_type = pd.ParameterType (j);\r
3913                                 \r
3914                                 if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS &&\r
3915                                     chose_params_expanded)\r
3916                                         parameter_type = TypeManager.TypeToCoreType (parameter_type.GetElementType ());\r
3917 \r
3918                                 if (a.Type != parameter_type){\r
3919                                         Expression conv;\r
3920                                         \r
3921                                         conv = ConvertImplicit (ec, a_expr, parameter_type, loc);\r
3922 \r
3923                                         if (conv == null) {\r
3924                                                 if (!Location.IsNull (loc)) {\r
3925                                                         if (delegate_type == null) \r
3926                                                                 if (InvokingProperty == null)\r
3927                                                                         Report.Error (1502, loc,\r
3928                                                                                 "The best overloaded match for method '" +\r
3929                                                                                 FullMethodDesc (method) +\r
3930                                                                                 "' has some invalid arguments");\r
3931                                                                 else\r
3932                                                                         Report.Error (1502, loc,\r
3933                                                                                 "Property '" +\r
3934                                                                                 InvokingProperty +\r
3935                                                                                 "' has some invalid arguments");\r
3936                                                         else\r
3937                                                                 Report.Error (1594, loc,\r
3938                                                                               "Delegate '" + delegate_type.ToString () +\r
3939                                                                               "' has some invalid arguments.");\r
3940                                                         Report.Error (1503, loc,\r
3941                                                          "Argument " + (j+1) +\r
3942                                                          ": Cannot convert from '" + Argument.FullDesc (a) \r
3943                                                          + "' to '" + pd.ParameterDesc (j) + "'");\r
3944                                                 }\r
3945                                                 \r
3946                                                 return false;\r
3947                                         }\r
3948                                         \r
3949                                         //\r
3950                                         // Update the argument with the implicit conversion\r
3951                                         //\r
3952                                         if (a_expr != conv)\r
3953                                                 a.Expr = conv;\r
3954                                 }\r
3955 \r
3956                                 Parameter.Modifier a_mod = a.GetParameterModifier () &\r
3957                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);\r
3958                                 Parameter.Modifier p_mod = pd.ParameterModifier (j) &\r
3959                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);\r
3960 \r
3961                                 \r
3962                                 if (a_mod != p_mod &&\r
3963                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {\r
3964                                         if (!Location.IsNull (loc)) {\r
3965                                                 Report.Error (1502, loc,\r
3966                                                        "The best overloaded match for method '" + FullMethodDesc (method)+\r
3967                                                        "' has some invalid arguments");\r
3968                                                 Report.Error (1503, loc,\r
3969                                                        "Argument " + (j+1) +\r
3970                                                        ": Cannot convert from '" + Argument.FullDesc (a) \r
3971                                                        + "' to '" + pd.ParameterDesc (j) + "'");\r
3972                                         }\r
3973                                         \r
3974                                         return false;\r
3975                                 }\r
3976                         }\r
3977 \r
3978                         return true;\r
3979                 }\r
3980 \r
3981                 public override Expression DoResolve (EmitContext ec)\r
3982                 {\r
3983                         //\r
3984                         // First, resolve the expression that is used to\r
3985                         // trigger the invocation\r
3986                         //\r
3987                         Expression expr_to_return = null;\r
3988 \r
3989                         if (expr is BaseAccess)\r
3990                                 is_base = true;\r
3991 \r
3992                         expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);\r
3993                         if (expr == null)\r
3994                                 return null;\r
3995                 \r
3996                         if (expr is Invocation) {\r
3997                                 // FIXME Calls which return an Array are not resolved (here or in the grammar)\r
3998                                 expr = expr.Resolve(ec);\r
3999                         }\r
4000 \r
4001                         if (!(expr is MethodGroupExpr)) \r
4002                         {\r
4003                                 Type expr_type = expr.Type;\r
4004 \r
4005                                 if (expr_type != null)\r
4006                                 {\r
4007                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);\r
4008                                         if (IsDelegate)\r
4009                                                 return (new DelegateInvocation (\r
4010                                                         this.expr, Arguments, loc)).Resolve (ec);\r
4011                                 }\r
4012                         }\r
4013 \r
4014                         //\r
4015                         // Next, evaluate all the expressions in the argument list\r
4016                         //\r
4017                         if (Arguments != null)\r
4018                         {\r
4019                                 foreach (Argument a in Arguments)\r
4020                                 {\r
4021                                         if ((a.ArgType == Argument.AType.NoArg) && (!(expr is MethodGroupExpr)))\r
4022                                                 Report.Error (999, "This item cannot have empty arguments");\r
4023                                         \r
4024                                         if (!a.Resolve (ec, loc))\r
4025                                                 return null;                            \r
4026                                 }\r
4027                         }\r
4028 \r
4029                         if (expr is MethodGroupExpr) \r
4030                         {\r
4031                                 MethodGroupExpr mg = (MethodGroupExpr) expr;\r
4032                                 method = OverloadResolve (ec, mg, ref Arguments, loc);\r
4033 \r
4034                                 if (method == null)\r
4035                                 {\r
4036                                         Error (-6,\r
4037                                                 "Could not find any applicable function for this argument list");\r
4038                                         return null;\r
4039                                 }\r
4040 \r
4041                                 if ((method as MethodInfo) != null) \r
4042                                 {\r
4043                                         MethodInfo mi = method as MethodInfo;\r
4044                                         type = TypeManager.TypeToCoreType (mi.ReturnType);\r
4045                                         if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))\r
4046                                                 SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);\r
4047                                 }\r
4048 \r
4049                                 if ((method as ConstructorInfo) != null) \r
4050                                 {\r
4051                                         ConstructorInfo ci = method as ConstructorInfo;\r
4052                                         type = TypeManager.void_type;\r
4053                                         if (!ci.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))\r
4054                                                 SimpleName.Error_ObjectRefRequired (ec, loc, ci.Name);\r
4055                                 }\r
4056 \r
4057                                 if (type.IsPointer)\r
4058                                 {\r
4059                                         if (!ec.InUnsafe)\r
4060                                         {\r
4061                                                 UnsafeError (loc);\r
4062                                                 return null;\r
4063                                         }\r
4064                                 }\r
4065                                 eclass = ExprClass.Value;\r
4066                                 expr_to_return = this;\r
4067                         }\r
4068 \r
4069                         if (expr is PropertyExpr) \r
4070                         {\r
4071                                 PropertyExpr pe = ((PropertyExpr) expr);\r
4072                                 pe.PropertyArgs = (ArrayList) Arguments.Clone();\r
4073                                 Arguments.Clear();\r
4074                                 Arguments = new ArrayList();\r
4075                                 MethodBase mi = pe.PropertyInfo.GetGetMethod(true);\r
4076 \r
4077                                 if(VerifyArgumentsCompat (ec, pe.PropertyArgs, \r
4078                                         pe.PropertyArgs.Count, mi, false, null, loc, pe.Name)) \r
4079                                 {\r
4080 \r
4081                                         expr_to_return = pe.DoResolve (ec);\r
4082                                         expr_to_return.eclass = ExprClass.PropertyAccess;\r
4083                                 }\r
4084                         }\r
4085 \r
4086                         if (expr is FieldExpr || expr is LocalVariableReference) {\r
4087                                 // If we are here, expr must be an ArrayAccess\r
4088                                 // FIXME: we should check dimensions, etc.\r
4089                                 ArrayList idxs = new ArrayList();\r
4090                                 foreach (Argument a in Arguments) \r
4091                                 {\r
4092                                         idxs.Add (a.Expr);\r
4093                                 }\r
4094                                 ElementAccess ea = new ElementAccess (expr, idxs, expr.Location);\r
4095                                 ArrayAccess aa = new ArrayAccess (ea, expr.Location);\r
4096                                 expr_to_return = aa.DoResolve(ec);\r
4097                                 expr_to_return.eclass = ExprClass.Variable;\r
4098                         }\r
4099 \r
4100                         return expr_to_return;\r
4101                 }\r
4102 \r
4103                 // <summary>\r
4104                 //   Emits the list of arguments as an array\r
4105                 // </summary>\r
4106                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)\r
4107                 {\r
4108                         ILGenerator ig = ec.ig;\r
4109                         int count = arguments.Count - idx;\r
4110                         Argument a = (Argument) arguments [idx];\r
4111                         Type t = a.Expr.Type;\r
4112                         string array_type = t.FullName + "[]";\r
4113                         LocalBuilder array;\r
4114 \r
4115                         array = ig.DeclareLocal (TypeManager.LookupType (array_type));\r
4116                         IntConstant.EmitInt (ig, count);\r
4117                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));\r
4118                         ig.Emit (OpCodes.Stloc, array);\r
4119 \r
4120                         int top = arguments.Count;\r
4121                         for (int j = idx; j < top; j++){\r
4122                                 a = (Argument) arguments [j];\r
4123                                 \r
4124                                 ig.Emit (OpCodes.Ldloc, array);\r
4125                                 IntConstant.EmitInt (ig, j - idx);\r
4126                                 a.Emit (ec);\r
4127                                 \r
4128                                 ArrayAccess.EmitStoreOpcode (ig, t);\r
4129                         }\r
4130                         ig.Emit (OpCodes.Ldloc, array);\r
4131                 }\r
4132                 \r
4133                 /// <summary>\r
4134                 ///   Emits a list of resolved Arguments that are in the arguments\r
4135                 ///   ArrayList.\r
4136                 /// \r
4137                 ///   The MethodBase argument might be null if the\r
4138                 ///   emission of the arguments is known not to contain\r
4139                 ///   a 'params' field (for example in constructors or other routines\r
4140                 ///   that keep their arguments in this structure)\r
4141                 /// </summary>\r
4142                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)\r
4143                 {\r
4144                         ParameterData pd;\r
4145                         if (mb != null)\r
4146                                 pd = GetParameterData (mb);\r
4147                         else\r
4148                                 pd = null;\r
4149 \r
4150                         //\r
4151                         // If we are calling a params method with no arguments, special case it\r
4152                         //\r
4153                         if (arguments == null){\r
4154                                 if (pd != null && pd.Count > 0 &&\r
4155                                     pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){\r
4156                                         ILGenerator ig = ec.ig;\r
4157 \r
4158                                         IntConstant.EmitInt (ig, 0);\r
4159                                         ig.Emit (OpCodes.Newarr, pd.ParameterType (0).GetElementType ());\r
4160                                 }\r
4161                                 return;\r
4162                         }\r
4163 \r
4164                         int top = arguments.Count;\r
4165 \r
4166                         for (int i = 0; i < top; i++){\r
4167                                 Argument a = (Argument) arguments [i];\r
4168 \r
4169                                 if (pd != null){\r
4170                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){\r
4171                                                 //\r
4172                                                 // Special case if we are passing the same data as the\r
4173                                                 // params argument, do not put it in an array.\r
4174                                                 //\r
4175                                                 if (pd.ParameterType (i) == a.Type)\r
4176                                                         a.Emit (ec);\r
4177                                                 else\r
4178                                                         EmitParams (ec, i, arguments);\r
4179                                                 return;\r
4180                                         }\r
4181                                 }\r
4182                                             \r
4183                                 a.Emit (ec);\r
4184                         }\r
4185 \r
4186                         if (pd != null && pd.Count > top &&\r
4187                             pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){\r
4188                                 ILGenerator ig = ec.ig;\r
4189 \r
4190                                 IntConstant.EmitInt (ig, 0);\r
4191                                 ig.Emit (OpCodes.Newarr, pd.ParameterType (top).GetElementType ());\r
4192                         }\r
4193                 }\r
4194 \r
4195                 /// <remarks>\r
4196                 ///   is_base tells whether we want to force the use of the 'call'\r
4197                 ///   opcode instead of using callvirt.  Call is required to call\r
4198                 ///   a specific method, while callvirt will always use the most\r
4199                 ///   recent method in the vtable.\r
4200                 ///\r
4201                 ///   is_static tells whether this is an invocation on a static method\r
4202                 ///\r
4203                 ///   instance_expr is an expression that represents the instance\r
4204                 ///   it must be non-null if is_static is false.\r
4205                 ///\r
4206                 ///   method is the method to invoke.\r
4207                 ///\r
4208                 ///   Arguments is the list of arguments to pass to the method or constructor.\r
4209                 /// </remarks>\r
4210                 public static void EmitCall (EmitContext ec, bool is_base,\r
4211                                              bool is_static, Expression instance_expr,\r
4212                                              MethodBase method, ArrayList Arguments, Location loc)\r
4213                 {\r
4214                         EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, null, loc);\r
4215                 }\r
4216                 \r
4217                 public static void EmitCall (EmitContext ec, bool is_base,\r
4218                         bool is_static, Expression instance_expr,\r
4219                         MethodBase method, ArrayList Arguments, ArrayList prop_args, Location loc)\r
4220                 {\r
4221                         ILGenerator ig = ec.ig;\r
4222                         bool struct_call = false;\r
4223 \r
4224                         Type decl_type = method.DeclaringType;\r
4225 \r
4226                         if (!RootContext.StdLib) \r
4227                         {\r
4228                                 // Replace any calls to the system's System.Array type with calls to\r
4229                                 // the newly created one.\r
4230                                 if (method == TypeManager.system_int_array_get_length)\r
4231                                         method = TypeManager.int_array_get_length;\r
4232                                 else if (method == TypeManager.system_int_array_get_rank)\r
4233                                         method = TypeManager.int_array_get_rank;\r
4234                                 else if (method == TypeManager.system_object_array_clone)\r
4235                                         method = TypeManager.object_array_clone;\r
4236                                 else if (method == TypeManager.system_int_array_get_length_int)\r
4237                                         method = TypeManager.int_array_get_length_int;\r
4238                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)\r
4239                                         method = TypeManager.int_array_get_lower_bound_int;\r
4240                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)\r
4241                                         method = TypeManager.int_array_get_upper_bound_int;\r
4242                                 else if (method == TypeManager.system_void_array_copyto_array_int)\r
4243                                         method = TypeManager.void_array_copyto_array_int;\r
4244                         }\r
4245 \r
4246                         //\r
4247                         // This checks the 'ConditionalAttribute' on the method, and the\r
4248                         // ObsoleteAttribute\r
4249                         //\r
4250                         TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc);\r
4251                         if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0)\r
4252                                 return;\r
4253                         if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)\r
4254                                 return;\r
4255                         \r
4256                         if (!is_static)\r
4257                         {\r
4258                                 if (decl_type.IsValueType)\r
4259                                         struct_call = true;\r
4260                                 //\r
4261                                 // If this is ourselves, push "this"\r
4262                                 //\r
4263                                 if (instance_expr == null)\r
4264                                 {\r
4265                                         ig.Emit (OpCodes.Ldarg_0);\r
4266                                 } \r
4267                                 else \r
4268                                 {\r
4269                                         //\r
4270                                         // Push the instance expression\r
4271                                         //\r
4272                                         if (instance_expr.Type.IsValueType)\r
4273                                         {\r
4274                                                 //\r
4275                                                 // Special case: calls to a function declared in a \r
4276                                                 // reference-type with a value-type argument need\r
4277                                                 // to have their value boxed.  \r
4278 \r
4279                                                 struct_call = true;\r
4280                                                 if (decl_type.IsValueType)\r
4281                                                 {\r
4282                                                         //\r
4283                                                         // If the expression implements IMemoryLocation, then\r
4284                                                         // we can optimize and use AddressOf on the\r
4285                                                         // return.\r
4286                                                         //\r
4287                                                         // If not we have to use some temporary storage for\r
4288                                                         // it.\r
4289                                                         if (instance_expr is IMemoryLocation)\r
4290                                                         {\r
4291                                                                 ((IMemoryLocation)instance_expr).\r
4292                                                                         AddressOf (ec, AddressOp.LoadStore);\r
4293                                                         }\r
4294                                                         else \r
4295                                                         {\r
4296                                                                 Type t = instance_expr.Type;\r
4297                                                                 \r
4298                                                                 instance_expr.Emit (ec);\r
4299                                                                 LocalBuilder temp = ig.DeclareLocal (t);\r
4300                                                                 ig.Emit (OpCodes.Stloc, temp);\r
4301                                                                 ig.Emit (OpCodes.Ldloca, temp);\r
4302                                                         }\r
4303                                                 } \r
4304                                                 else \r
4305                                                 {\r
4306                                                         instance_expr.Emit (ec);\r
4307                                                         ig.Emit (OpCodes.Box, instance_expr.Type);\r
4308                                                 } \r
4309                                         } \r
4310                                         else\r
4311                                                 instance_expr.Emit (ec);\r
4312                                 }\r
4313                         }\r
4314                         \r
4315                         if (prop_args != null && prop_args.Count > 0)\r
4316                         {\r
4317                                 if (Arguments == null) \r
4318                                         Arguments = new ArrayList();\r
4319 \r
4320                                 for (int i = prop_args.Count-1; i >=0 ; i--) \r
4321                                 {\r
4322                                         Arguments.Insert (0,prop_args[i]);\r
4323                                 }\r
4324 \r
4325                         }\r
4326 \r
4327                         EmitArguments (ec, method, Arguments);\r
4328 \r
4329                         if (is_static || struct_call || is_base)\r
4330                         {\r
4331                                 if (method is MethodInfo) \r
4332                                 {\r
4333                                         ig.Emit (OpCodes.Call, (MethodInfo) method);\r
4334                                 } \r
4335                                 else\r
4336                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);\r
4337                         } \r
4338                         else \r
4339                         {\r
4340                                 if (method is MethodInfo)\r
4341                                         ig.Emit (OpCodes.Callvirt, (MethodInfo) method);\r
4342                                 else\r
4343                                         ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);\r
4344                         }\r
4345                 }\r
4346                 \r
4347                 static void EmitPropertyArgs (EmitContext ec, ArrayList prop_args)\r
4348                 {\r
4349                         int top = prop_args.Count;\r
4350 \r
4351                         for (int i = 0; i < top; i++)\r
4352                         {\r
4353                                 Argument a = (Argument) prop_args [i];\r
4354                                 a.Emit (ec);\r
4355                         }\r
4356                 }\r
4357 \r
4358                 public override void Emit (EmitContext ec)\r
4359                 {\r
4360                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;\r
4361 \r
4362                         EmitCall (\r
4363                                 ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);\r
4364                 }\r
4365                 \r
4366                 public override void EmitStatement (EmitContext ec)\r
4367                 {\r
4368                         Emit (ec);\r
4369 \r
4370                         // \r
4371                         // Pop the return value if there is one\r
4372                         //\r
4373                         if (method is MethodInfo){\r
4374                                 Type ret = ((MethodInfo)method).ReturnType;\r
4375                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)\r
4376                                         ec.ig.Emit (OpCodes.Pop);\r
4377                         }\r
4378                 }\r
4379         }\r
4380 \r
4381         //\r
4382         // This class is used to "disable" the code generation for the\r
4383         // temporary variable when initializing value types.\r
4384         //\r
4385         class EmptyAddressOf : EmptyExpression, IMemoryLocation {\r
4386                 public void AddressOf (EmitContext ec, AddressOp Mode)\r
4387                 {\r
4388                         // nothing\r
4389                 }\r
4390         }\r
4391         \r
4392         /// <summary>\r
4393         ///    Implements the new expression \r
4394         /// </summary>\r
4395         public class New : ExpressionStatement {\r
4396                 public readonly ArrayList Arguments;\r
4397                 public readonly Expression RequestedType;\r
4398 \r
4399                 MethodBase method = null;\r
4400 \r
4401                 //\r
4402                 // If set, the new expression is for a value_target, and\r
4403                 // we will not leave anything on the stack.\r
4404                 //\r
4405                 Expression value_target;\r
4406                 bool value_target_set = false;\r
4407                 \r
4408                 public New (Expression requested_type, ArrayList arguments, Location l)\r
4409                 {\r
4410                         RequestedType = requested_type;\r
4411                         Arguments = arguments;\r
4412                         loc = l;\r
4413                 }\r
4414 \r
4415                 public Expression ValueTypeVariable {\r
4416                         get {\r
4417                                 return value_target;\r
4418                         }\r
4419 \r
4420                         set {\r
4421                                 value_target = value;\r
4422                                 value_target_set = true;\r
4423                         }\r
4424                 }\r
4425 \r
4426                 //\r
4427                 // This function is used to disable the following code sequence for\r
4428                 // value type initialization:\r
4429                 //\r
4430                 // AddressOf (temporary)\r
4431                 // Construct/Init\r
4432                 // LoadTemporary\r
4433                 //\r
4434                 // Instead the provide will have provided us with the address on the\r
4435                 // stack to store the results.\r
4436                 //\r
4437                 static Expression MyEmptyExpression;\r
4438                 \r
4439                 public void DisableTemporaryValueType ()\r
4440                 {\r
4441                         if (MyEmptyExpression == null)\r
4442                                 MyEmptyExpression = new EmptyAddressOf ();\r
4443 \r
4444                         //\r
4445                         // To enable this, look into:\r
4446                         // test-34 and test-89 and self bootstrapping.\r
4447                         //\r
4448                         // For instance, we can avoid a copy by using 'newobj'\r
4449                         // instead of Call + Push-temp on value types.\r
4450 //                      value_target = MyEmptyExpression;\r
4451                 }\r
4452                 \r
4453                 public override Expression DoResolve (EmitContext ec)\r
4454                 {\r
4455                         type = ec.DeclSpace.ResolveType (RequestedType, false, loc);\r
4456                         \r
4457                         if (type == null)\r
4458                                 return null;\r
4459                         \r
4460                         bool IsDelegate = TypeManager.IsDelegateType (type);\r
4461                         \r
4462                         if (IsDelegate)\r
4463                                 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);\r
4464 \r
4465                         if (type.IsInterface || type.IsAbstract){\r
4466                                 Error (\r
4467                                         144, "It is not possible to create instances of interfaces " +\r
4468                                         "or abstract classes");\r
4469                                 return null;\r
4470                         }\r
4471                         \r
4472                         bool is_struct = false;\r
4473                         is_struct = type.IsValueType;\r
4474                         eclass = ExprClass.Value;\r
4475 \r
4476                         //\r
4477                         // SRE returns a match for .ctor () on structs (the object constructor), \r
4478                         // so we have to manually ignore it.\r
4479                         //\r
4480                         if (is_struct && Arguments == null)\r
4481                                 return this;\r
4482                         \r
4483                         Expression ml;\r
4484                         ml = MemberLookupFinal (ec, type, ".ctor",\r
4485                                                 MemberTypes.Constructor,\r
4486                                                 AllBindingFlags | BindingFlags.Public, loc);\r
4487 \r
4488                         if (ml == null)\r
4489                                 return null;\r
4490                         \r
4491                         if (! (ml is MethodGroupExpr)){\r
4492                                 if (!is_struct){\r
4493                                         ml.Error118 ("method group");\r
4494                                         return null;\r
4495                                 }\r
4496                         }\r
4497 \r
4498                         if (ml != null) {\r
4499                                 if (Arguments != null){\r
4500                                         foreach (Argument a in Arguments){\r
4501                                                 if (!a.Resolve (ec, loc))\r
4502                                                         return null;\r
4503                                         }\r
4504                                 }\r
4505 \r
4506                                 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,\r
4507                                                                      Arguments, loc);\r
4508                                 \r
4509                         }\r
4510 \r
4511                         if (method == null) { \r
4512                                 if (!is_struct || Arguments.Count > 0) {\r
4513                                         Error (1501,\r
4514                                                "New invocation: Can not find a constructor for " +\r
4515                                                "this argument list");\r
4516                                         return null;\r
4517                                 }\r
4518                         }\r
4519                         return this;\r
4520                 }\r
4521 \r
4522                 //\r
4523                 // This DoEmit can be invoked in two contexts:\r
4524                 //    * As a mechanism that will leave a value on the stack (new object)\r
4525                 //    * As one that wont (init struct)\r
4526                 //\r
4527                 // You can control whether a value is required on the stack by passing\r
4528                 // need_value_on_stack.  The code *might* leave a value on the stack\r
4529                 // so it must be popped manually\r
4530                 //\r
4531                 // If we are dealing with a ValueType, we have a few\r
4532                 // situations to deal with:\r
4533                 //\r
4534                 //    * The target is a ValueType, and we have been provided\r
4535                 //      the instance (this is easy, we are being assigned).\r
4536                 //\r
4537                 //    * The target of New is being passed as an argument,\r
4538                 //      to a boxing operation or a function that takes a\r
4539                 //      ValueType.\r
4540                 //\r
4541                 //      In this case, we need to create a temporary variable\r
4542                 //      that is the argument of New.\r
4543                 //\r
4544                 // Returns whether a value is left on the stack\r
4545                 //\r
4546                 bool DoEmit (EmitContext ec, bool need_value_on_stack)\r
4547                 {\r
4548                         bool is_value_type = type.IsValueType;\r
4549                         ILGenerator ig = ec.ig;\r
4550 \r
4551                         if (is_value_type){\r
4552                                 IMemoryLocation ml;\r
4553 \r
4554                                 // Allow DoEmit() to be called multiple times.\r
4555                                 // We need to create a new LocalTemporary each time since\r
4556                                 // you can't share LocalBuilders among ILGeneators.\r
4557                                 if (!value_target_set)\r
4558                                         value_target = new LocalTemporary (ec, type);\r
4559                                         \r
4560                                 ml = (IMemoryLocation) value_target;\r
4561                                 ml.AddressOf (ec, AddressOp.Store);\r
4562                         }\r
4563 \r
4564                         if (method != null)\r
4565                                 Invocation.EmitArguments (ec, method, Arguments);\r
4566 \r
4567                         if (is_value_type){\r
4568                                 if (method == null)\r
4569                                         ig.Emit (OpCodes.Initobj, type);\r
4570                                 else \r
4571                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);\r
4572                                 if (need_value_on_stack){\r
4573                                         value_target.Emit (ec);\r
4574                                         return true;\r
4575                                 }\r
4576                                 return false;\r
4577                         } else {\r
4578                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);\r
4579                                 return true;\r
4580                         }\r
4581                 }\r
4582 \r
4583                 public override void Emit (EmitContext ec)\r
4584                 {\r
4585                         DoEmit (ec, true);\r
4586                 }\r
4587                 \r
4588                 public override void EmitStatement (EmitContext ec)\r
4589                 {\r
4590                         if (DoEmit (ec, false))\r
4591                                 ec.ig.Emit (OpCodes.Pop);\r
4592                 }\r
4593         }\r
4594 \r
4595         /// <summary>\r
4596         ///   14.5.10.2: Represents an array creation expression.\r
4597         /// </summary>\r
4598         ///\r
4599         /// <remarks>\r
4600         ///   There are two possible scenarios here: one is an array creation\r
4601         ///   expression that specifies the dimensions and optionally the\r
4602         ///   initialization data and the other which does not need dimensions\r
4603         ///   specified but where initialization data is mandatory.\r
4604         /// </remarks>\r
4605         public class ArrayCreation : ExpressionStatement {\r
4606                 Expression requested_base_type;\r
4607                 ArrayList initializers;\r
4608 \r
4609                 //\r
4610                 // The list of Argument types.\r
4611                 // This is used to construct the 'newarray' or constructor signature\r
4612                 //\r
4613                 ArrayList arguments;\r
4614 \r
4615                 //\r
4616                 // Method used to create the array object.\r
4617                 //\r
4618                 MethodBase new_method = null;\r
4619                 \r
4620                 Type array_element_type;\r
4621                 Type underlying_type;\r
4622                 bool is_one_dimensional = false;\r
4623                 bool is_builtin_type = false;\r
4624                 bool expect_initializers = false;\r
4625                 int num_arguments = 0;\r
4626                 int dimensions = 0;\r
4627                 string rank;\r
4628 \r
4629                 ArrayList array_data;\r
4630 \r
4631                 Hashtable bounds;\r
4632 \r
4633                 //\r
4634                 // The number of array initializers that we can handle\r
4635                 // via the InitializeArray method - through EmitStaticInitializers\r
4636                 //\r
4637                 int num_automatic_initializers;\r
4638                 \r
4639                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)\r
4640                 {\r
4641                         this.requested_base_type = requested_base_type;\r
4642                         this.initializers = initializers;\r
4643                         this.rank = rank;\r
4644                         loc = l;\r
4645 \r
4646                         arguments = new ArrayList ();\r
4647 \r
4648                         foreach (Expression e in exprs) {\r
4649                                 arguments.Add (new Argument (e, Argument.AType.Expression));\r
4650                                 num_arguments++;\r
4651                         }\r
4652                 }\r
4653 \r
4654                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)\r
4655                 {\r
4656                         this.requested_base_type = requested_base_type;\r
4657                         this.initializers = initializers;\r
4658                         this.rank = rank;\r
4659                         loc = l;\r
4660 \r
4661                         //this.rank = rank.Substring (0, rank.LastIndexOf ("["));\r
4662                         //\r
4663                         //string tmp = rank.Substring (rank.LastIndexOf ("["));\r
4664                         //\r
4665                         //dimensions = tmp.Length - 1;\r
4666                         expect_initializers = true;\r
4667                 }\r
4668 \r
4669                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)\r
4670                 {\r
4671                         StringBuilder sb = new StringBuilder (rank);\r
4672                         \r
4673                         sb.Append ("[");\r
4674                         for (int i = 1; i < idx_count; i++)\r
4675                                 sb.Append (",");\r
4676                         \r
4677                         sb.Append ("]");\r
4678 \r
4679                         return new ComposedCast (base_type, sb.ToString (), loc);\r
4680                 }\r
4681 \r
4682                 void Error_IncorrectArrayInitializer ()\r
4683                 {\r
4684                         Error (178, "Incorrectly structured array initializer");\r
4685                 }\r
4686                 \r
4687                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)\r
4688                 {\r
4689                         if (specified_dims) { \r
4690                                 Argument a = (Argument) arguments [idx];\r
4691                                 \r
4692                                 if (!a.Resolve (ec, loc))\r
4693                                         return false;\r
4694                                 \r
4695                                 if (!(a.Expr is Constant)) {\r
4696                                         Error (150, "A constant value is expected");\r
4697                                         return false;\r
4698                                 }\r
4699                                 \r
4700                                 int value = (int) ((Constant) a.Expr).GetValue ();\r
4701                                 \r
4702                                 if (value != probe.Count) {\r
4703                                         Error_IncorrectArrayInitializer ();\r
4704                                         return false;\r
4705                                 }\r
4706                                 \r
4707                                 bounds [idx] = value;\r
4708                         }\r
4709 \r
4710                         int child_bounds = -1;\r
4711                         foreach (object o in probe) {\r
4712                                 if (o is ArrayList) {\r
4713                                         int current_bounds = ((ArrayList) o).Count;\r
4714                                         \r
4715                                         if (child_bounds == -1) \r
4716                                                 child_bounds = current_bounds;\r
4717 \r
4718                                         else if (child_bounds != current_bounds){\r
4719                                                 Error_IncorrectArrayInitializer ();\r
4720                                                 return false;\r
4721                                         }\r
4722                                         bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);\r
4723                                         if (!ret)\r
4724                                                 return false;\r
4725                                 } else {\r
4726                                         if (child_bounds != -1){\r
4727                                                 Error_IncorrectArrayInitializer ();\r
4728                                                 return false;\r
4729                                         }\r
4730                                         \r
4731                                         Expression tmp = (Expression) o;\r
4732                                         tmp = tmp.Resolve (ec);\r
4733                                         if (tmp == null)\r
4734                                                 continue;\r
4735 \r
4736                                         // Console.WriteLine ("I got: " + tmp);\r
4737                                         // Handle initialization from vars, fields etc.\r
4738 \r
4739                                         Expression conv = ConvertImplicitRequired (\r
4740                                                 ec, tmp, underlying_type, loc);\r
4741                                         \r
4742                                         if (conv == null) \r
4743                                                 return false;\r
4744 \r
4745                                         if (conv is StringConstant)\r
4746                                                 array_data.Add (conv);\r
4747                                         else if (conv is Constant) {\r
4748                                                 array_data.Add (conv);\r
4749                                                 num_automatic_initializers++;\r
4750                                         } else\r
4751                                                 array_data.Add (conv);\r
4752                                 }\r
4753                         }\r
4754 \r
4755                         return true;\r
4756                 }\r
4757                 \r
4758                 public void UpdateIndices (EmitContext ec)\r
4759                 {\r
4760                         int i = 0;\r
4761                         for (ArrayList probe = initializers; probe != null;) {\r
4762                                 if (probe.Count > 0 && probe [0] is ArrayList) {\r
4763                                         Expression e = new IntConstant (probe.Count);\r
4764                                         arguments.Add (new Argument (e, Argument.AType.Expression));\r
4765 \r
4766                                         bounds [i++] =  probe.Count;\r
4767                                         \r
4768                                         probe = (ArrayList) probe [0];\r
4769                                         \r
4770                                 } else {\r
4771                                         Expression e = new IntConstant (probe.Count);\r
4772                                         arguments.Add (new Argument (e, Argument.AType.Expression));\r
4773 \r
4774                                         bounds [i++] = probe.Count;\r
4775                                         probe = null;\r
4776                                 }\r
4777                         }\r
4778 \r
4779                 }\r
4780                 \r
4781                 public bool ValidateInitializers (EmitContext ec, Type array_type)\r
4782                 {\r
4783                         if (initializers == null) {\r
4784                                 if (expect_initializers)\r
4785                                         return false;\r
4786                                 else\r
4787                                         return true;\r
4788                         }\r
4789                         \r
4790                         if (underlying_type == null)\r
4791                                 return false;\r
4792                         \r
4793                         //\r
4794                         // We use this to store all the date values in the order in which we\r
4795                         // will need to store them in the byte blob later\r
4796                         //\r
4797                         array_data = new ArrayList ();\r
4798                         bounds = new Hashtable ();\r
4799                         \r
4800                         bool ret;\r
4801 \r
4802                         if (arguments != null) {\r
4803                                 ret = CheckIndices (ec, initializers, 0, true);\r
4804                                 return ret;\r
4805                         } else {\r
4806                                 arguments = new ArrayList ();\r
4807 \r
4808                                 ret = CheckIndices (ec, initializers, 0, false);\r
4809                                 \r
4810                                 if (!ret)\r
4811                                         return false;\r
4812                                 \r
4813                                 UpdateIndices (ec);\r
4814                                 \r
4815                                 if (arguments.Count != dimensions) {\r
4816                                         Error_IncorrectArrayInitializer ();\r
4817                                         return false;\r
4818                                 }\r
4819 \r
4820                                 return ret;\r
4821                         }\r
4822                 }\r
4823 \r
4824                 void Error_NegativeArrayIndex ()\r
4825                 {\r
4826                         Error (284, "Can not create array with a negative size");\r
4827                 }\r
4828                 \r
4829                 //\r
4830                 // Converts 'source' to an int, uint, long or ulong.\r
4831                 //\r
4832                 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)\r
4833                 {\r
4834                         Expression target;\r
4835                         \r
4836                         bool old_checked = ec.CheckState;\r
4837                         ec.CheckState = true;\r
4838                         \r
4839                         target = ConvertImplicit (ec, source, TypeManager.int32_type, loc);\r
4840                         if (target == null){\r
4841                                 target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);\r
4842                                 if (target == null){\r
4843                                         target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);\r
4844                                         if (target == null){\r
4845                                                 target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);\r
4846                                                 if (target == null)\r
4847                                                         Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type);\r
4848                                         }\r
4849                                 }\r
4850                         } \r
4851                         ec.CheckState = old_checked;\r
4852 \r
4853                         //\r
4854                         // Only positive constants are allowed at compile time\r
4855                         //\r
4856                         if (target is Constant){\r
4857                                 if (target is IntConstant){\r
4858                                         if (((IntConstant) target).Value < 0){\r
4859                                                 Error_NegativeArrayIndex ();\r
4860                                                 return null;\r
4861                                         }\r
4862                                 }\r
4863 \r
4864                                 if (target is LongConstant){\r
4865                                         if (((LongConstant) target).Value < 0){\r
4866                                                 Error_NegativeArrayIndex ();\r
4867                                                 return null;\r
4868                                         }\r
4869                                 }\r
4870                                 \r
4871                         }\r
4872 \r
4873                         return target;\r
4874                 }\r
4875 \r
4876                 //\r
4877                 // Creates the type of the array\r
4878                 //\r
4879                 bool LookupType (EmitContext ec)\r
4880                 {\r
4881                         StringBuilder array_qualifier = new StringBuilder (rank);\r
4882 \r
4883                         //\r
4884                         // 'In the first form allocates an array instace of the type that results\r
4885                         // from deleting each of the individual expression from the expression list'\r
4886                         //\r
4887                         if (num_arguments > 0) {\r
4888                                 array_qualifier.Append ("[");\r
4889                                 for (int i = num_arguments-1; i > 0; i--)\r
4890                                         array_qualifier.Append (",");\r
4891                                 array_qualifier.Append ("]");                           \r
4892                         }\r
4893 \r
4894                         //\r
4895                         // Lookup the type\r
4896                         //\r
4897                         Expression array_type_expr;\r
4898                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);\r
4899                         string sss = array_qualifier.ToString ();\r
4900                         type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);\r
4901 \r
4902                         if (type == null)\r
4903                                 return false;\r
4904 \r
4905                         underlying_type = type;\r
4906                         if (underlying_type.IsArray)\r
4907                                 underlying_type = TypeManager.TypeToCoreType (underlying_type.GetElementType ());\r
4908                         dimensions = type.GetArrayRank ();\r
4909 \r
4910                         return true;\r
4911                 }\r
4912                 \r
4913                 public override Expression DoResolve (EmitContext ec)\r
4914                 {\r
4915                         int arg_count;\r
4916 \r
4917                         if (!LookupType (ec))\r
4918                                 return null;\r
4919                         \r
4920                         //\r
4921                         // First step is to validate the initializers and fill\r
4922                         // in any missing bits\r
4923                         //\r
4924                         if (!ValidateInitializers (ec, type))\r
4925                                 return null;\r
4926 \r
4927                         if (arguments == null)\r
4928                                 arg_count = 0;\r
4929                         else {\r
4930                                 arg_count = arguments.Count;\r
4931                                 foreach (Argument a in arguments){\r
4932                                         if (!a.Resolve (ec, loc))\r
4933                                                 return null;\r
4934 \r
4935                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);\r
4936                                         if (real_arg == null)\r
4937                                                 return null;\r
4938 \r
4939                                         a.Expr = real_arg;\r
4940                                 }\r
4941                         }\r
4942                         \r
4943                         array_element_type = TypeManager.TypeToCoreType (type.GetElementType ());\r
4944 \r
4945                         if (arg_count == 1) {\r
4946                                 is_one_dimensional = true;\r
4947                                 eclass = ExprClass.Value;\r
4948                                 return this;\r
4949                         }\r
4950 \r
4951                         is_builtin_type = TypeManager.IsBuiltinType (type);\r
4952 \r
4953                         if (is_builtin_type) {\r
4954                                 Expression ml;\r
4955                                 \r
4956                                 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,\r
4957                                                    AllBindingFlags, loc);\r
4958                                 \r
4959                                 if (!(ml is MethodGroupExpr)) {\r
4960                                         ml.Error118 ("method group");\r
4961                                         return null;\r
4962                                 }\r
4963                                 \r
4964                                 if (ml == null) {\r
4965                                         Error (-6, "New invocation: Can not find a constructor for " +\r
4966                                                       "this argument list");\r
4967                                         return null;\r
4968                                 }\r
4969                                 \r
4970                                 new_method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, arguments, loc);\r
4971 \r
4972                                 if (new_method == null) {\r
4973                                         Error (-6, "New invocation: Can not find a constructor for " +\r
4974                                                       "this argument list");\r
4975                                         return null;\r
4976                                 }\r
4977                                 \r
4978                                 eclass = ExprClass.Value;\r
4979                                 return this;\r
4980                         } else {\r
4981                                 ModuleBuilder mb = CodeGen.ModuleBuilder;\r
4982                                 ArrayList args = new ArrayList ();\r
4983                                 \r
4984                                 if (arguments != null) {\r
4985                                         for (int i = 0; i < arg_count; i++)\r
4986                                                 args.Add (TypeManager.int32_type);\r
4987                                 }\r
4988                                 \r
4989                                 Type [] arg_types = null;\r
4990 \r
4991                                 if (args.Count > 0)\r
4992                                         arg_types = new Type [args.Count];\r
4993                                 \r
4994                                 args.CopyTo (arg_types, 0);\r
4995                                 \r
4996                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,\r
4997                                                             arg_types);\r
4998 \r
4999                                 if (new_method == null) {\r
5000                                         Error (-6, "New invocation: Can not find a constructor for " +\r
5001                                                       "this argument list");\r
5002                                         return null;\r
5003                                 }\r
5004                                 \r
5005                                 eclass = ExprClass.Value;\r
5006                                 return this;\r
5007                         }\r
5008                 }\r
5009 \r
5010                 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)\r
5011                 {\r
5012                         int factor;\r
5013                         byte [] data;\r
5014                         byte [] element;\r
5015                         int count = array_data.Count;\r
5016 \r
5017                         if (underlying_type.IsEnum)\r
5018                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);\r
5019                         \r
5020                         factor = GetTypeSize (underlying_type);\r
5021                         if (factor == 0)\r
5022                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);\r
5023 \r
5024                         data = new byte [(count * factor + 4) & ~3];\r
5025                         int idx = 0;\r
5026                         \r
5027                         for (int i = 0; i < count; ++i) {\r
5028                                 object v = array_data [i];\r
5029 \r
5030                                 if (v is EnumConstant)\r
5031                                         v = ((EnumConstant) v).Child;\r
5032                                 \r
5033                                 if (v is Constant && !(v is StringConstant))\r
5034                                         v = ((Constant) v).GetValue ();\r
5035                                 else {\r
5036                                         idx += factor;\r
5037                                         continue;\r
5038                                 }\r
5039                                 \r
5040                                 if (underlying_type == TypeManager.int64_type){\r
5041                                         if (!(v is Expression)){\r
5042                                                 long val = (long) v;\r
5043                                                 \r
5044                                                 for (int j = 0; j < factor; ++j) {\r
5045                                                         data [idx + j] = (byte) (val & 0xFF);\r
5046                                                         val = (val >> 8);\r
5047                                                 }\r
5048                                         }\r
5049                                 } else if (underlying_type == TypeManager.uint64_type){\r
5050                                         if (!(v is Expression)){\r
5051                                                 ulong val = (ulong) v;\r
5052 \r
5053                                                 for (int j = 0; j < factor; ++j) {\r
5054                                                         data [idx + j] = (byte) (val & 0xFF);\r
5055                                                         val = (val >> 8);\r
5056                                                 }\r
5057                                         }\r
5058                                 } else if (underlying_type == TypeManager.float_type) {\r
5059                                         if (!(v is Expression)){\r
5060                                                 element = BitConverter.GetBytes ((float) v);\r
5061                                                         \r
5062                                                 for (int j = 0; j < factor; ++j)\r
5063                                                         data [idx + j] = element [j];\r
5064                                         }\r
5065                                 } else if (underlying_type == TypeManager.double_type) {\r
5066                                         if (!(v is Expression)){\r
5067                                                 element = BitConverter.GetBytes ((double) v);\r
5068 \r
5069                                                 for (int j = 0; j < factor; ++j)\r
5070                                                         data [idx + j] = element [j];\r
5071                                         }\r
5072                                 } else if (underlying_type == TypeManager.char_type){\r
5073                                         if (!(v is Expression)){\r
5074                                                 int val = (int) ((char) v);\r
5075                                                 \r
5076                                                 data [idx] = (byte) (val & 0xff);\r
5077                                                 data [idx+1] = (byte) (val >> 8);\r
5078                                         }\r
5079                                 } else if (underlying_type == TypeManager.short_type){\r
5080                                         if (!(v is Expression)){\r
5081                                                 int val = (int) ((short) v);\r
5082                                         \r
5083                                                 data [idx] = (byte) (val & 0xff);\r
5084                                                 data [idx+1] = (byte) (val >> 8);\r
5085                                         }\r
5086                                 } else if (underlying_type == TypeManager.ushort_type){\r
5087                                         if (!(v is Expression)){\r
5088                                                 int val = (int) ((ushort) v);\r
5089                                         \r
5090                                                 data [idx] = (byte) (val & 0xff);\r
5091                                                 data [idx+1] = (byte) (val >> 8);\r
5092                                         }\r
5093                                 } else if (underlying_type == TypeManager.int32_type) {\r
5094                                         if (!(v is Expression)){\r
5095                                                 int val = (int) v;\r
5096                                         \r
5097                                                 data [idx]   = (byte) (val & 0xff);\r
5098                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);\r
5099                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);\r
5100                                                 data [idx+3] = (byte) (val >> 24);\r
5101                                         }\r
5102                                 } else if (underlying_type == TypeManager.uint32_type) {\r
5103                                         if (!(v is Expression)){\r
5104                                                 uint val = (uint) v;\r
5105                                         \r
5106                                                 data [idx]   = (byte) (val & 0xff);\r
5107                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);\r
5108                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);\r
5109                                                 data [idx+3] = (byte) (val >> 24);\r
5110                                         }\r
5111                                 } else if (underlying_type == TypeManager.sbyte_type) {\r
5112                                         if (!(v is Expression)){\r
5113                                                 sbyte val = (sbyte) v;\r
5114                                                 data [idx] = (byte) val;\r
5115                                         }\r
5116                                 } else if (underlying_type == TypeManager.byte_type) {\r
5117                                         if (!(v is Expression)){\r
5118                                                 byte val = (byte) v;\r
5119                                                 data [idx] = (byte) val;\r
5120                                         }\r
5121                                 } else if (underlying_type == TypeManager.bool_type) {\r
5122                                         if (!(v is Expression)){\r
5123                                                 bool val = (bool) v;\r
5124                                                 data [idx] = (byte) (val ? 1 : 0);\r
5125                                         }\r
5126                                 } else if (underlying_type == TypeManager.decimal_type){\r
5127                                         if (!(v is Expression)){\r
5128                                                 int [] bits = Decimal.GetBits ((decimal) v);\r
5129                                                 int p = idx;\r
5130                                                 \r
5131                                                 for (int j = 0; j < 4; j++){\r
5132                                                         data [p++] = (byte) (bits [j] & 0xff);\r
5133                                                         data [p++] = (byte) ((bits [j] >> 8) & 0xff);\r
5134                                                         data [p++] = (byte) ((bits [j] >> 16) & 0xff);\r
5135                                                         data [p++] = (byte) (bits [j] >> 24);\r
5136                                                 }\r
5137                                         }\r
5138                                 } else\r
5139                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);\r
5140 \r
5141                                 idx += factor;\r
5142                         }\r
5143 \r
5144                         return data;\r
5145                 }\r
5146 \r
5147                 //\r
5148                 // Emits the initializers for the array\r
5149                 //\r
5150                 void EmitStaticInitializers (EmitContext ec, bool is_expression)\r
5151                 {\r
5152                         //\r
5153                         // First, the static data\r
5154                         //\r
5155                         FieldBuilder fb;\r
5156                         ILGenerator ig = ec.ig;\r
5157                         \r
5158                         byte [] data = MakeByteBlob (array_data, underlying_type, loc);\r
5159 \r
5160                         fb = RootContext.MakeStaticData (data);\r
5161 \r
5162                         if (is_expression)\r
5163                                 ig.Emit (OpCodes.Dup);\r
5164                         ig.Emit (OpCodes.Ldtoken, fb);\r
5165                         ig.Emit (OpCodes.Call,\r
5166                                  TypeManager.void_initializearray_array_fieldhandle);\r
5167                 }\r
5168                 \r
5169                 //\r
5170                 // Emits pieces of the array that can not be computed at compile\r
5171                 // time (variables and string locations).\r
5172                 //\r
5173                 // This always expect the top value on the stack to be the array\r
5174                 //\r
5175                 void EmitDynamicInitializers (EmitContext ec, bool is_expression)\r
5176                 {\r
5177                         ILGenerator ig = ec.ig;\r
5178                         int dims = bounds.Count;\r
5179                         int [] current_pos = new int [dims];\r
5180                         int top = array_data.Count;\r
5181                         LocalBuilder temp = ig.DeclareLocal (type);\r
5182 \r
5183                         ig.Emit (OpCodes.Stloc, temp);\r
5184 \r
5185                         MethodInfo set = null;\r
5186 \r
5187                         if (dims != 1){\r
5188                                 Type [] args;\r
5189                                 ModuleBuilder mb = null;\r
5190                                 mb = CodeGen.ModuleBuilder;\r
5191                                 args = new Type [dims + 1];\r
5192 \r
5193                                 int j;\r
5194                                 for (j = 0; j < dims; j++)\r
5195                                         args [j] = TypeManager.int32_type;\r
5196 \r
5197                                 args [j] = array_element_type;\r
5198                                 \r
5199                                 set = mb.GetArrayMethod (\r
5200                                         type, "Set",\r
5201                                         CallingConventions.HasThis | CallingConventions.Standard,\r
5202                                         TypeManager.void_type, args);\r
5203                         }\r
5204                         \r
5205                         for (int i = 0; i < top; i++){\r
5206 \r
5207                                 Expression e = null;\r
5208 \r
5209                                 if (array_data [i] is Expression)\r
5210                                         e = (Expression) array_data [i];\r
5211 \r
5212                                 if (e != null) {\r
5213                                         //\r
5214                                         // Basically we do this for string literals and\r
5215                                         // other non-literal expressions\r
5216                                         //\r
5217                                         if (e is StringConstant || !(e is Constant) ||\r
5218                                             num_automatic_initializers <= 2) {\r
5219                                                 Type etype = e.Type;\r
5220                                                 \r
5221                                                 ig.Emit (OpCodes.Ldloc, temp);\r
5222 \r
5223                                                 for (int idx = 0; idx < dims; idx++) \r
5224                                                         IntConstant.EmitInt (ig, current_pos [idx]);\r
5225 \r
5226                                                 //\r
5227                                                 // If we are dealing with a struct, get the\r
5228                                                 // address of it, so we can store it.\r
5229                                                 //\r
5230                                                 if ((dims == 1) &&\r
5231                                                     etype.IsSubclassOf (TypeManager.value_type) &&\r
5232                                                     (!TypeManager.IsBuiltinType (etype) ||\r
5233                                                      etype == TypeManager.decimal_type)) {\r
5234                                                         if (e is New){\r
5235                                                                 New n = (New) e;\r
5236 \r
5237                                                                 //\r
5238                                                                 // Let new know that we are providing\r
5239                                                                 // the address where to store the results\r
5240                                                                 //\r
5241                                                                 n.DisableTemporaryValueType ();\r
5242                                                         }\r
5243                                                                              \r
5244                                                         ig.Emit (OpCodes.Ldelema, etype);\r
5245                                                 }\r
5246 \r
5247                                                 e.Emit (ec);\r
5248                                                 \r
5249                                                 if (dims == 1)\r
5250                                                         ArrayAccess.EmitStoreOpcode (ig, array_element_type);\r
5251                                                 else \r
5252                                                         ig.Emit (OpCodes.Call, set);\r
5253                                         }\r
5254                                 }\r
5255                                 \r
5256                                 //\r
5257                                 // Advance counter\r
5258                                 //\r
5259                                 for (int j = dims - 1; j >= 0; j--){\r
5260                                         current_pos [j]++;\r
5261                                         if (current_pos [j] < (int) bounds [j])\r
5262                                                 break;\r
5263                                         current_pos [j] = 0;\r
5264                                 }\r
5265                         }\r
5266 \r
5267                         if (is_expression)\r
5268                                 ig.Emit (OpCodes.Ldloc, temp);\r
5269                 }\r
5270 \r
5271                 void EmitArrayArguments (EmitContext ec)\r
5272                 {\r
5273                         ILGenerator ig = ec.ig;\r
5274                         \r
5275                         foreach (Argument a in arguments) {\r
5276                                 Type atype = a.Type;\r
5277                                 a.Emit (ec);\r
5278 \r
5279                                 if (atype == TypeManager.uint64_type)\r
5280                                         ig.Emit (OpCodes.Conv_Ovf_U4);\r
5281                                 else if (atype == TypeManager.int64_type)\r
5282                                         ig.Emit (OpCodes.Conv_Ovf_I4);\r
5283                         }\r
5284                 }\r
5285                 \r
5286                 void DoEmit (EmitContext ec, bool is_statement)\r
5287                 {\r
5288                         ILGenerator ig = ec.ig;\r
5289                         \r
5290                         EmitArrayArguments (ec);\r
5291                         if (is_one_dimensional)\r
5292                                 ig.Emit (OpCodes.Newarr, array_element_type);\r
5293                         else {\r
5294                                 if (is_builtin_type) \r
5295                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);\r
5296                                 else \r
5297                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);\r
5298                         }\r
5299                         \r
5300                         if (initializers != null){\r
5301                                 //\r
5302                                 // FIXME: Set this variable correctly.\r
5303                                 // \r
5304                                 bool dynamic_initializers = true;\r
5305 \r
5306                                 if (underlying_type != TypeManager.string_type &&\r
5307                                     underlying_type != TypeManager.object_type) {\r
5308                                         if (num_automatic_initializers > 2)\r
5309                                                 EmitStaticInitializers (ec, dynamic_initializers || !is_statement);\r
5310                                 }\r
5311                                 \r
5312                                 if (dynamic_initializers)\r
5313                                         EmitDynamicInitializers (ec, !is_statement);\r
5314                         }\r
5315                 }\r
5316                 \r
5317                 public override void Emit (EmitContext ec)\r
5318                 {\r
5319                         DoEmit (ec, false);\r
5320                 }\r
5321 \r
5322                 public override void EmitStatement (EmitContext ec)\r
5323                 {\r
5324                         DoEmit (ec, true);\r
5325                 }\r
5326                 \r
5327         }\r
5328         \r
5329         /// <summary>\r
5330         ///   Represents the 'this' construct\r
5331         /// </summary>\r
5332         public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {\r
5333 \r
5334                 Block block;\r
5335                 VariableInfo vi;\r
5336                 \r
5337                 public This (Block block, Location loc)\r
5338                 {\r
5339                         this.loc = loc;\r
5340                         this.block = block;\r
5341                 }\r
5342 \r
5343                 public This (Location loc)\r
5344                 {\r
5345                         this.loc = loc;\r
5346                 }\r
5347 \r
5348                 public bool IsAssigned (EmitContext ec, Location loc)\r
5349                 {\r
5350                         if (vi == null)\r
5351                                 return true;\r
5352 \r
5353                         return vi.IsAssigned (ec, loc);\r
5354                 }\r
5355 \r
5356                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)\r
5357                 {\r
5358                         if (vi == null)\r
5359                                 return true;\r
5360 \r
5361                         return vi.IsFieldAssigned (ec, field_name, loc);\r
5362                 }\r
5363 \r
5364                 public void SetAssigned (EmitContext ec)\r
5365                 {\r
5366                         if (vi != null)\r
5367                                 vi.SetAssigned (ec);\r
5368                 }\r
5369 \r
5370                 public void SetFieldAssigned (EmitContext ec, string field_name)\r
5371                 {       \r
5372                         if (vi != null)\r
5373                                 vi.SetFieldAssigned (ec, field_name);\r
5374                 }\r
5375 \r
5376                 public override Expression DoResolve (EmitContext ec)\r
5377                 {\r
5378                         eclass = ExprClass.Variable;\r
5379                         type = ec.ContainerType;\r
5380 \r
5381                         if (ec.IsStatic){\r
5382                                 Error (26, "Keyword this not valid in static code");\r
5383                                 return null;\r
5384                         }\r
5385 \r
5386                         if (block != null)\r
5387                                 vi = block.ThisVariable;\r
5388 \r
5389                         return this;\r
5390                 }\r
5391 \r
5392                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)\r
5393                 {\r
5394                         DoResolve (ec);\r
5395 \r
5396                         VariableInfo vi = ec.CurrentBlock.ThisVariable;\r
5397                         if (vi != null)\r
5398                                 vi.SetAssigned (ec);\r
5399                         \r
5400                         if (ec.TypeContainer is Class){\r
5401                                 Error (1604, "Cannot assign to 'this'");\r
5402                                 return null;\r
5403                         }\r
5404 \r
5405                         return this;\r
5406                 }\r
5407 \r
5408                 public override void Emit (EmitContext ec)\r
5409                 {\r
5410                         ILGenerator ig = ec.ig;\r
5411                         \r
5412                         ig.Emit (OpCodes.Ldarg_0);\r
5413                         if (ec.TypeContainer is Struct)\r
5414                                 ig.Emit (OpCodes.Ldobj, type);\r
5415                 }\r
5416 \r
5417                 public void EmitAssign (EmitContext ec, Expression source)\r
5418                 {\r
5419                         ILGenerator ig = ec.ig;\r
5420                         \r
5421                         if (ec.TypeContainer is Struct){\r
5422                                 ig.Emit (OpCodes.Ldarg_0);\r
5423                                 source.Emit (ec);\r
5424                                 ig.Emit (OpCodes.Stobj, type);\r
5425                         } else {\r
5426                                 source.Emit (ec);\r
5427                                 ig.Emit (OpCodes.Starg, 0);\r
5428                         }\r
5429                 }\r
5430 \r
5431                 public void AddressOf (EmitContext ec, AddressOp mode)\r
5432                 {\r
5433                         ec.ig.Emit (OpCodes.Ldarg_0);\r
5434 \r
5435                         // FIMXE\r
5436                         // FIGURE OUT WHY LDARG_S does not work\r
5437                         //\r
5438                         // consider: struct X { int val; int P { set { val = value; }}}\r
5439                         //\r
5440                         // Yes, this looks very bad. Look at 'NOTAS' for\r
5441                         // an explanation.\r
5442                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);\r
5443                 }\r
5444         }\r
5445 \r
5446         /// <summary>\r
5447         ///   Implements the typeof operator\r
5448         /// </summary>\r
5449         public class TypeOf : Expression {\r
5450                 public readonly Expression QueriedType;\r
5451                 Type typearg;\r
5452                 \r
5453                 public TypeOf (Expression queried_type, Location l)\r
5454                 {\r
5455                         QueriedType = queried_type;\r
5456                         loc = l;\r
5457                 }\r
5458 \r
5459                 public override Expression DoResolve (EmitContext ec)\r
5460                 {\r
5461                         typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);\r
5462 \r
5463                         if (typearg == null)\r
5464                                 return null;\r
5465 \r
5466                         type = TypeManager.type_type;\r
5467                         eclass = ExprClass.Type;\r
5468                         return this;\r
5469                 }\r
5470 \r
5471                 public override void Emit (EmitContext ec)\r
5472                 {\r
5473                         ec.ig.Emit (OpCodes.Ldtoken, typearg);\r
5474                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);\r
5475                 }\r
5476 \r
5477                 public Type TypeArg { \r
5478                         get { return typearg; }\r
5479                 }\r
5480         }\r
5481 \r
5482         /// <summary>\r
5483         ///   Implements the sizeof expression\r
5484         /// </summary>\r
5485         public class SizeOf : Expression {\r
5486                 public readonly Expression QueriedType;\r
5487                 Type type_queried;\r
5488                 \r
5489                 public SizeOf (Expression queried_type, Location l)\r
5490                 {\r
5491                         this.QueriedType = queried_type;\r
5492                         loc = l;\r
5493                 }\r
5494 \r
5495                 public override Expression DoResolve (EmitContext ec)\r
5496                 {\r
5497                         if (!ec.InUnsafe) {\r
5498                                 Error (233, "Sizeof may only be used in an unsafe context " +\r
5499                                        "(consider using System.Runtime.InteropServices.Marshal.Sizeof");\r
5500                                 return null;\r
5501                         }\r
5502                                 \r
5503                         type_queried = ec.DeclSpace.ResolveType (QueriedType, false, loc);\r
5504                         if (type_queried == null)\r
5505                                 return null;\r
5506 \r
5507                         if (!TypeManager.IsUnmanagedType (type_queried)){\r
5508                                 Report.Error (208, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");\r
5509                                 return null;\r
5510                         }\r
5511                         \r
5512                         type = TypeManager.int32_type;\r
5513                         eclass = ExprClass.Value;\r
5514                         return this;\r
5515                 }\r
5516 \r
5517                 public override void Emit (EmitContext ec)\r
5518                 {\r
5519                         int size = GetTypeSize (type_queried);\r
5520 \r
5521                         if (size == 0)\r
5522                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);\r
5523                         else\r
5524                                 IntConstant.EmitInt (ec.ig, size);\r
5525                 }\r
5526         }\r
5527 \r
5528         /// <summary>\r
5529         ///   Implements the member access expression\r
5530         /// </summary>\r
5531         public class MemberAccess : Expression, ITypeExpression {\r
5532                 public readonly string Identifier;\r
5533                 Expression expr;\r
5534                 Expression member_lookup;\r
5535                 \r
5536                 public MemberAccess (Expression expr, string id, Location l)\r
5537                 {\r
5538                         this.expr = expr;\r
5539                         Identifier = id;\r
5540                         loc = l;\r
5541                 }\r
5542 \r
5543                 public Expression Expr {\r
5544                         get {\r
5545                                 return expr;\r
5546                         }\r
5547                 }\r
5548 \r
5549                 static void error176 (Location loc, string name)\r
5550                 {\r
5551                         Report.Error (176, loc, "Static member '" +\r
5552                                       name + "' cannot be accessed " +\r
5553                                       "with an instance reference, qualify with a " +\r
5554                                       "type name instead");\r
5555                 }\r
5556 \r
5557                 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)\r
5558                 {\r
5559                         if (left_original == null)\r
5560                                 return false;\r
5561 \r
5562                         if (!(left_original is SimpleName))\r
5563                                 return false;\r
5564 \r
5565                         SimpleName sn = (SimpleName) left_original;\r
5566 \r
5567                         Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);\r
5568                         if (t != null)\r
5569                                 return true;\r
5570 \r
5571                         return false;\r
5572                 }\r
5573                 \r
5574                 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,\r
5575                                                               Expression left, Location loc,\r
5576                                                               Expression left_original)\r
5577                 {\r
5578                         bool left_is_type, left_is_explicit;\r
5579 \r
5580                         // If 'left' is null, then we're called from SimpleNameResolve and this is\r
5581                         // a member in the currently defining class.\r
5582                         if (left == null) {\r
5583                                 left_is_type = ec.IsStatic || ec.IsFieldInitializer;\r
5584                                 left_is_explicit = false;\r
5585 \r
5586                                 // Implicitly default to 'this' unless we're static.\r
5587                                 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)\r
5588                                         left = ec.This;\r
5589                         } else {\r
5590                                 left_is_type = left is TypeExpr;\r
5591                                 left_is_explicit = true;\r
5592                         }\r
5593 \r
5594                         if (member_lookup is FieldExpr){\r
5595                                 FieldExpr fe = (FieldExpr) member_lookup;\r
5596                                 FieldInfo fi = fe.FieldInfo;\r
5597                                 Type decl_type = fi.DeclaringType;\r
5598                                 \r
5599                                 if (fi is FieldBuilder) {\r
5600                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);\r
5601                                         \r
5602                                         if (c != null) {\r
5603                                                 object o = c.LookupConstantValue (ec);\r
5604                                                 object real_value = ((Constant) c.Expr).GetValue ();\r
5605 \r
5606                                                 return Constantify (real_value, fi.FieldType);\r
5607                                         }\r
5608                                 }\r
5609 \r
5610                                 if (fi.IsLiteral) {\r
5611                                         Type t = fi.FieldType;\r
5612                                         \r
5613                                         object o;\r
5614 \r
5615                                         if (fi is FieldBuilder)\r
5616                                                 o = TypeManager.GetValue ((FieldBuilder) fi);\r
5617                                         else\r
5618                                                 o = fi.GetValue (fi);\r
5619                                         \r
5620                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {\r
5621                                                 if (left_is_explicit && !left_is_type &&\r
5622                                                     !IdenticalNameAndTypeName (ec, left_original, loc)) {\r
5623                                                         error176 (loc, fe.FieldInfo.Name);\r
5624                                                         return null;\r
5625                                                 }                                       \r
5626                                                 \r
5627                                                 Expression enum_member = MemberLookup (\r
5628                                                         ec, decl_type, "value__", MemberTypes.Field,\r
5629                                                         AllBindingFlags, loc); \r
5630 \r
5631                                                 Enum en = TypeManager.LookupEnum (decl_type);\r
5632 \r
5633                                                 Constant c;\r
5634                                                 if (en != null)\r
5635                                                         c = Constantify (o, en.UnderlyingType);\r
5636                                                 else \r
5637                                                         c = Constantify (o, enum_member.Type);\r
5638                                                 \r
5639                                                 return new EnumConstant (c, decl_type);\r
5640                                         }\r
5641                                         \r
5642                                         Expression exp = Constantify (o, t);\r
5643 \r
5644                                         if (left_is_explicit && !left_is_type) {\r
5645                                                 error176 (loc, fe.FieldInfo.Name);\r
5646                                                 return null;\r
5647                                         }\r
5648                                         \r
5649                                         return exp;\r
5650                                 }\r
5651 \r
5652                                 if (fi.FieldType.IsPointer && !ec.InUnsafe){\r
5653                                         UnsafeError (loc);\r
5654                                         return null;\r
5655                                 }\r
5656                         }\r
5657 \r
5658                         if (member_lookup is EventExpr) {\r
5659 \r
5660                                 EventExpr ee = (EventExpr) member_lookup;\r
5661                                 \r
5662                                 //\r
5663                                 // If the event is local to this class, we transform ourselves into\r
5664                                 // a FieldExpr\r
5665                                 //\r
5666 \r
5667                                 if (ee.EventInfo.DeclaringType == ec.ContainerType) {\r
5668                                         MemberInfo mi = GetFieldFromEvent (ee);\r
5669 \r
5670                                         if (mi == null) {\r
5671                                                 //\r
5672                                                 // If this happens, then we have an event with its own\r
5673                                                 // accessors and private field etc so there's no need\r
5674                                                 // to transform ourselves : we should instead flag an error\r
5675                                                 //\r
5676                                                 Assign.error70 (ee.EventInfo, loc);\r
5677                                                 return null;\r
5678                                         }\r
5679 \r
5680                                         Expression ml = ExprClassFromMemberInfo (ec, mi, loc);\r
5681                                         \r
5682                                         if (ml == null) {\r
5683                                                 Report.Error (-200, loc, "Internal error!!");\r
5684                                                 return null;\r
5685                                         }\r
5686                                         \r
5687                                         return ResolveMemberAccess (ec, ml, left, loc, left_original);\r
5688                                 }\r
5689                         }\r
5690                         \r
5691                         if (member_lookup is IMemberExpr) {\r
5692                                 IMemberExpr me = (IMemberExpr) member_lookup;\r
5693 \r
5694                                 if (left_is_type){\r
5695                                         MethodGroupExpr mg = me as MethodGroupExpr;\r
5696                                         if ((mg != null) && left_is_explicit && left.Type.IsInterface)\r
5697                                                 mg.IsExplicitImpl = left_is_explicit;\r
5698 \r
5699                                         if (!me.IsStatic){\r
5700                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))\r
5701                                                         return member_lookup;\r
5702 \r
5703                                                 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);\r
5704                                                 return null;\r
5705                                         }\r
5706 \r
5707                                 } else {\r
5708                                         if (!me.IsInstance){\r
5709                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))\r
5710                                                         return member_lookup;\r
5711 \r
5712                                                 if (left_is_explicit) {\r
5713                                                         error176 (loc, me.Name);\r
5714                                                         return null;\r
5715                                                 }\r
5716                                         }\r
5717 \r
5718                                         //\r
5719                                         // Since we can not check for instance objects in SimpleName,\r
5720                                         // becaue of the rule that allows types and variables to share\r
5721                                         // the name (as long as they can be de-ambiguated later, see \r
5722                                         // IdenticalNameAndTypeName), we have to check whether left \r
5723                                         // is an instance variable in a static context\r
5724                                         //\r
5725                                         // However, if the left-hand value is explicitly given, then\r
5726                                         // it is already our instance expression, so we aren't in\r
5727                                         // static context.\r
5728                                         //\r
5729 \r
5730                                         if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){\r
5731                                                 IMemberExpr mexp = (IMemberExpr) left;\r
5732 \r
5733                                                 if (!mexp.IsStatic){\r
5734                                                         SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);\r
5735                                                         return null;\r
5736                                                 }\r
5737                                         }\r
5738 \r
5739                                         me.InstanceExpression = left;\r
5740                                 }\r
5741 \r
5742                                 return member_lookup;\r
5743                         }\r
5744 \r
5745                         if (member_lookup is TypeExpr){\r
5746                                 member_lookup.Resolve (ec, ResolveFlags.Type);\r
5747                                 return member_lookup;\r
5748                         }\r
5749                         \r
5750                         Console.WriteLine ("Left is: " + left);\r
5751                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");\r
5752                         Environment.Exit (0);\r
5753                         return null;\r
5754                 }\r
5755                 \r
5756                 public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)\r
5757                 {\r
5758                         if (type != null)\r
5759                                 throw new Exception ();\r
5760                         //\r
5761                         // Resolve the expression with flow analysis turned off, we'll do the definite\r
5762                         // assignment checks later.  This is because we don't know yet what the expression\r
5763                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the\r
5764                         // definite assignment check on the actual field and not on the whole struct.\r
5765                         //\r
5766 \r
5767                         Expression original = expr;\r
5768                         expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);\r
5769 \r
5770                         if (expr == null)\r
5771                                 return null;\r
5772 \r
5773                         if (expr is SimpleName){\r
5774                                 SimpleName child_expr = (SimpleName) expr;\r
5775                                 \r
5776                                 Expression new_expr = new SimpleName (child_expr.Name + "." + Identifier, loc);\r
5777 \r
5778                                 return new_expr.Resolve (ec, flags);\r
5779                         }\r
5780                                         \r
5781                         //\r
5782                         // TODO: I mailed Ravi about this, and apparently we can get rid\r
5783                         // of this and put it in the right place.\r
5784                         // \r
5785                         // Handle enums here when they are in transit.\r
5786                         // Note that we cannot afford to hit MemberLookup in this case because\r
5787                         // it will fail to find any members at all\r
5788                         //\r
5789 \r
5790                         int errors = Report.Errors;\r
5791                         \r
5792                         Type expr_type = expr.Type;\r
5793                         if ((expr is TypeExpr) && (expr_type.IsSubclassOf (TypeManager.enum_type))){\r
5794                                 \r
5795                                 Enum en = TypeManager.LookupEnum (expr_type);\r
5796                                 \r
5797                                 if (en != null) {\r
5798                                         object value = en.LookupEnumValue (ec, Identifier, loc);\r
5799 \r
5800                                         if (value != null){\r
5801                                                 Constant c = Constantify (value, en.UnderlyingType);\r
5802                                                 return new EnumConstant (c, expr_type);\r
5803                                         }\r
5804                                 }\r
5805                         }\r
5806 \r
5807                         if (expr_type.IsPointer){\r
5808                                 Error (23, "The '.' operator can not be applied to pointer operands (" +\r
5809                                        TypeManager.CSharpName (expr_type) + ")");\r
5810                                 return null;\r
5811                         }\r
5812 \r
5813                         member_lookup = MemberLookup (ec, expr_type, Identifier, loc);\r
5814 \r
5815                         if (member_lookup == null)\r
5816                         {\r
5817                                 // Error has already been reported.\r
5818                                 if (errors < Report.Errors)\r
5819                                         return null;\r
5820                                 \r
5821                                 //\r
5822                                 // Try looking the member up from the same type, if we find\r
5823                                 // it, we know that the error was due to limited visibility\r
5824                                 //\r
5825                                 object lookup = TypeManager.MemberLookup (\r
5826                                         expr_type, expr_type, AllMemberTypes, AllBindingFlags |\r
5827                                         BindingFlags.NonPublic, Identifier);\r
5828                                         \r
5829                                 if (lookup == null)\r
5830                                         Error (117, "'" + expr_type + "' does not contain a definition for '" + Identifier + "'");\r
5831                                 else\r
5832                                 {\r
5833                                         if ((expr_type != ec.ContainerType) &&\r
5834                                                  ec.ContainerType.IsSubclassOf (expr_type))\r
5835                                         {\r
5836 \r
5837                                                 // Although a derived class can access protected members of\r
5838                                                 // its base class it cannot do so through an instance of the\r
5839                                                 // base class (CS1540).  If the expr_type is a parent of the\r
5840                                                 // ec.ContainerType and the lookup succeeds with the latter one,\r
5841                                                 // then we are in this situation.\r
5842 \r
5843                                                 lookup = TypeManager.MemberLookup(\r
5844                                                                         ec.ContainerType, ec.ContainerType, AllMemberTypes, \r
5845                                                                         AllBindingFlags, Identifier);\r
5846 \r
5847                                                 if (lookup != null)\r
5848                                                         Error (1540, "Cannot access protected member '" +\r
5849                                                        expr_type + "." + Identifier + "' " +\r
5850                                                        "via a qualifier of type '" + TypeManager.CSharpName (expr_type) + "'; the " +\r
5851                                                        "qualifier must be of type '" + TypeManager.CSharpName (ec.ContainerType) + "' " +\r
5852                                                        "(or derived from it)");\r
5853                                                 else\r
5854                                                         Error (122, "'" + expr_type + "." + Identifier + "' " +\r
5855                                                        "is inaccessible because of its protection level");\r
5856                                         } else\r
5857                                                 Error (122, "'" + expr_type + "." + Identifier + "' " +\r
5858                                                "is inaccessible because of its protection level");\r
5859                                 }  \r
5860                                 return null;\r
5861                         }\r
5862 \r
5863                         if (member_lookup is TypeExpr){\r
5864                                 member_lookup.Resolve (ec, ResolveFlags.Type);\r
5865                                 return member_lookup;\r
5866                         } else if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)\r
5867                                 return null;\r
5868                         \r
5869                         member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);\r
5870                         if (member_lookup == null)\r
5871                                 return null;\r
5872 \r
5873                         // The following DoResolve/DoResolveLValue will do the definite assignment\r
5874                         // check.\r
5875 \r
5876                         if (right_side != null)\r
5877                                 member_lookup = member_lookup.DoResolveLValue (ec, right_side);\r
5878                         else\r
5879                                 member_lookup = member_lookup.DoResolve (ec);\r
5880 \r
5881                         return member_lookup;\r
5882                 }\r
5883 \r
5884                 public override Expression DoResolve (EmitContext ec)\r
5885                 {\r
5886                         return DoResolve (ec, null, ResolveFlags.VariableOrValue |\r
5887                                           ResolveFlags.SimpleName | ResolveFlags.Type);\r
5888                 }\r
5889 \r
5890                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)\r
5891                 {\r
5892                         return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |\r
5893                                           ResolveFlags.SimpleName | ResolveFlags.Type);\r
5894                 }\r
5895 \r
5896                 public Expression DoResolveType (EmitContext ec)\r
5897                 {\r
5898                         return DoResolve (ec, null, ResolveFlags.Type);\r
5899                 }\r
5900 \r
5901                 public override void Emit (EmitContext ec)\r
5902                 {\r
5903                         throw new Exception ("Should not happen");\r
5904                 }\r
5905 \r
5906                 public override string ToString ()\r
5907                 {\r
5908                         return expr + "." + Identifier;\r
5909                 }\r
5910         }\r
5911 \r
5912         \r
5913         \r
5914         /// <summary>\r
5915         ///   Implements checked expressions\r
5916         /// </summary>\r
5917         public class CheckedExpr : Expression {\r
5918 \r
5919                 public Expression Expr;\r
5920 \r
5921                 public CheckedExpr (Expression e, Location l)\r
5922                 {\r
5923                         Expr = e;\r
5924                         loc = l;\r
5925                 }\r
5926 \r
5927                 public override Expression DoResolve (EmitContext ec)\r
5928                 {\r
5929                         bool last_const_check = ec.ConstantCheckState;\r
5930 \r
5931                         ec.ConstantCheckState = true;\r
5932                         Expr = Expr.Resolve (ec);\r
5933                         ec.ConstantCheckState = last_const_check;\r
5934                         \r
5935                         if (Expr == null)\r
5936                                 return null;\r
5937 \r
5938                         if (Expr is Constant)\r
5939                                 return Expr;\r
5940                         \r
5941                         eclass = Expr.eclass;\r
5942                         type = Expr.Type;\r
5943                         return this;\r
5944                 }\r
5945 \r
5946                 public override void Emit (EmitContext ec)\r
5947                 {\r
5948                         bool last_check = ec.CheckState;\r
5949                         bool last_const_check = ec.ConstantCheckState;\r
5950                         \r
5951                         ec.CheckState = true;\r
5952                         ec.ConstantCheckState = true;\r
5953                         Expr.Emit (ec);\r
5954                         ec.CheckState = last_check;\r
5955                         ec.ConstantCheckState = last_const_check;\r
5956                 }\r
5957                 \r
5958         }\r
5959 \r
5960         /// <summary>\r
5961         ///   Implements the unchecked expression\r
5962         /// </summary>\r
5963         public class UnCheckedExpr : Expression {\r
5964 \r
5965                 public Expression Expr;\r
5966 \r
5967                 public UnCheckedExpr (Expression e, Location l)\r
5968                 {\r
5969                         Expr = e;\r
5970                         loc = l;\r
5971                 }\r
5972 \r
5973                 public override Expression DoResolve (EmitContext ec)\r
5974                 {\r
5975                         bool last_const_check = ec.ConstantCheckState;\r
5976 \r
5977                         ec.ConstantCheckState = false;\r
5978                         Expr = Expr.Resolve (ec);\r
5979                         ec.ConstantCheckState = last_const_check;\r
5980 \r
5981                         if (Expr == null)\r
5982                                 return null;\r
5983 \r
5984                         if (Expr is Constant)\r
5985                                 return Expr;\r
5986                         \r
5987                         eclass = Expr.eclass;\r
5988                         type = Expr.Type;\r
5989                         return this;\r
5990                 }\r
5991 \r
5992                 public override void Emit (EmitContext ec)\r
5993                 {\r
5994                         bool last_check = ec.CheckState;\r
5995                         bool last_const_check = ec.ConstantCheckState;\r
5996                         \r
5997                         ec.CheckState = false;\r
5998                         ec.ConstantCheckState = false;\r
5999                         Expr.Emit (ec);\r
6000                         ec.CheckState = last_check;\r
6001                         ec.ConstantCheckState = last_const_check;\r
6002                 }\r
6003                 \r
6004         }\r
6005 \r
6006         /// <summary>\r
6007         ///   An Element Access expression.\r
6008         ///\r
6009         ///   During semantic analysis these are transformed into \r
6010         ///   IndexerAccess or ArrayAccess \r
6011         /// </summary>\r
6012         public class ElementAccess : Expression {\r
6013                 public ArrayList  Arguments;\r
6014                 public Expression Expr;\r
6015                 \r
6016                 public ElementAccess (Expression e, ArrayList e_list, Location l)\r
6017                 {\r
6018                         Expr = e;\r
6019 \r
6020                         loc  = l;\r
6021                         \r
6022                         if (e_list == null)\r
6023                                 return;\r
6024                         \r
6025                         Arguments = new ArrayList ();\r
6026                         foreach (Expression tmp in e_list)\r
6027                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));\r
6028                         \r
6029                 }\r
6030 \r
6031                 bool CommonResolve (EmitContext ec)\r
6032                 {\r
6033                         Expr = Expr.Resolve (ec);\r
6034 \r
6035                         if (Expr == null) \r
6036                                 return false;\r
6037 \r
6038                         if (Arguments == null)\r
6039                                 return false;\r
6040 \r
6041                         foreach (Argument a in Arguments){\r
6042                                 if (!a.Resolve (ec, loc))\r
6043                                         return false;\r
6044                         }\r
6045 \r
6046                         return true;\r
6047                 }\r
6048 \r
6049                 Expression MakePointerAccess ()\r
6050                 {\r
6051                         Type t = Expr.Type;\r
6052 \r
6053                         if (t == TypeManager.void_ptr_type){\r
6054                                 Error (\r
6055                                         242,\r
6056                                         "The array index operation is not valid for void pointers");\r
6057                                 return null;\r
6058                         }\r
6059                         if (Arguments.Count != 1){\r
6060                                 Error (\r
6061                                         196,\r
6062                                         "A pointer must be indexed by a single value");\r
6063                                 return null;\r
6064                         }\r
6065                         Expression p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr,\r
6066                                                               t, loc);\r
6067                         return new Indirection (p, loc);\r
6068                 }\r
6069                 \r
6070                 public override Expression DoResolve (EmitContext ec)\r
6071                 {\r
6072                         if (!CommonResolve (ec))\r
6073                                 return null;\r
6074 \r
6075                         //\r
6076                         // We perform some simple tests, and then to "split" the emit and store\r
6077                         // code we create an instance of a different class, and return that.\r
6078                         //\r
6079                         // I am experimenting with this pattern.\r
6080                         //\r
6081                         Type t = Expr.Type;\r
6082 \r
6083                         if (t.IsArray)\r
6084                                 return (new ArrayAccess (this, loc)).Resolve (ec);\r
6085                         else if (t.IsPointer)\r
6086                                 return MakePointerAccess ();\r
6087                         else\r
6088                                 return (new IndexerAccess (this, loc)).Resolve (ec);\r
6089                 }\r
6090 \r
6091                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)\r
6092                 {\r
6093                         if (!CommonResolve (ec))\r
6094                                 return null;\r
6095 \r
6096                         Type t = Expr.Type;\r
6097                         if (t.IsArray)\r
6098                                 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);\r
6099                         else if (t.IsPointer)\r
6100                                 return MakePointerAccess ();\r
6101                         else\r
6102                                 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);\r
6103                 }\r
6104                 \r
6105                 public override void Emit (EmitContext ec)\r
6106                 {\r
6107                         throw new Exception ("Should never be reached");\r
6108                 }\r
6109         }\r
6110 \r
6111         /// <summary>\r
6112         ///   Implements array access \r
6113         /// </summary>\r
6114         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {\r
6115                 //\r
6116                 // Points to our "data" repository\r
6117                 //\r
6118                 ElementAccess ea;\r
6119 \r
6120                 LocalTemporary [] cached_locations;\r
6121                 \r
6122                 public ArrayAccess (ElementAccess ea_data, Location l)\r
6123                 {\r
6124                         ea = ea_data;\r
6125                         eclass = ExprClass.Variable;\r
6126                         loc = l;\r
6127                 }\r
6128 \r
6129                 public override Expression DoResolve (EmitContext ec)\r
6130                 {\r
6131                         ExprClass eclass = ea.Expr.eclass;\r
6132 \r
6133 #if false\r
6134                         // As long as the type is valid\r
6135                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||\r
6136                               eclass == ExprClass.Value)) {\r
6137                                 ea.Expr.Error118 ("variable or value");\r
6138                                 return null;\r
6139                         }\r
6140 #endif\r
6141 \r
6142                         Type t = ea.Expr.Type;\r
6143                         \r
6144                         if (t == typeof (System.Object))\r
6145                         {\r
6146                                 // We can't resolve now, but we\r
6147                                 // have to try to access the array with a call\r
6148                                 // to LateIndexGet in the runtime\r
6149                                 \r
6150                                 Expression lig_call_expr = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices.LateBinding.LateIndexGet", Location.Null);\r
6151                                 Expression obj_type = Mono.MonoBASIC.Parser.DecomposeQI("System.Object", Location.Null);\r
6152                                 ArrayList adims = new ArrayList();\r
6153                                 \r
6154                                 ArrayList ainit = new ArrayList(); \r
6155                                 foreach (Argument a in ea.Arguments)\r
6156                                         ainit.Add ((Expression) a.Expr);                \r
6157                                                 \r
6158                                 adims.Add ((Expression) new IntLiteral (ea.Arguments.Count));\r
6159                                 \r
6160                                 Expression oace = new ArrayCreation (obj_type, adims, "", ainit, Location.Null);\r
6161                                 \r
6162                                 ArrayList args = new ArrayList();\r
6163                                 args.Add (new Argument(ea.Expr, Argument.AType.Expression));\r
6164                                 args.Add (new Argument(oace, Argument.AType.Expression));\r
6165                                 args.Add (new Argument(NullLiteral.Null, Argument.AType.Expression));\r
6166                                 \r
6167                                 Expression lig_call = new Invocation (lig_call_expr, args, Location.Null);\r
6168                                 lig_call = lig_call.Resolve(ec);\r
6169                                 return lig_call;\r
6170                         }\r
6171                                                 \r
6172                         if (t.GetArrayRank () != ea.Arguments.Count){\r
6173                                 ea.Error (22,\r
6174                                           "Incorrect number of indexes for array " +\r
6175                                           " expected: " + t.GetArrayRank () + " got: " +\r
6176                                           ea.Arguments.Count);\r
6177                                 return null;\r
6178                         }\r
6179                         type = TypeManager.TypeToCoreType (t.GetElementType ());\r
6180                         if (type.IsPointer && !ec.InUnsafe){\r
6181                                 UnsafeError (ea.Location);\r
6182                                 return null;\r
6183                         }\r
6184 \r
6185                         foreach (Argument a in ea.Arguments){\r
6186                                 Type argtype = a.Type;\r
6187 \r
6188                                 if (argtype == TypeManager.int32_type ||\r
6189                                     argtype == TypeManager.uint32_type ||\r
6190                                     argtype == TypeManager.int64_type ||\r
6191                                     argtype == TypeManager.uint64_type)\r
6192                                         continue;\r
6193 \r
6194                                 //\r
6195                                 // Mhm.  This is strage, because the Argument.Type is not the same as\r
6196                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.\r
6197                                 //\r
6198                                 // Wonder if I will run into trouble for this.\r
6199                                 //\r
6200                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);\r
6201                                 if (a.Expr == null)\r
6202                                         return null;\r
6203                         }\r
6204                         \r
6205                         eclass = ExprClass.Variable;\r
6206 \r
6207                         return this;\r
6208                 }\r
6209 \r
6210                 /// <summary>\r
6211                 ///    Emits the right opcode to load an object of Type 't'\r
6212                 ///    from an array of T\r
6213                 /// </summary>\r
6214                 static public void EmitLoadOpcode (ILGenerator ig, Type type)\r
6215                 {\r
6216                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)\r
6217                                 ig.Emit (OpCodes.Ldelem_U1);\r
6218                         else if (type == TypeManager.sbyte_type)\r
6219                                 ig.Emit (OpCodes.Ldelem_I1);\r
6220                         else if (type == TypeManager.short_type)\r
6221                                 ig.Emit (OpCodes.Ldelem_I2);\r
6222                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)\r
6223                                 ig.Emit (OpCodes.Ldelem_U2);\r
6224                         else if (type == TypeManager.int32_type)\r
6225                                 ig.Emit (OpCodes.Ldelem_I4);\r
6226                         else if (type == TypeManager.uint32_type)\r
6227                                 ig.Emit (OpCodes.Ldelem_U4);\r
6228                         else if (type == TypeManager.uint64_type)\r
6229                                 ig.Emit (OpCodes.Ldelem_I8);\r
6230                         else if (type == TypeManager.int64_type)\r
6231                                 ig.Emit (OpCodes.Ldelem_I8);\r
6232                         else if (type == TypeManager.float_type)\r
6233                                 ig.Emit (OpCodes.Ldelem_R4);\r
6234                         else if (type == TypeManager.double_type)\r
6235                                 ig.Emit (OpCodes.Ldelem_R8);\r
6236                         else if (type == TypeManager.intptr_type)\r
6237                                 ig.Emit (OpCodes.Ldelem_I);\r
6238                         else if (type.IsValueType){\r
6239                                 ig.Emit (OpCodes.Ldelema, type);\r
6240                                 ig.Emit (OpCodes.Ldobj, type);\r
6241                         } else \r
6242                                 ig.Emit (OpCodes.Ldelem_Ref);\r
6243                 }\r
6244 \r
6245                 /// <summary>\r
6246                 ///    Emits the right opcode to store an object of Type 't'\r
6247                 ///    from an array of T.  \r
6248                 /// </summary>\r
6249                 static public void EmitStoreOpcode (ILGenerator ig, Type t)\r
6250                 {\r
6251                         t = TypeManager.TypeToCoreType (t);\r
6252                         if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)\r
6253                                 t = TypeManager.EnumToUnderlying (t);\r
6254                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||\r
6255                             t == TypeManager.bool_type)\r
6256                                 ig.Emit (OpCodes.Stelem_I1);\r
6257                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type || t == TypeManager.char_type)\r
6258                                 ig.Emit (OpCodes.Stelem_I2);\r
6259                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)\r
6260                                 ig.Emit (OpCodes.Stelem_I4);\r
6261                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)\r
6262                                 ig.Emit (OpCodes.Stelem_I8);\r
6263                         else if (t == TypeManager.float_type)\r
6264                                 ig.Emit (OpCodes.Stelem_R4);\r
6265                         else if (t == TypeManager.double_type)\r
6266                                 ig.Emit (OpCodes.Stelem_R8);\r
6267                         else if (t == TypeManager.intptr_type)\r
6268                                 ig.Emit (OpCodes.Stelem_I);\r
6269                         else if (t.IsValueType){\r
6270                                 ig.Emit (OpCodes.Stobj, t);\r
6271                         } else\r
6272                                 ig.Emit (OpCodes.Stelem_Ref);\r
6273                 }\r
6274 \r
6275                 MethodInfo FetchGetMethod ()\r
6276                 {\r
6277                         ModuleBuilder mb = CodeGen.ModuleBuilder;\r
6278                         int arg_count = ea.Arguments.Count;\r
6279                         Type [] args = new Type [arg_count];\r
6280                         MethodInfo get;\r
6281                         \r
6282                         for (int i = 0; i < arg_count; i++){\r
6283                                 //args [i++] = a.Type;\r
6284                                 args [i] = TypeManager.int32_type;\r
6285                         }\r
6286                         \r
6287                         get = mb.GetArrayMethod (\r
6288                                 ea.Expr.Type, "Get",\r
6289                                 CallingConventions.HasThis |\r
6290                                 CallingConventions.Standard,\r
6291                                 type, args);\r
6292                         return get;\r
6293                 }\r
6294                                 \r
6295 \r
6296                 MethodInfo FetchAddressMethod ()\r
6297                 {\r
6298                         ModuleBuilder mb = CodeGen.ModuleBuilder;\r
6299                         int arg_count = ea.Arguments.Count;\r
6300                         Type [] args = new Type [arg_count];\r
6301                         MethodInfo address;\r
6302                         string ptr_type_name;\r
6303                         Type ret_type;\r
6304                         \r
6305                         ptr_type_name = type.FullName + "&";\r
6306                         ret_type = Type.GetType (ptr_type_name);\r
6307                         \r
6308                         //\r
6309                         // It is a type defined by the source code we are compiling\r
6310                         //\r
6311                         if (ret_type == null){\r
6312                                 ret_type = mb.GetType (ptr_type_name);\r
6313                         }\r
6314 \r
6315                         for (int i = 0; i < arg_count; i++){\r
6316                                 //args [i++] = a.Type;\r
6317                                 args [i] = TypeManager.int32_type;\r
6318                         }\r
6319                         \r
6320                         address = mb.GetArrayMethod (\r
6321                                 ea.Expr.Type, "Address",\r
6322                                 CallingConventions.HasThis |\r
6323                                 CallingConventions.Standard,\r
6324                                 ret_type, args);\r
6325 \r
6326                         return address;\r
6327                 }\r
6328 \r
6329                 //\r
6330                 // Load the array arguments into the stack.\r
6331                 //\r
6332                 // If we have been requested to cache the values (cached_locations array\r
6333                 // initialized), then load the arguments the first time and store them\r
6334                 // in locals.  otherwise load from local variables.\r
6335                 //\r
6336                 void LoadArrayAndArguments (EmitContext ec)\r
6337                 {\r
6338                         ILGenerator ig = ec.ig;\r
6339                         \r
6340                         if (cached_locations == null){\r
6341                                 ea.Expr.Emit (ec);\r
6342                                 foreach (Argument a in ea.Arguments){\r
6343                                         Type argtype = a.Expr.Type;\r
6344                                         \r
6345                                         a.Expr.Emit (ec);\r
6346                                         \r
6347                                         if (argtype == TypeManager.int64_type)\r
6348                                                 ig.Emit (OpCodes.Conv_Ovf_I);\r
6349                                         else if (argtype == TypeManager.uint64_type)\r
6350                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);\r
6351                                 }\r
6352                                 return;\r
6353                         }\r
6354 \r
6355                         if (cached_locations [0] == null){\r
6356                                 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);\r
6357                                 ea.Expr.Emit (ec);\r
6358                                 ig.Emit (OpCodes.Dup);\r
6359                                 cached_locations [0].Store (ec);\r
6360                                 \r
6361                                 int j = 1;\r
6362                                 \r
6363                                 foreach (Argument a in ea.Arguments){\r
6364                                         Type argtype = a.Expr.Type;\r
6365                                         \r
6366                                         cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);\r
6367                                         a.Expr.Emit (ec);\r
6368                                         if (argtype == TypeManager.int64_type)\r
6369                                                 ig.Emit (OpCodes.Conv_Ovf_I);\r
6370                                         else if (argtype == TypeManager.uint64_type)\r
6371                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);\r
6372 \r
6373                                         ig.Emit (OpCodes.Dup);\r
6374                                         cached_locations [j].Store (ec);\r
6375                                         j++;\r
6376                                 }\r
6377                                 return;\r
6378                         }\r
6379 \r
6380                         foreach (LocalTemporary lt in cached_locations)\r
6381                                 lt.Emit (ec);\r
6382                 }\r
6383 \r
6384                 public new void CacheTemporaries (EmitContext ec)\r
6385                 {\r
6386                         cached_locations = new LocalTemporary [ea.Arguments.Count + 1];\r
6387                 }\r
6388                 \r
6389                 public override void Emit (EmitContext ec)\r
6390                 {\r
6391                         int rank = ea.Expr.Type.GetArrayRank ();\r
6392                         ILGenerator ig = ec.ig;\r
6393 \r
6394                         LoadArrayAndArguments (ec);\r
6395                         \r
6396                         if (rank == 1)\r
6397                                 EmitLoadOpcode (ig, type);\r
6398                         else {\r
6399                                 MethodInfo method;\r
6400                                 \r
6401                                 method = FetchGetMethod ();\r
6402                                 ig.Emit (OpCodes.Call, method);\r
6403                         }\r
6404                 }\r
6405 \r
6406                 public void EmitAssign (EmitContext ec, Expression source)\r
6407                 {\r
6408                         int rank = ea.Expr.Type.GetArrayRank ();\r
6409                         ILGenerator ig = ec.ig;\r
6410                         Type t = source.Type;\r
6411 \r
6412                         LoadArrayAndArguments (ec);\r
6413 \r
6414                         //\r
6415                         // The stobj opcode used by value types will need\r
6416                         // an address on the stack, not really an array/array\r
6417                         // pair\r
6418                         //\r
6419                         if (rank == 1){\r
6420                                 if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||\r
6421                                     (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))\r
6422                                         ig.Emit (OpCodes.Ldelema, t);\r
6423                         }\r
6424                         \r
6425                         source.Emit (ec);\r
6426 \r
6427                         if (rank == 1)\r
6428                                 EmitStoreOpcode (ig, t);\r
6429                         else {\r
6430                                 ModuleBuilder mb = CodeGen.ModuleBuilder;\r
6431                                 int arg_count = ea.Arguments.Count;\r
6432                                 Type [] args = new Type [arg_count + 1];\r
6433                                 MethodInfo set;\r
6434                                 \r
6435                                 for (int i = 0; i < arg_count; i++){\r
6436                                         //args [i++] = a.Type;\r
6437                                         args [i] = TypeManager.int32_type;\r
6438                                 }\r
6439 \r
6440                                 args [arg_count] = type;\r
6441                                 \r
6442                                 set = mb.GetArrayMethod (\r
6443                                         ea.Expr.Type, "Set",\r
6444                                         CallingConventions.HasThis |\r
6445                                         CallingConventions.Standard,\r
6446                                         TypeManager.void_type, args);\r
6447                                 \r
6448                                 ig.Emit (OpCodes.Call, set);\r
6449                         }\r
6450                 }\r
6451 \r
6452                 public void AddressOf (EmitContext ec, AddressOp mode)\r
6453                 {\r
6454                         int rank = ea.Expr.Type.GetArrayRank ();\r
6455                         ILGenerator ig = ec.ig;\r
6456 \r
6457                         LoadArrayAndArguments (ec);\r
6458 \r
6459                         if (rank == 1){\r
6460                                 ig.Emit (OpCodes.Ldelema, type);\r
6461                         } else {\r
6462                                 MethodInfo address = FetchAddressMethod ();\r
6463                                 ig.Emit (OpCodes.Call, address);\r
6464                         }\r
6465                 }\r
6466         }\r
6467 \r
6468         \r
6469         class Indexers {\r
6470                 public ArrayList getters, setters;\r
6471                 static Hashtable map;\r
6472 \r
6473                 static Indexers ()\r
6474                 {\r
6475                         map = new Hashtable ();\r
6476                 }\r
6477 \r
6478                 Indexers (MemberInfo [] mi)\r
6479                 {\r
6480                         foreach (PropertyInfo property in mi){\r
6481                                 MethodInfo get, set;\r
6482                                 \r
6483                                 get = property.GetGetMethod (true);\r
6484                                 if (get != null){\r
6485                                         if (getters == null)\r
6486                                                 getters = new ArrayList ();\r
6487 \r
6488                                         getters.Add (get);\r
6489                                 }\r
6490                                 \r
6491                                 set = property.GetSetMethod (true);\r
6492                                 if (set != null){\r
6493                                         if (setters == null)\r
6494                                                 setters = new ArrayList ();\r
6495                                         setters.Add (set);\r
6496                                 }\r
6497                         }\r
6498                 }\r
6499 \r
6500                 static private Indexers GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)\r
6501                 {\r
6502                         Indexers ix = (Indexers) map [lookup_type];\r
6503                         \r
6504                         if (ix != null)\r
6505                                 return ix;\r
6506 \r
6507                         string p_name = TypeManager.IndexerPropertyName (lookup_type);\r
6508 \r
6509                         MemberInfo [] mi = TypeManager.MemberLookup (\r
6510                                 caller_type, lookup_type, MemberTypes.Property,\r
6511                                 BindingFlags.Public | BindingFlags.Instance, p_name);\r
6512 \r
6513                         if (mi == null || mi.Length == 0)\r
6514                                 return null;\r
6515 \r
6516                         ix = new Indexers (mi);\r
6517                         map [lookup_type] = ix;\r
6518 \r
6519                         return ix;\r
6520                 }\r
6521                 \r
6522                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) \r
6523                 {\r
6524                         Indexers ix = (Indexers) map [lookup_type];\r
6525                         \r
6526                         if (ix != null)\r
6527                                 return ix;\r
6528 \r
6529                         ix = GetIndexersForTypeOrInterface (caller_type, lookup_type);\r
6530                         if (ix != null)\r
6531                                 return ix;\r
6532 \r
6533                         Type [] ifaces = TypeManager.GetInterfaces (lookup_type);\r
6534                         if (ifaces != null) {\r
6535                                 foreach (Type itype in ifaces) {\r
6536                                         ix = GetIndexersForTypeOrInterface (caller_type, itype);\r
6537                                         if (ix != null)\r
6538                                                 return ix;\r
6539                                 }\r
6540                         }\r
6541 \r
6542                         Report.Error (21, loc,\r
6543                                       "Type '" + TypeManager.CSharpName (lookup_type) +\r
6544                                       "' does not have any indexers defined");\r
6545                         return null;\r
6546                 }\r
6547         }\r
6548 \r
6549         /// <summary>\r
6550         ///   Expressions that represent an indexer call.\r
6551         /// </summary>\r
6552         public class IndexerAccess : Expression, IAssignMethod {\r
6553                 //\r
6554                 // Points to our "data" repository\r
6555                 //\r
6556                 MethodInfo get, set;\r
6557                 Indexers ilist;\r
6558                 ArrayList set_arguments;\r
6559                 bool is_base_indexer;\r
6560 \r
6561                 protected Type indexer_type;\r
6562                 protected Type current_type;\r
6563                 protected Expression instance_expr;\r
6564                 protected ArrayList arguments;\r
6565                 \r
6566                 public IndexerAccess (ElementAccess ea, Location loc)\r
6567                         : this (ea.Expr, false, loc)\r
6568                 {\r
6569                         this.arguments = ea.Arguments;\r
6570                 }\r
6571 \r
6572                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,\r
6573                                          Location loc)\r
6574                 {\r
6575                         this.instance_expr = instance_expr;\r
6576                         this.is_base_indexer = is_base_indexer;\r
6577                         this.eclass = ExprClass.Value;\r
6578                         this.loc = loc;\r
6579                 }\r
6580 \r
6581                 protected virtual bool CommonResolve (EmitContext ec)\r
6582                 {\r
6583                         indexer_type = instance_expr.Type;\r
6584                         current_type = ec.ContainerType;\r
6585 \r
6586                         return true;\r
6587                 }\r
6588 \r
6589                 public override Expression DoResolve (EmitContext ec)\r
6590                 {\r
6591                         if (!CommonResolve (ec))\r
6592                                 return null;\r
6593 \r
6594                         //\r
6595                         // Step 1: Query for all 'Item' *properties*.  Notice\r
6596                         // that the actual methods are pointed from here.\r
6597                         //\r
6598                         // This is a group of properties, piles of them.  \r
6599 \r
6600                         if (ilist == null)\r
6601                                 ilist = Indexers.GetIndexersForType (\r
6602                                         current_type, indexer_type, loc);\r
6603 \r
6604                         //\r
6605                         // Step 2: find the proper match\r
6606                         //\r
6607                         if (ilist != null && ilist.getters != null && ilist.getters.Count > 0)\r
6608                                 get = (MethodInfo) Invocation.OverloadResolve (\r
6609                                         ec, new MethodGroupExpr (ilist.getters, loc), arguments, loc);\r
6610 \r
6611                         if (get == null){\r
6612                                 Error (154, "indexer can not be used in this context, because " +\r
6613                                        "it lacks a 'get' accessor");\r
6614                                 return null;\r
6615                         }\r
6616 \r
6617                         type = get.ReturnType;\r
6618                         if (type.IsPointer && !ec.InUnsafe){\r
6619                                 UnsafeError (loc);\r
6620                                 return null;\r
6621                         }\r
6622                         \r
6623                         eclass = ExprClass.IndexerAccess;\r
6624                         return this;\r
6625                 }\r
6626 \r
6627                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)\r
6628                 {\r
6629                         if (!CommonResolve (ec))\r
6630                                 return null;\r
6631 \r
6632                         Type right_type = right_side.Type;\r
6633 \r
6634                         if (ilist == null)\r
6635                                 ilist = Indexers.GetIndexersForType (\r
6636                                         current_type, indexer_type, loc);\r
6637 \r
6638                         if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){\r
6639                                 set_arguments = (ArrayList) arguments.Clone ();\r
6640                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));\r
6641 \r
6642                                 set = (MethodInfo) Invocation.OverloadResolve (\r
6643                                         ec, new MethodGroupExpr (ilist.setters, loc), set_arguments, loc);\r
6644                         }\r
6645                         \r
6646                         if (set == null){\r
6647                                 Error (200, "indexer X.this [" + TypeManager.CSharpName (right_type) +\r
6648                                        "] lacks a 'set' accessor");\r
6649                                 return null;\r
6650                         }\r
6651 \r
6652                         type = TypeManager.void_type;\r
6653                         eclass = ExprClass.IndexerAccess;\r
6654                         return this;\r
6655                 }\r
6656                 \r
6657                 public override void Emit (EmitContext ec)\r
6658                 {\r
6659                         Invocation.EmitCall (ec, false, false, instance_expr, get, arguments, loc);\r
6660                 }\r
6661 \r
6662                 //\r
6663                 // source is ignored, because we already have a copy of it from the\r
6664                 // LValue resolution and we have already constructed a pre-cached\r
6665                 // version of the arguments (ea.set_arguments);\r
6666                 //\r
6667                 public void EmitAssign (EmitContext ec, Expression source)\r
6668                 {\r
6669                         Invocation.EmitCall (ec, false, false, instance_expr, set, set_arguments, loc);\r
6670                 }\r
6671         }\r
6672 \r
6673         /// <summary>\r
6674         ///   The base operator for method names\r
6675         /// </summary>\r
6676         public class BaseAccess : Expression {\r
6677                 string member;\r
6678                 \r
6679                 public BaseAccess (string member, Location l)\r
6680                 {\r
6681                         this.member = member;\r
6682                         loc = l;\r
6683                 }\r
6684 \r
6685                 public override Expression DoResolve (EmitContext ec)\r
6686                 {\r
6687                         Expression member_lookup;\r
6688                         Type current_type = ec.ContainerType;\r
6689                         Type base_type = current_type.BaseType;\r
6690                         Expression e;\r
6691 \r
6692                         if (ec.IsStatic){\r
6693                                 Error (1511, "Keyword MyBase is not allowed in static method");\r
6694                                 return null;\r
6695                         }\r
6696                         \r
6697                         if (member == "New")\r
6698                                 member = ".ctor";\r
6699                         \r
6700                         member_lookup = MemberLookup (ec, base_type, base_type, member,\r
6701                                                       AllMemberTypes, AllBindingFlags, loc);\r
6702 \r
6703                         if (member_lookup == null) {\r
6704                                 Error (117,\r
6705                                               TypeManager.CSharpName (base_type) + " does not " +\r
6706                                               "contain a definition for '" + member + "'");\r
6707                                 return null;\r
6708                         }\r
6709 \r
6710                         Expression left;\r
6711                         \r
6712                         if (ec.IsStatic)\r
6713                                 left = new TypeExpr (base_type, loc);\r
6714                         else\r
6715                                 left = ec.This;\r
6716                         \r
6717                         e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);\r
6718 \r
6719                         if (e is PropertyExpr){\r
6720                                 PropertyExpr pe = (PropertyExpr) e;\r
6721 \r
6722                                 pe.IsBase = true;\r
6723                         }\r
6724 \r
6725                         return e;\r
6726                 }\r
6727 \r
6728                 public override void Emit (EmitContext ec)\r
6729                 {\r
6730                         throw new Exception ("Should never be called"); \r
6731                 }\r
6732         }\r
6733 \r
6734         /// <summary>\r
6735         ///   The base indexer operator\r
6736         /// </summary>\r
6737         public class BaseIndexerAccess : IndexerAccess {\r
6738                 public BaseIndexerAccess (ArrayList args, Location loc)\r
6739                         : base (null, true, loc)\r
6740                 {\r
6741                         arguments = new ArrayList ();\r
6742                         foreach (Expression tmp in args)\r
6743                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));\r
6744                 }\r
6745 \r
6746                 protected override bool CommonResolve (EmitContext ec)\r
6747                 {\r
6748                         instance_expr = ec.This;\r
6749 \r
6750                         current_type = ec.ContainerType.BaseType;\r
6751                         indexer_type = current_type;\r
6752 \r
6753                         foreach (Argument a in arguments){\r
6754                                 if (!a.Resolve (ec, loc))\r
6755                                         return false;\r
6756                         }\r
6757 \r
6758                         return true;\r
6759                 }\r
6760         }\r
6761         \r
6762         /// <summary>\r
6763         ///   This class exists solely to pass the Type around and to be a dummy\r
6764         ///   that can be passed to the conversion functions (this is used by\r
6765         ///   foreach implementation to typecast the object return value from\r
6766         ///   get_Current into the proper type.  All code has been generated and\r
6767         ///   we only care about the side effect conversions to be performed\r
6768         ///\r
6769         ///   This is also now used as a placeholder where a no-action expression\r
6770         ///   is needed (the 'New' class).\r
6771         /// </summary>\r
6772         public class EmptyExpression : Expression {\r
6773                 public EmptyExpression ()\r
6774                 {\r
6775                         type = TypeManager.object_type;\r
6776                         eclass = ExprClass.Value;\r
6777                         loc = Location.Null;\r
6778                 }\r
6779 \r
6780                 public EmptyExpression (Type t)\r
6781                 {\r
6782                         type = t;\r
6783                         eclass = ExprClass.Value;\r
6784                         loc = Location.Null;\r
6785                 }\r
6786                 \r
6787                 public override Expression DoResolve (EmitContext ec)\r
6788                 {\r
6789                         return this;\r
6790                 }\r
6791 \r
6792                 public override void Emit (EmitContext ec)\r
6793                 {\r
6794                         // nothing, as we only exist to not do anything.\r
6795                 }\r
6796 \r
6797                 //\r
6798                 // This is just because we might want to reuse this bad boy\r
6799                 // instead of creating gazillions of EmptyExpressions.\r
6800                 // (CanConvertImplicit uses it)\r
6801                 //\r
6802                 public void SetType (Type t)\r
6803                 {\r
6804                         type = t;\r
6805                 }\r
6806         }\r
6807 \r
6808         public class UserCast : Expression {\r
6809                 MethodBase method;\r
6810                 Expression source;\r
6811                 \r
6812                 public UserCast (MethodInfo method, Expression source, Location l)\r
6813                 {\r
6814                         this.method = method;\r
6815                         this.source = source;\r
6816                         type = method.ReturnType;\r
6817                         eclass = ExprClass.Value;\r
6818                         loc = l;\r
6819                 }\r
6820 \r
6821                 public override Expression DoResolve (EmitContext ec)\r
6822                 {\r
6823                         //\r
6824                         // We are born fully resolved\r
6825                         //\r
6826                         return this;\r
6827                 }\r
6828 \r
6829                 public override void Emit (EmitContext ec)\r
6830                 {\r
6831                         ILGenerator ig = ec.ig;\r
6832 \r
6833                         source.Emit (ec);\r
6834                         \r
6835                         if (method is MethodInfo)\r
6836                                 ig.Emit (OpCodes.Call, (MethodInfo) method);\r
6837                         else\r
6838                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);\r
6839 \r
6840                 }\r
6841         }\r
6842 \r
6843         // <summary>\r
6844         //   This class is used to "construct" the type during a typecast\r
6845         //   operation.  Since the Type.GetType class in .NET can parse\r
6846         //   the type specification, we just use this to construct the type\r
6847         //   one bit at a time.\r
6848         // </summary>\r
6849         public class ComposedCast : Expression, ITypeExpression {\r
6850                 Expression left;\r
6851                 string dim;\r
6852                 \r
6853                 public ComposedCast (Expression left, string dim, Location l)\r
6854                 {\r
6855                         this.left = left;\r
6856                         this.dim = dim;\r
6857                         loc = l;\r
6858                 }\r
6859 \r
6860                 public Expression DoResolveType (EmitContext ec)\r
6861                 {\r
6862                         Type ltype = ec.DeclSpace.ResolveType (left, false, loc);\r
6863                         if (ltype == null)\r
6864                                 return null;\r
6865 \r
6866                         //\r
6867                         // ltype.Fullname is already fully qualified, so we can skip\r
6868                         // a lot of probes, and go directly to TypeManager.LookupType\r
6869                         //\r
6870                         string cname = ltype.FullName + dim;\r
6871                         type = TypeManager.LookupTypeDirect (cname);\r
6872                         if (type == null){\r
6873                                 //\r
6874                                 // For arrays of enumerations we are having a problem\r
6875                                 // with the direct lookup.  Need to investigate.\r
6876                                 //\r
6877                                 // For now, fall back to the full lookup in that case.\r
6878                                 //\r
6879                                 type = RootContext.LookupType (\r
6880                                         ec.DeclSpace, cname, false, loc);\r
6881 \r
6882                                 if (type == null)\r
6883                                         return null;\r
6884                         }\r
6885 \r
6886                         if (!ec.ResolvingTypeTree){\r
6887                                 //\r
6888                                 // If the above flag is set, this is being invoked from the ResolveType function.\r
6889                                 // Upper layers take care of the type validity in this context.\r
6890                                 //\r
6891                         if (!ec.InUnsafe && type.IsPointer){\r
6892                                 UnsafeError (loc);\r
6893                                 return null;\r
6894                         }\r
6895                         }\r
6896                         \r
6897                         eclass = ExprClass.Type;\r
6898                         return this;\r
6899                 }\r
6900 \r
6901                 public override Expression DoResolve (EmitContext ec)\r
6902                 {\r
6903                         return DoResolveType (ec);\r
6904                 }\r
6905 \r
6906                 public override void Emit (EmitContext ec)\r
6907                 {\r
6908                         throw new Exception ("This should never be called");\r
6909                 }\r
6910 \r
6911                 public override string ToString ()\r
6912                 {\r
6913                         return left + dim;\r
6914                 }\r
6915         }\r
6916 \r
6917         //\r
6918         // This class is used to represent the address of an array, used\r
6919         // only by the Fixed statement, this is like the C "&a [0]" construct.\r
6920         //\r
6921         public class ArrayPtr : Expression {\r
6922                 Expression array;\r
6923                 \r
6924                 public ArrayPtr (Expression array, Location l)\r
6925                 {\r
6926                         Type array_type = array.Type.GetElementType ();\r
6927 \r
6928                         this.array = array;\r
6929                         \r
6930                         string array_ptr_type_name = array_type.FullName + "*";\r
6931                         \r
6932                         type = Type.GetType (array_ptr_type_name);\r
6933                         if (type == null){\r
6934                                 ModuleBuilder mb = CodeGen.ModuleBuilder;\r
6935                                 \r
6936                                 type = mb.GetType (array_ptr_type_name);\r
6937                         }\r
6938 \r
6939                         eclass = ExprClass.Value;\r
6940                         loc = l;\r
6941                 }\r
6942 \r
6943                 public override void Emit (EmitContext ec)\r
6944                 {\r
6945                         ILGenerator ig = ec.ig;\r
6946                         \r
6947                         array.Emit (ec);\r
6948                         IntLiteral.EmitInt (ig, 0);\r
6949                         ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());\r
6950                 }\r
6951 \r
6952                 public override Expression DoResolve (EmitContext ec)\r
6953                 {\r
6954                         //\r
6955                         // We are born fully resolved\r
6956                         //\r
6957                         return this;\r
6958                 }\r
6959         }\r
6960 \r
6961         //\r
6962         // Used by the fixed statement\r
6963         //\r
6964         public class StringPtr : Expression {\r
6965                 LocalBuilder b;\r
6966                 \r
6967                 public StringPtr (LocalBuilder b, Location l)\r
6968                 {\r
6969                         this.b = b;\r
6970                         eclass = ExprClass.Value;\r
6971                         type = TypeManager.char_ptr_type;\r
6972                         loc = l;\r
6973                 }\r
6974 \r
6975                 public override Expression DoResolve (EmitContext ec)\r
6976                 {\r
6977                         // This should never be invoked, we are born in fully\r
6978                         // initialized state.\r
6979 \r
6980                         return this;\r
6981                 }\r
6982 \r
6983                 public override void Emit (EmitContext ec)\r
6984                 {\r
6985                         ILGenerator ig = ec.ig;\r
6986 \r
6987                         ig.Emit (OpCodes.Ldloc, b);\r
6988                         ig.Emit (OpCodes.Conv_I);\r
6989                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);\r
6990                         ig.Emit (OpCodes.Add);\r
6991                 }\r
6992         }\r
6993         \r
6994         //\r
6995         // Implements the 'stackalloc' keyword\r
6996         //\r
6997         public class StackAlloc : Expression {\r
6998                 Type otype;\r
6999                 Expression t;\r
7000                 Expression count;\r
7001                 \r
7002                 public StackAlloc (Expression type, Expression count, Location l)\r
7003                 {\r
7004                         t = type;\r
7005                         this.count = count;\r
7006                         loc = l;\r
7007                 }\r
7008 \r
7009                 public override Expression DoResolve (EmitContext ec)\r
7010                 {\r
7011                         count = count.Resolve (ec);\r
7012                         if (count == null)\r
7013                                 return null;\r
7014                         \r
7015                         if (count.Type != TypeManager.int32_type){\r
7016                                 count = ConvertImplicitRequired (ec, count, TypeManager.int32_type, loc);\r
7017                                 if (count == null)\r
7018                                         return null;\r
7019                         }\r
7020 \r
7021                         if (ec.InCatch || ec.InFinally){\r
7022                                 Error (255,\r
7023                                               "stackalloc can not be used in a catch or finally block");\r
7024                                 return null;\r
7025                         }\r
7026 \r
7027                         otype = ec.DeclSpace.ResolveType (t, false, loc);\r
7028 \r
7029                         if (otype == null)\r
7030                                 return null;\r
7031 \r
7032                         if (!TypeManager.VerifyUnManaged (otype, loc))\r
7033                                 return null;\r
7034 \r
7035                         string ptr_name = otype.FullName + "*";\r
7036                         type = Type.GetType (ptr_name);\r
7037                         if (type == null){\r
7038                                 ModuleBuilder mb = CodeGen.ModuleBuilder;\r
7039                                 \r
7040                                 type = mb.GetType (ptr_name);\r
7041                         }\r
7042                         eclass = ExprClass.Value;\r
7043 \r
7044                         return this;\r
7045                 }\r
7046 \r
7047                 public override void Emit (EmitContext ec)\r
7048                 {\r
7049                         int size = GetTypeSize (otype);\r
7050                         ILGenerator ig = ec.ig;\r
7051                                 \r
7052                         if (size == 0)\r
7053                                 ig.Emit (OpCodes.Sizeof, otype);\r
7054                         else\r
7055                                 IntConstant.EmitInt (ig, size);\r
7056                         count.Emit (ec);\r
7057                         ig.Emit (OpCodes.Mul);\r
7058                         ig.Emit (OpCodes.Localloc);\r
7059                 }\r
7060         }\r
7061 }\r