2008-10-01 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / expression.cs
1 //
2 // expression.cs: Expression representation for the IL tree.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Marek Safar (marek.safar@gmail.com)
7 //
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 //
11 #define USE_OLD
12
13 namespace Mono.CSharp {
14         using System;
15         using System.Collections;
16         using System.Reflection;
17         using System.Reflection.Emit;
18         using System.Text;
19
20         //
21         // This is an user operator expression, automatically created during
22         // resolve phase
23         //
24         public class UserOperatorCall : Expression {
25                 public delegate Expression ExpressionTreeExpression (EmitContext ec, MethodGroupExpr mg);
26
27                 protected readonly ArrayList arguments;
28                 protected readonly MethodGroupExpr mg;
29                 readonly ExpressionTreeExpression expr_tree;
30
31                 public UserOperatorCall (MethodGroupExpr mg, ArrayList args, ExpressionTreeExpression expr_tree, Location loc)
32                 {
33                         this.mg = mg;
34                         this.arguments = args;
35                         this.expr_tree = expr_tree;
36
37                         type = TypeManager.TypeToCoreType (((MethodInfo) mg).ReturnType);
38                         eclass = ExprClass.Value;
39                         this.loc = loc;
40                 }
41
42                 public override Expression CreateExpressionTree (EmitContext ec)
43                 {
44                         if (expr_tree != null)
45                                 return expr_tree (ec, mg);
46
47                         ArrayList args = new ArrayList (arguments.Count + 1);
48                         args.Add (new Argument (new NullLiteral (loc)));
49                         args.Add (new Argument (mg.CreateExpressionTree (ec)));
50                         foreach (Argument a in arguments) {
51                                 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
52                         }
53
54                         return CreateExpressionFactoryCall ("Call", args);
55                 }
56
57                 protected override void CloneTo (CloneContext context, Expression target)
58                 {
59                         // Nothing to clone
60                 }
61                 
62                 public override Expression DoResolve (EmitContext ec)
63                 {
64                         //
65                         // We are born fully resolved
66                         //
67                         return this;
68                 }
69
70                 public override void Emit (EmitContext ec)
71                 {
72                         mg.EmitCall (ec, arguments);
73                 }
74
75                 public MethodGroupExpr Method {
76                         get { return mg; }
77                 }
78
79                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
80                 {
81                         foreach (Argument a in arguments)
82                                 a.Expr.MutateHoistedGenericType (storey);
83
84                         mg.MutateHoistedGenericType (storey);
85                 }
86         }
87
88         public class ParenthesizedExpression : Expression
89         {
90                 public Expression Expr;
91
92                 public ParenthesizedExpression (Expression expr)
93                 {
94                         Expr = expr;
95                         loc = expr.Location;
96                 }
97
98                 public override Expression CreateExpressionTree (EmitContext ec)
99                 {
100                         throw new NotSupportedException ("ET");
101                 }
102
103                 public override Expression DoResolve (EmitContext ec)
104                 {
105                         Expr = Expr.Resolve (ec);
106                         return Expr;
107                 }
108
109                 public override void Emit (EmitContext ec)
110                 {
111                         throw new Exception ("Should not happen");
112                 }
113
114                 protected override void CloneTo (CloneContext clonectx, Expression t)
115                 {
116                         ParenthesizedExpression target = (ParenthesizedExpression) t;
117
118                         target.Expr = Expr.Clone (clonectx);
119                 }
120         }
121         
122         //
123         //   Unary implements unary expressions.
124         //
125         public class Unary : Expression {
126                 public enum Operator : byte {
127                         UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
128                         AddressOf,  TOP
129                 }
130
131                 static Type [] [] predefined_operators;
132
133                 public readonly Operator Oper;
134                 public Expression Expr;
135                 Expression enum_conversion;
136
137                 public Unary (Operator op, Expression expr, Location loc)
138                 {
139                         Oper = op;
140                         Expr = expr;
141                         this.loc = loc;
142                 }
143
144                 // <summary>
145                 //   This routine will attempt to simplify the unary expression when the
146                 //   argument is a constant.
147                 // </summary>
148                 Constant TryReduceConstant (EmitContext ec, Constant e)
149                 {
150                         if (e is EmptyConstantCast)
151                                 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
152                         
153                         if (e is SideEffectConstant) {
154                                 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
155                                 return r == null ? null : new SideEffectConstant (r, e, r.Location);
156                         }
157
158                         Type expr_type = e.Type;
159                         
160                         switch (Oper){
161                         case Operator.UnaryPlus:
162                                 // Unary numeric promotions
163                                 if (expr_type == TypeManager.byte_type)
164                                         return new IntConstant (((ByteConstant)e).Value, e.Location);
165                                 if (expr_type == TypeManager.sbyte_type)
166                                         return new IntConstant (((SByteConstant)e).Value, e.Location);
167                                 if (expr_type == TypeManager.short_type)
168                                         return new IntConstant (((ShortConstant)e).Value, e.Location);
169                                 if (expr_type == TypeManager.ushort_type)
170                                         return new IntConstant (((UShortConstant)e).Value, e.Location);
171                                 if (expr_type == TypeManager.char_type)
172                                         return new IntConstant (((CharConstant)e).Value, e.Location);
173                                 
174                                 // Predefined operators
175                                 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
176                                     expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
177                                     expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
178                                     expr_type == TypeManager.decimal_type) {
179                                         return e;
180                                 }
181                                 
182                                 return null;
183                                 
184                         case Operator.UnaryNegation:
185                                 // Unary numeric promotions
186                                 if (expr_type == TypeManager.byte_type)
187                                         return new IntConstant (-((ByteConstant)e).Value, e.Location);
188                                 if (expr_type == TypeManager.sbyte_type)
189                                         return new IntConstant (-((SByteConstant)e).Value, e.Location);
190                                 if (expr_type == TypeManager.short_type)
191                                         return new IntConstant (-((ShortConstant)e).Value, e.Location);
192                                 if (expr_type == TypeManager.ushort_type)
193                                         return new IntConstant (-((UShortConstant)e).Value, e.Location);
194                                 if (expr_type == TypeManager.char_type)
195                                         return new IntConstant (-((CharConstant)e).Value, e.Location);
196                                 
197                                 // Predefined operators
198                                 if (expr_type == TypeManager.int32_type) {
199                                         int value = ((IntConstant)e).Value;
200                                         if (value == int.MinValue) {
201                                                 if (ec.ConstantCheckState) {
202                                                         ConstantFold.Error_CompileTimeOverflow (loc);
203                                                         return null;
204                                                 }
205                                                 return e;
206                                         }
207                                         return new IntConstant (-value, e.Location);
208                                 }
209                                 if (expr_type == TypeManager.int64_type) {
210                                         long value = ((LongConstant)e).Value;
211                                         if (value == long.MinValue) {
212                                                 if (ec.ConstantCheckState) {
213                                                         ConstantFold.Error_CompileTimeOverflow (loc);
214                                                         return null;
215                                                 }
216                                                 return e;
217                                         }
218                                         return new LongConstant (-value, e.Location);
219                                 }
220                                 
221                                 if (expr_type == TypeManager.uint32_type) {
222                                         UIntLiteral uil = e as UIntLiteral;
223                                         if (uil != null) {
224                                                 if (uil.Value == 2147483648)
225                                                         return new IntLiteral (int.MinValue, e.Location);
226                                                 return new LongLiteral (-uil.Value, e.Location);
227                                         }
228                                         return new LongConstant (-((UIntConstant)e).Value, e.Location);
229                                 }
230                                 
231                                 if (expr_type == TypeManager.uint64_type) {
232                                         ULongLiteral ull = e as ULongLiteral;
233                                         if (ull != null && ull.Value == 9223372036854775808)
234                                                 return new LongLiteral (long.MinValue, e.Location);
235                                         return null;
236                                 }
237                                 
238                                 if (expr_type == TypeManager.float_type) {
239                                         FloatLiteral fl = e as FloatLiteral;
240                                         // For better error reporting
241                                         if (fl != null) {
242                                                 fl.Value = -fl.Value;
243                                                 return fl;
244                                         }
245                                         return new FloatConstant (-((FloatConstant)e).Value, e.Location);
246                                 }
247                                 if (expr_type == TypeManager.double_type) {
248                                         DoubleLiteral dl = e as DoubleLiteral;
249                                         // For better error reporting
250                                         if (dl != null) {
251                                                 dl.Value = -dl.Value;
252                                                 return dl;
253                                         }
254                                         
255                                         return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
256                                 }
257                                 if (expr_type == TypeManager.decimal_type)
258                                         return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
259                                 
260                                 return null;
261                                 
262                         case Operator.LogicalNot:
263                                 if (expr_type != TypeManager.bool_type)
264                                         return null;
265                                 
266                                 bool b = (bool)e.GetValue ();
267                                 return new BoolConstant (!b, e.Location);
268                                 
269                         case Operator.OnesComplement:
270                                 // Unary numeric promotions
271                                 if (expr_type == TypeManager.byte_type)
272                                         return new IntConstant (~((ByteConstant)e).Value, e.Location);
273                                 if (expr_type == TypeManager.sbyte_type)
274                                         return new IntConstant (~((SByteConstant)e).Value, e.Location);
275                                 if (expr_type == TypeManager.short_type)
276                                         return new IntConstant (~((ShortConstant)e).Value, e.Location);
277                                 if (expr_type == TypeManager.ushort_type)
278                                         return new IntConstant (~((UShortConstant)e).Value, e.Location);
279                                 if (expr_type == TypeManager.char_type)
280                                         return new IntConstant (~((CharConstant)e).Value, e.Location);
281                                 
282                                 // Predefined operators
283                                 if (expr_type == TypeManager.int32_type)
284                                         return new IntConstant (~((IntConstant)e).Value, e.Location);
285                                 if (expr_type == TypeManager.uint32_type)
286                                         return new UIntConstant (~((UIntConstant)e).Value, e.Location);
287                                 if (expr_type == TypeManager.int64_type)
288                                         return new LongConstant (~((LongConstant)e).Value, e.Location);
289                                 if (expr_type == TypeManager.uint64_type){
290                                         return new ULongConstant (~((ULongConstant)e).Value, e.Location);
291                                 }
292                                 if (e is EnumConstant) {
293                                         e = TryReduceConstant (ec, ((EnumConstant)e).Child);
294                                         if (e != null)
295                                                 e = new EnumConstant (e, expr_type);
296                                         return e;
297                                 }
298                                 return null;
299                         }
300                         throw new Exception ("Can not constant fold: " + Oper.ToString());
301                 }
302                 
303                 protected Expression ResolveOperator (EmitContext ec, Expression expr)
304                 {
305                         eclass = ExprClass.Value;
306
307                         if (predefined_operators == null)
308                                 CreatePredefinedOperatorsTable ();
309
310                         Type expr_type = expr.Type;
311                         Expression best_expr;
312
313                         //
314                         // Primitive types first
315                         //
316                         if (TypeManager.IsPrimitiveType (expr_type)) {
317                                 best_expr = ResolvePrimitivePredefinedType (expr);
318                                 if (best_expr == null)
319                                         return null;
320
321                                 type = best_expr.Type;
322                                 Expr = best_expr;
323                                 return this;
324                         }
325
326                         //
327                         // E operator ~(E x);
328                         //
329                         if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
330                                 return ResolveEnumOperator (ec, expr);
331
332                         return ResolveUserType (ec, expr);
333                 }
334
335                 protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
336                 {
337                         Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
338                         Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
339                         if (best_expr == null)
340                                 return null;
341
342                         Expr = best_expr;
343                         enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
344                         type = expr.Type;
345                         return EmptyCast.Create (this, type);
346                 }
347
348                 public override Expression CreateExpressionTree (EmitContext ec)
349                 {
350                         return CreateExpressionTree (ec, null);
351                 }
352
353                 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
354                 {
355                         string method_name;
356                         switch (Oper) {
357                         case Operator.AddressOf:
358                                 Error_PointerInsideExpressionTree ();
359                                 return null;
360                         case Operator.UnaryNegation:
361                                 if (ec.CheckState && user_op == null && !IsFloat (type))
362                                         method_name = "NegateChecked";
363                                 else
364                                         method_name = "Negate";
365                                 break;
366                         case Operator.OnesComplement:
367                         case Operator.LogicalNot:
368                                 method_name = "Not";
369                                 break;
370                         case Operator.UnaryPlus:
371                                 method_name = "UnaryPlus";
372                                 break;
373                         default:
374                                 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
375                         }
376
377                         ArrayList args = new ArrayList (2);
378                         args.Add (new Argument (Expr.CreateExpressionTree (ec)));
379                         if (user_op != null)
380                                 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
381                         return CreateExpressionFactoryCall (method_name, args);
382                 }
383
384                 static void CreatePredefinedOperatorsTable ()
385                 {
386                         predefined_operators = new Type [(int) Operator.TOP] [];
387
388                         //
389                         // 7.6.1 Unary plus operator
390                         //
391                         predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
392                                 TypeManager.int32_type, TypeManager.uint32_type,
393                                 TypeManager.int64_type, TypeManager.uint64_type,
394                                 TypeManager.float_type, TypeManager.double_type,
395                                 TypeManager.decimal_type
396                         };
397
398                         //
399                         // 7.6.2 Unary minus operator
400                         //
401                         predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
402                                 TypeManager.int32_type, 
403                                 TypeManager.int64_type,
404                                 TypeManager.float_type, TypeManager.double_type,
405                                 TypeManager.decimal_type
406                         };
407
408                         //
409                         // 7.6.3 Logical negation operator
410                         //
411                         predefined_operators [(int) Operator.LogicalNot] = new Type [] {
412                                 TypeManager.bool_type
413                         };
414
415                         //
416                         // 7.6.4 Bitwise complement operator
417                         //
418                         predefined_operators [(int) Operator.OnesComplement] = new Type [] {
419                                 TypeManager.int32_type, TypeManager.uint32_type,
420                                 TypeManager.int64_type, TypeManager.uint64_type
421                         };
422                 }
423
424                 //
425                 // Unary numeric promotions
426                 //
427                 static Expression DoNumericPromotion (Operator op, Expression expr)
428                 {
429                         Type expr_type = expr.Type;
430                         if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
431                                 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
432                                 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
433                                 expr_type == TypeManager.char_type)
434                                 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
435
436                         if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
437                                 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
438
439                         return expr;
440                 }
441
442                 public override Expression DoResolve (EmitContext ec)
443                 {
444                         if (Oper == Operator.AddressOf) {
445                                 return ResolveAddressOf (ec);
446                         }
447
448                         Expr = Expr.Resolve (ec);
449                         if (Expr == null)
450                                 return null;
451
452                         if (TypeManager.IsNullableValueType (Expr.Type))
453                                 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
454
455                         //
456                         // Attempt to use a constant folding operation.
457                         //
458                         Constant cexpr = Expr as Constant;
459                         if (cexpr != null) {
460                                 cexpr = TryReduceConstant (ec, cexpr);
461                                 if (cexpr != null)
462                                         return cexpr;
463                         }
464
465                         Expression expr = ResolveOperator (ec, Expr);
466                         if (expr == null)
467                                 Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
468                         
469                         //
470                         // Reduce unary operator on predefined types
471                         //
472                         if (expr == this && Oper == Operator.UnaryPlus)
473                                 return Expr;
474
475                         return expr;
476                 }
477
478                 public override Expression DoResolveLValue (EmitContext ec, Expression right)
479                 {
480                         return null;
481                 }
482
483                 public override void Emit (EmitContext ec)
484                 {
485                         EmitOperator (ec, type);
486                 }
487
488                 protected void EmitOperator (EmitContext ec, Type type)
489                 {
490                         ILGenerator ig = ec.ig;
491
492                         switch (Oper) {
493                         case Operator.UnaryPlus:
494                                 Expr.Emit (ec);
495                                 break;
496                                 
497                         case Operator.UnaryNegation:
498                                 if (ec.CheckState && !IsFloat (type)) {
499                                         ig.Emit (OpCodes.Ldc_I4_0);
500                                         if (type == TypeManager.int64_type)
501                                                 ig.Emit (OpCodes.Conv_U8);
502                                         Expr.Emit (ec);
503                                         ig.Emit (OpCodes.Sub_Ovf);
504                                 } else {
505                                         Expr.Emit (ec);
506                                         ig.Emit (OpCodes.Neg);
507                                 }
508                                 
509                                 break;
510                                 
511                         case Operator.LogicalNot:
512                                 Expr.Emit (ec);
513                                 ig.Emit (OpCodes.Ldc_I4_0);
514                                 ig.Emit (OpCodes.Ceq);
515                                 break;
516                                 
517                         case Operator.OnesComplement:
518                                 Expr.Emit (ec);
519                                 ig.Emit (OpCodes.Not);
520                                 break;
521                                 
522                         case Operator.AddressOf:
523                                 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
524                                 break;
525                                 
526                         default:
527                                 throw new Exception ("This should not happen: Operator = "
528                                                      + Oper.ToString ());
529                         }
530
531                         //
532                         // Same trick as in Binary expression
533                         //
534                         if (enum_conversion != null)
535                                 enum_conversion.Emit (ec);
536                 }
537
538                 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
539                 {
540                         if (Oper == Operator.LogicalNot)
541                                 Expr.EmitBranchable (ec, target, !on_true);
542                         else
543                                 base.EmitBranchable (ec, target, on_true);
544                 }
545
546                 public override void EmitSideEffect (EmitContext ec)
547                 {
548                         Expr.EmitSideEffect (ec);
549                 }
550
551                 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
552                 {
553                         Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
554                                 oper, TypeManager.CSharpName (t));
555                 }
556
557                 static bool IsFloat (Type t)
558                 {
559                         return t == TypeManager.float_type || t == TypeManager.double_type;
560                 }
561
562                 //
563                 // Returns a stringified representation of the Operator
564                 //
565                 public static string OperName (Operator oper)
566                 {
567                         switch (oper) {
568                         case Operator.UnaryPlus:
569                                 return "+";
570                         case Operator.UnaryNegation:
571                                 return "-";
572                         case Operator.LogicalNot:
573                                 return "!";
574                         case Operator.OnesComplement:
575                                 return "~";
576                         case Operator.AddressOf:
577                                 return "&";
578                         }
579
580                         throw new NotImplementedException (oper.ToString ());
581                 }
582
583                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
584                 {
585                         type = storey.MutateType (type);
586                         Expr.MutateHoistedGenericType (storey);
587                 }
588
589                 Expression ResolveAddressOf (EmitContext ec)
590                 {
591                         if (!ec.InUnsafe)
592                                 UnsafeError (loc);
593
594                         Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
595                         if (Expr == null || Expr.eclass != ExprClass.Variable) {
596                                 Error (211, "Cannot take the address of the given expression");
597                                 return null;
598                         }
599
600                         if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
601                                 return null;
602                         }
603
604                         IVariableReference vr = Expr as IVariableReference;
605                         bool is_fixed;
606                         if (vr != null) {
607                                 VariableInfo vi = vr.VariableInfo;
608                                 if (vi != null) {
609                                         if (vi.LocalInfo != null)
610                                                 vi.LocalInfo.Used = true;
611
612                                         //
613                                         // A variable is considered definitely assigned if you take its address.
614                                         //
615                                         vi.SetAssigned (ec);
616                                 }
617
618                                 is_fixed = vr.IsFixed;
619                                 vr.SetHasAddressTaken ();
620
621                                 if (vr.IsHoisted) {
622                                         AnonymousMethodExpression.Error_AddressOfCapturedVar (vr, loc);
623                                 }
624                         } else {
625                                 //
626                                 // A pointer-indirection is always fixed
627                                 //
628                                 is_fixed = Expr is Indirection;
629                         }
630
631                         if (!is_fixed && !ec.InFixedInitializer) {
632                                 Error (212, "You can only take the address of unfixed expression inside of a fixed statement initializer");
633                         }
634
635                         type = TypeManager.GetPointerType (Expr.Type);
636                         eclass = ExprClass.Value;
637                         return this;
638                 }
639
640                 Expression ResolvePrimitivePredefinedType (Expression expr)
641                 {
642                         expr = DoNumericPromotion (Oper, expr);
643                         Type expr_type = expr.Type;
644                         Type[] predefined = predefined_operators [(int) Oper];
645                         foreach (Type t in predefined) {
646                                 if (t == expr_type)
647                                         return expr;
648                         }
649                         return null;
650                 }
651
652                 //
653                 // Perform user-operator overload resolution
654                 //
655                 protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
656                 {
657                         CSharp.Operator.OpType op_type;
658                         switch (Oper) {
659                         case Operator.LogicalNot:
660                                 op_type = CSharp.Operator.OpType.LogicalNot; break;
661                         case Operator.OnesComplement:
662                                 op_type = CSharp.Operator.OpType.OnesComplement; break;
663                         case Operator.UnaryNegation:
664                                 op_type = CSharp.Operator.OpType.UnaryNegation; break;
665                         case Operator.UnaryPlus:
666                                 op_type = CSharp.Operator.OpType.UnaryPlus; break;
667                         default:
668                                 throw new InternalErrorException (Oper.ToString ());
669                         }
670
671                         string op_name = CSharp.Operator.GetMetadataName (op_type);
672                         MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
673                         if (user_op == null)
674                                 return null;
675
676                         ArrayList args = new ArrayList (1);
677                         args.Add (new Argument (expr));
678                         user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
679
680                         if (user_op == null)
681                                 return null;
682
683                         Expr = ((Argument) args [0]).Expr;
684                         return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
685                 }
686
687                 //
688                 // Unary user type overload resolution
689                 //
690                 Expression ResolveUserType (EmitContext ec, Expression expr)
691                 {
692                         Expression best_expr = ResolveUserOperator (ec, expr);
693                         if (best_expr != null)
694                                 return best_expr;
695
696                         Type[] predefined = predefined_operators [(int) Oper];
697                         foreach (Type t in predefined) {
698                                 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
699                                 if (oper_expr == null)
700                                         continue;
701
702                                 //
703                                 // decimal type is predefined but has user-operators
704                                 //
705                                 if (oper_expr.Type == TypeManager.decimal_type)
706                                         oper_expr = ResolveUserType (ec, oper_expr);
707                                 else
708                                         oper_expr = ResolvePrimitivePredefinedType (oper_expr);
709
710                                 if (oper_expr == null)
711                                         continue;
712
713                                 if (best_expr == null) {
714                                         best_expr = oper_expr;
715                                         continue;
716                                 }
717
718                                 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
719                                 if (result == 0) {
720                                         Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
721                                                 OperName (Oper), TypeManager.CSharpName (expr.Type));
722                                         break;
723                                 }
724
725                                 if (result == 2)
726                                         best_expr = oper_expr;
727                         }
728                         
729                         if (best_expr == null)
730                                 return null;
731                         
732                         //
733                         // HACK: Decimal user-operator is included in standard operators
734                         //
735                         if (best_expr.Type == TypeManager.decimal_type)
736                                 return best_expr;                       
737
738                         Expr = best_expr;
739                         type = best_expr.Type;
740                         return this;                    
741                 }
742
743                 protected override void CloneTo (CloneContext clonectx, Expression t)
744                 {
745                         Unary target = (Unary) t;
746
747                         target.Expr = Expr.Clone (clonectx);
748                 }
749         }
750
751         //
752         // Unary operators are turned into Indirection expressions
753         // after semantic analysis (this is so we can take the address
754         // of an indirection).
755         //
756         public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
757                 Expression expr;
758                 LocalTemporary temporary;
759                 bool prepared;
760                 
761                 public Indirection (Expression expr, Location l)
762                 {
763                         this.expr = expr;
764                         loc = l;
765                 }
766
767                 public override Expression CreateExpressionTree (EmitContext ec)
768                 {
769                         Error_PointerInsideExpressionTree ();
770                         return null;
771                 }
772                 
773                 protected override void CloneTo (CloneContext clonectx, Expression t)
774                 {
775                         Indirection target = (Indirection) t;
776                         target.expr = expr.Clone (clonectx);
777                 }               
778                 
779                 public override void Emit (EmitContext ec)
780                 {
781                         if (!prepared)
782                                 expr.Emit (ec);
783                         
784                         LoadFromPtr (ec.ig, Type);
785                 }
786
787                 public void Emit (EmitContext ec, bool leave_copy)
788                 {
789                         Emit (ec);
790                         if (leave_copy) {
791                                 ec.ig.Emit (OpCodes.Dup);
792                                 temporary = new LocalTemporary (expr.Type);
793                                 temporary.Store (ec);
794                         }
795                 }
796                 
797                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
798                 {
799                         prepared = prepare_for_load;
800                         
801                         expr.Emit (ec);
802
803                         if (prepare_for_load)
804                                 ec.ig.Emit (OpCodes.Dup);
805                         
806                         source.Emit (ec);
807                         if (leave_copy) {
808                                 ec.ig.Emit (OpCodes.Dup);
809                                 temporary = new LocalTemporary (expr.Type);
810                                 temporary.Store (ec);
811                         }
812                         
813                         StoreFromPtr (ec.ig, type);
814                         
815                         if (temporary != null) {
816                                 temporary.Emit (ec);
817                                 temporary.Release (ec);
818                         }
819                 }
820                 
821                 public void AddressOf (EmitContext ec, AddressOp Mode)
822                 {
823                         expr.Emit (ec);
824                 }
825
826                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
827                 {
828                         return DoResolve (ec);
829                 }
830
831                 public override Expression DoResolve (EmitContext ec)
832                 {
833                         expr = expr.Resolve (ec);
834                         if (expr == null)
835                                 return null;
836
837                         if (!ec.InUnsafe)
838                                 UnsafeError (loc);
839
840                         if (!expr.Type.IsPointer) {
841                                 Error (193, "The * or -> operator must be applied to a pointer");
842                                 return null;
843                         }
844
845                         if (expr.Type == TypeManager.void_ptr_type) {
846                                 Error (242, "The operation in question is undefined on void pointers");
847                                 return null;
848                         }
849
850                         type = TypeManager.GetElementType (expr.Type);
851                         eclass = ExprClass.Variable;
852                         return this;
853                 }
854
855                 public bool IsFixed {
856                         get { return true; }
857                 }
858
859                 public override string ToString ()
860                 {
861                         return "*(" + expr + ")";
862                 }
863         }
864         
865         /// <summary>
866         ///   Unary Mutator expressions (pre and post ++ and --)
867         /// </summary>
868         ///
869         /// <remarks>
870         ///   UnaryMutator implements ++ and -- expressions.   It derives from
871         ///   ExpressionStatement becuase the pre/post increment/decrement
872         ///   operators can be used in a statement context.
873         ///
874         /// FIXME: Idea, we could split this up in two classes, one simpler
875         /// for the common case, and one with the extra fields for more complex
876         /// classes (indexers require temporary access;  overloaded require method)
877         ///
878         /// </remarks>
879         public class UnaryMutator : ExpressionStatement {
880                 [Flags]
881                 public enum Mode : byte {
882                         IsIncrement    = 0,
883                         IsDecrement    = 1,
884                         IsPre          = 0,
885                         IsPost         = 2,
886                         
887                         PreIncrement   = 0,
888                         PreDecrement   = IsDecrement,
889                         PostIncrement  = IsPost,
890                         PostDecrement  = IsPost | IsDecrement
891                 }
892
893                 Mode mode;
894                 bool is_expr = false;
895                 bool recurse = false;
896
897                 Expression expr;
898
899                 //
900                 // This is expensive for the simplest case.
901                 //
902                 UserOperatorCall method;
903
904                 public UnaryMutator (Mode m, Expression e, Location l)
905                 {
906                         mode = m;
907                         loc = l;
908                         expr = e;
909                 }
910
911                 static string OperName (Mode mode)
912                 {
913                         return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
914                                 "++" : "--";
915                 }
916
917                 /// <summary>
918                 ///   Returns whether an object of type `t' can be incremented
919                 ///   or decremented with add/sub (ie, basically whether we can
920                 ///   use pre-post incr-decr operations on it, but it is not a
921                 ///   System.Decimal, which we require operator overloading to catch)
922                 /// </summary>
923                 static bool IsIncrementableNumber (Type t)
924                 {
925                         return (t == TypeManager.sbyte_type) ||
926                                 (t == TypeManager.byte_type) ||
927                                 (t == TypeManager.short_type) ||
928                                 (t == TypeManager.ushort_type) ||
929                                 (t == TypeManager.int32_type) ||
930                                 (t == TypeManager.uint32_type) ||
931                                 (t == TypeManager.int64_type) ||
932                                 (t == TypeManager.uint64_type) ||
933                                 (t == TypeManager.char_type) ||
934                                 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
935                                 (t == TypeManager.float_type) ||
936                                 (t == TypeManager.double_type) ||
937                                 (t.IsPointer && t != TypeManager.void_ptr_type);
938                 }
939
940                 Expression ResolveOperator (EmitContext ec)
941                 {
942                         type = expr.Type;
943
944                         //
945                         // Step 1: Perform Operator Overload location
946                         //
947                         MethodGroupExpr mg;
948                         string op_name;
949                         
950                         if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
951                                 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
952                         else
953                                 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
954
955                         mg = MemberLookup (ec.ContainerType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
956
957                         if (mg != null) {
958                                 ArrayList args = new ArrayList (1);
959                                 args.Add (new Argument (expr, Argument.AType.Expression));
960                                 mg = mg.OverloadResolve (ec, ref args, false, loc);
961                                 if (mg == null)
962                                         return null;
963
964                                 method = new UserOperatorCall (mg, args, null, loc);
965                                 Convert.ImplicitConversionRequired (ec, method, type, loc);
966                                 return this;
967                         }
968
969                         if (!IsIncrementableNumber (type)) {
970                                 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
971                                            TypeManager.CSharpName (type) + "'");
972                                 return null;
973                         }
974
975                         //
976                         // The operand of the prefix/postfix increment decrement operators
977                         // should be an expression that is classified as a variable,
978                         // a property access or an indexer access
979                         //
980                         if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
981                                 expr = expr.ResolveLValue (ec, expr, Location);
982                         } else {
983                                 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
984                         }
985
986                         return this;
987                 }
988
989                 public override Expression CreateExpressionTree (EmitContext ec)
990                 {
991                         return new SimpleAssign (this, this).CreateExpressionTree (ec);
992                 }
993
994                 public override Expression DoResolve (EmitContext ec)
995                 {
996                         expr = expr.Resolve (ec);
997                         
998                         if (expr == null)
999                                 return null;
1000
1001                         eclass = ExprClass.Value;
1002
1003 #if GMCS_SOURCE
1004                         if (TypeManager.IsNullableValueType (expr.Type))
1005                                 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1006 #endif
1007
1008                         return ResolveOperator (ec);
1009                 }
1010
1011                 //
1012                 // Loads the proper "1" into the stack based on the type, then it emits the
1013                 // opcode for the operation requested
1014                 //
1015                 void LoadOneAndEmitOp (EmitContext ec, Type t)
1016                 {
1017                         //
1018                         // Measure if getting the typecode and using that is more/less efficient
1019                         // that comparing types.  t.GetTypeCode() is an internal call.
1020                         //
1021                         ILGenerator ig = ec.ig;
1022                                                      
1023                         if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1024                                 LongConstant.EmitLong (ig, 1);
1025                         else if (t == TypeManager.double_type)
1026                                 ig.Emit (OpCodes.Ldc_R8, 1.0);
1027                         else if (t == TypeManager.float_type)
1028                                 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1029                         else if (t.IsPointer){
1030                                 Type et = TypeManager.GetElementType (t);
1031                                 int n = GetTypeSize (et);
1032                                 
1033                                 if (n == 0)
1034                                         ig.Emit (OpCodes.Sizeof, et);
1035                                 else {
1036                                         IntConstant.EmitInt (ig, n);
1037                                         ig.Emit (OpCodes.Conv_I);
1038                                 }
1039                         } else 
1040                                 ig.Emit (OpCodes.Ldc_I4_1);
1041
1042                         //
1043                         // Now emit the operation
1044                         //
1045
1046                         Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1047                         Binary.EmitOperatorOpcode (ec, op, t);
1048
1049                         if (t == TypeManager.sbyte_type){
1050                                 if (ec.CheckState)
1051                                         ig.Emit (OpCodes.Conv_Ovf_I1);
1052                                 else
1053                                         ig.Emit (OpCodes.Conv_I1);
1054                         } else if (t == TypeManager.byte_type){
1055                                 if (ec.CheckState)
1056                                         ig.Emit (OpCodes.Conv_Ovf_U1);
1057                                 else
1058                                         ig.Emit (OpCodes.Conv_U1);
1059                         } else if (t == TypeManager.short_type){
1060                                 if (ec.CheckState)
1061                                         ig.Emit (OpCodes.Conv_Ovf_I2);
1062                                 else
1063                                         ig.Emit (OpCodes.Conv_I2);
1064                         } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1065                                 if (ec.CheckState)
1066                                         ig.Emit (OpCodes.Conv_Ovf_U2);
1067                                 else
1068                                         ig.Emit (OpCodes.Conv_U2);
1069                         }
1070                         
1071                 }
1072
1073                 void EmitCode (EmitContext ec, bool is_expr)
1074                 {
1075                         recurse = true;
1076                         this.is_expr = is_expr;
1077                         ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1078                 }
1079
1080                 public override void Emit (EmitContext ec)
1081                 {
1082                         //
1083                         // We use recurse to allow ourselfs to be the source
1084                         // of an assignment. This little hack prevents us from
1085                         // having to allocate another expression
1086                         //
1087                         if (recurse) {
1088                                 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1089                                 if (method == null)
1090                                         LoadOneAndEmitOp (ec, expr.Type);
1091                                 else
1092                                         ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1093                                 recurse = false;
1094                                 return;
1095                         }
1096
1097                         EmitCode (ec, true);
1098                 }
1099
1100                 public override void EmitStatement (EmitContext ec)
1101                 {
1102                         EmitCode (ec, false);
1103                 }
1104
1105                 protected override void CloneTo (CloneContext clonectx, Expression t)
1106                 {
1107                         UnaryMutator target = (UnaryMutator) t;
1108
1109                         target.expr = expr.Clone (clonectx);
1110                 }
1111         }
1112
1113         /// <summary>
1114         ///   Base class for the `Is' and `As' classes. 
1115         /// </summary>
1116         ///
1117         /// <remarks>
1118         ///   FIXME: Split this in two, and we get to save the `Operator' Oper
1119         ///   size. 
1120         /// </remarks>
1121         public abstract class Probe : Expression {
1122                 public Expression ProbeType;
1123                 protected Expression expr;
1124                 protected TypeExpr probe_type_expr;
1125                 
1126                 public Probe (Expression expr, Expression probe_type, Location l)
1127                 {
1128                         ProbeType = probe_type;
1129                         loc = l;
1130                         this.expr = expr;
1131                 }
1132
1133                 public Expression Expr {
1134                         get {
1135                                 return expr;
1136                         }
1137                 }
1138
1139                 public override Expression DoResolve (EmitContext ec)
1140                 {
1141                         probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1142                         if (probe_type_expr == null)
1143                                 return null;
1144
1145                         expr = expr.Resolve (ec);
1146                         if (expr == null)
1147                                 return null;
1148
1149                         if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1150                                 Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1151                                         OperatorName);
1152                         }
1153                         
1154                         if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1155                                 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1156                                         OperatorName);
1157                                 return null;
1158                         }
1159
1160                         if (expr.Type == TypeManager.anonymous_method_type) {
1161                                 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1162                                         OperatorName);
1163                                 return null;
1164                         }
1165
1166                         return this;
1167                 }
1168
1169                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1170                 {
1171                         expr.MutateHoistedGenericType (storey);
1172                         probe_type_expr.MutateHoistedGenericType (storey);
1173                 }
1174
1175                 protected abstract string OperatorName { get; }
1176
1177                 protected override void CloneTo (CloneContext clonectx, Expression t)
1178                 {
1179                         Probe target = (Probe) t;
1180
1181                         target.expr = expr.Clone (clonectx);
1182                         target.ProbeType = ProbeType.Clone (clonectx);
1183                 }
1184
1185         }
1186
1187         /// <summary>
1188         ///   Implementation of the `is' operator.
1189         /// </summary>
1190         public class Is : Probe {
1191                 Nullable.Unwrap expr_unwrap;
1192
1193                 public Is (Expression expr, Expression probe_type, Location l)
1194                         : base (expr, probe_type, l)
1195                 {
1196                 }
1197
1198                 public override Expression CreateExpressionTree (EmitContext ec)
1199                 {
1200                         ArrayList args = new ArrayList (2);
1201                         args.Add (new Argument (expr.CreateExpressionTree (ec)));
1202                         args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1203                         return CreateExpressionFactoryCall ("TypeIs", args);
1204                 }
1205                 
1206                 public override void Emit (EmitContext ec)
1207                 {
1208                         ILGenerator ig = ec.ig;
1209                         if (expr_unwrap != null) {
1210                                 expr_unwrap.EmitCheck (ec);
1211                                 return;
1212                         }
1213
1214                         expr.Emit (ec);
1215                         ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1216                         ig.Emit (OpCodes.Ldnull);
1217                         ig.Emit (OpCodes.Cgt_Un);
1218                 }
1219
1220                 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1221                 {
1222                         ILGenerator ig = ec.ig;
1223                         if (expr_unwrap != null) {
1224                                 expr_unwrap.EmitCheck (ec);
1225                         } else {
1226                                 expr.Emit (ec);
1227                                 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1228                         }                       
1229                         ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1230                 }
1231                 
1232                 Expression CreateConstantResult (bool result)
1233                 {
1234                         if (result)
1235                                 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1236                                         TypeManager.CSharpName (probe_type_expr.Type));
1237                         else
1238                                 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1239                                         TypeManager.CSharpName (probe_type_expr.Type));
1240
1241                         return ReducedExpression.Create (new BoolConstant (result, loc), this);
1242                 }
1243
1244                 public override Expression DoResolve (EmitContext ec)
1245                 {
1246                         if (base.DoResolve (ec) == null)
1247                                 return null;
1248
1249                         Type d = expr.Type;
1250                         bool d_is_nullable = false;
1251
1252                         //
1253                         // If E is a method group or the null literal, or if the type of E is a reference
1254                         // type or a nullable type and the value of E is null, the result is false
1255                         //
1256                         if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1257                                 return CreateConstantResult (false);
1258
1259                         if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1260                                 d = TypeManager.GetTypeArguments (d) [0];
1261                                 d_is_nullable = true;
1262                         }
1263
1264                         type = TypeManager.bool_type;
1265                         eclass = ExprClass.Value;
1266                         Type t = probe_type_expr.Type;
1267                         bool t_is_nullable = false;
1268                         if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1269                                 t = TypeManager.GetTypeArguments (t) [0];
1270                                 t_is_nullable = true;
1271                         }
1272
1273                         if (t.IsValueType) {
1274                                 if (d == t) {
1275                                         //
1276                                         // D and T are the same value types but D can be null
1277                                         //
1278                                         if (d_is_nullable && !t_is_nullable) {
1279                                                 expr_unwrap = Nullable.Unwrap.Create (expr, ec);
1280                                                 return this;
1281                                         }
1282                                         
1283                                         //
1284                                         // The result is true if D and T are the same value types
1285                                         //
1286                                         return CreateConstantResult (true);
1287                                 }
1288
1289                                 if (TypeManager.IsGenericParameter (d))
1290                                         return ResolveGenericParameter (t, d);
1291
1292                                 //
1293                                 // An unboxing conversion exists
1294                                 //
1295                                 if (Convert.ExplicitReferenceConversionExists (d, t))
1296                                         return this;
1297                         } else {
1298                                 if (TypeManager.IsGenericParameter (t))
1299                                         return ResolveGenericParameter (d, t);
1300
1301                                 if (d.IsValueType) {
1302                                         bool temp;
1303                                         if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1304                                                 return CreateConstantResult (true);
1305                                 } else {
1306                                         if (TypeManager.IsGenericParameter (d))
1307                                                 return ResolveGenericParameter (t, d);
1308
1309                                         if (TypeManager.ContainsGenericParameters (d))
1310                                                 return this;
1311
1312                                         if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1313                                                 Convert.ExplicitReferenceConversionExists (d, t)) {
1314                                                 return this;
1315                                         }
1316                                 }
1317                         }
1318
1319                         return CreateConstantResult (false);
1320                 }
1321
1322                 Expression ResolveGenericParameter (Type d, Type t)
1323                 {
1324 #if GMCS_SOURCE
1325                         GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1326                         if (constraints != null) {
1327                                 if (constraints.IsReferenceType && d.IsValueType)
1328                                         return CreateConstantResult (false);
1329
1330                                 if (constraints.IsValueType && !d.IsValueType)
1331                                         return CreateConstantResult (TypeManager.IsEqual (d, t));
1332                         }
1333
1334                         if (!TypeManager.IsReferenceType (expr.Type))
1335                                 expr = new BoxedCast (expr, d);
1336
1337                         return this;
1338 #else
1339                         return null;
1340 #endif
1341                 }
1342                 
1343                 protected override string OperatorName {
1344                         get { return "is"; }
1345                 }
1346         }
1347
1348         /// <summary>
1349         ///   Implementation of the `as' operator.
1350         /// </summary>
1351         public class As : Probe {
1352                 bool do_isinst;
1353                 Expression resolved_type;
1354                 
1355                 public As (Expression expr, Expression probe_type, Location l)
1356                         : base (expr, probe_type, l)
1357                 {
1358                 }
1359
1360                 public override Expression CreateExpressionTree (EmitContext ec)
1361                 {
1362                         ArrayList args = new ArrayList (2);
1363                         args.Add (new Argument (expr.CreateExpressionTree (ec)));
1364                         args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1365                         return CreateExpressionFactoryCall ("TypeAs", args);
1366                 }
1367
1368                 public override void Emit (EmitContext ec)
1369                 {
1370                         ILGenerator ig = ec.ig;
1371
1372                         expr.Emit (ec);
1373
1374                         if (do_isinst)
1375                                 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1376
1377 #if GMCS_SOURCE
1378                         if (TypeManager.IsNullableType (type))
1379                                 ig.Emit (OpCodes.Unbox_Any, type);
1380 #endif
1381                 }
1382
1383                 public override Expression DoResolve (EmitContext ec)
1384                 {
1385                         if (resolved_type == null) {
1386                                 resolved_type = base.DoResolve (ec);
1387
1388                                 if (resolved_type == null)
1389                                         return null;
1390                         }
1391
1392                         type = probe_type_expr.Type;
1393                         eclass = ExprClass.Value;
1394                         Type etype = expr.Type;
1395
1396                         if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1397                                 if (probe_type_expr is TypeParameterExpr) {
1398                                         Report.Error (413, loc,
1399                                                 "The `as' operator cannot be used with a non-reference type parameter `{0}'",
1400                                                 probe_type_expr.GetSignatureForError ());
1401                                 } else {
1402                                         Report.Error (77, loc,
1403                                                 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1404                                                 TypeManager.CSharpName (type));
1405                                 }
1406                                 return null;
1407                         }
1408
1409                         if (expr.IsNull && TypeManager.IsNullableType (type)) {
1410                                 return Nullable.LiftedNull.CreateFromExpression (this);
1411                         }
1412                         
1413                         Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1414                         if (e != null){
1415                                 expr = e;
1416                                 do_isinst = false;
1417                                 return this;
1418                         }
1419
1420                         if (Convert.ExplicitReferenceConversionExists (etype, type)){
1421                                 if (TypeManager.IsGenericParameter (etype))
1422                                         expr = new BoxedCast (expr, etype);
1423
1424                                 do_isinst = true;
1425                                 return this;
1426                         }
1427
1428                         if (TypeManager.ContainsGenericParameters (etype) ||
1429                             TypeManager.ContainsGenericParameters (type)) {
1430                                 expr = new BoxedCast (expr, etype);
1431                                 do_isinst = true;
1432                                 return this;
1433                         }
1434
1435                         Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1436                                 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1437
1438                         return null;
1439                 }
1440
1441                 protected override string OperatorName {
1442                         get { return "as"; }
1443                 }
1444         
1445                 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1446                 {
1447                         return expr.GetAttributableValue (ec, value_type, out value);
1448                 }
1449         }
1450         
1451         /// <summary>
1452         ///   This represents a typecast in the source language.
1453         ///
1454         ///   FIXME: Cast expressions have an unusual set of parsing
1455         ///   rules, we need to figure those out.
1456         /// </summary>
1457         public class Cast : Expression {
1458                 Expression target_type;
1459                 Expression expr;
1460                         
1461                 public Cast (Expression cast_type, Expression expr)
1462                         : this (cast_type, expr, cast_type.Location)
1463                 {
1464                 }
1465
1466                 public Cast (Expression cast_type, Expression expr, Location loc)
1467                 {
1468                         this.target_type = cast_type;
1469                         this.expr = expr;
1470                         this.loc = loc;
1471                 }
1472
1473                 public Expression TargetType {
1474                         get { return target_type; }
1475                 }
1476
1477                 public Expression Expr {
1478                         get { return expr; }
1479                 }
1480
1481                 public override Expression CreateExpressionTree (EmitContext ec)
1482                 {
1483                         throw new NotSupportedException ("ET");
1484                 }
1485
1486                 public override Expression DoResolve (EmitContext ec)
1487                 {
1488                         expr = expr.Resolve (ec);
1489                         if (expr == null)
1490                                 return null;
1491
1492                         TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1493                         if (target == null)
1494                                 return null;
1495
1496                         type = target.Type;
1497
1498                         if (type.IsAbstract && type.IsSealed) {
1499                                 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1500                                 return null;
1501                         }
1502
1503                         eclass = ExprClass.Value;
1504
1505                         Constant c = expr as Constant;
1506                         if (c != null) {
1507                                 c = c.TryReduce (ec, type, loc);
1508                                 if (c != null)
1509                                         return c;
1510                         }
1511
1512                         if (type.IsPointer && !ec.InUnsafe) {
1513                                 UnsafeError (loc);
1514                                 return null;
1515                         }
1516                         expr = Convert.ExplicitConversion (ec, expr, type, loc);
1517                         return expr;
1518                 }
1519                 
1520                 public override void Emit (EmitContext ec)
1521                 {
1522                         throw new Exception ("Should not happen");
1523                 }
1524
1525                 protected override void CloneTo (CloneContext clonectx, Expression t)
1526                 {
1527                         Cast target = (Cast) t;
1528
1529                         target.target_type = target_type.Clone (clonectx);
1530                         target.expr = expr.Clone (clonectx);
1531                 }
1532         }
1533         
1534         //
1535         // C# 2.0 Default value expression
1536         //
1537         public class DefaultValueExpression : Expression
1538         {
1539                 Expression expr;
1540
1541                 public DefaultValueExpression (Expression expr, Location loc)
1542                 {
1543                         this.expr = expr;
1544                         this.loc = loc;
1545                 }
1546
1547                 public override Expression CreateExpressionTree (EmitContext ec)
1548                 {
1549                         ArrayList args = new ArrayList (2);
1550                         args.Add (new Argument (this));
1551                         args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1552                         return CreateExpressionFactoryCall ("Constant", args);
1553                 }
1554
1555                 public override Expression DoResolve (EmitContext ec)
1556                 {
1557                         TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1558                         if (texpr == null)
1559                                 return null;
1560
1561                         type = texpr.Type;
1562
1563                         if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1564                                 Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1565                         }
1566
1567                         if (type.IsPointer)
1568                                 return new NullLiteral (Location).ConvertImplicitly (type);
1569
1570                         if (TypeManager.IsReferenceType (type)) {
1571                                 return new EmptyConstantCast (new NullLiteral (Location), type);
1572
1573                                 // TODO: ET needs
1574                                 // return ReducedExpression.Create (new NullLiteral (Location), this);
1575                         }
1576
1577                         Constant c = New.Constantify (type);
1578                         if (c != null)
1579                                 return c;
1580
1581                         eclass = ExprClass.Variable;
1582                         return this;
1583                 }
1584
1585                 public override void Emit (EmitContext ec)
1586                 {
1587                         LocalTemporary temp_storage = new LocalTemporary(type);
1588
1589                         temp_storage.AddressOf(ec, AddressOp.LoadStore);
1590                         ec.ig.Emit(OpCodes.Initobj, type);
1591                         temp_storage.Emit(ec);
1592                 }
1593
1594                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1595                 {
1596                         type = storey.MutateType (type);
1597                 }
1598                 
1599                 protected override void CloneTo (CloneContext clonectx, Expression t)
1600                 {
1601                         DefaultValueExpression target = (DefaultValueExpression) t;
1602                         
1603                         target.expr = expr.Clone (clonectx);
1604                 }
1605         }
1606
1607         /// <summary>
1608         ///   Binary operators
1609         /// </summary>
1610         public class Binary : Expression {
1611
1612                 protected class PredefinedOperator {
1613                         protected readonly Type left;
1614                         protected readonly Type right;
1615                         public readonly Operator OperatorsMask;
1616                         public Type ReturnType;
1617
1618                         public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1619                                 : this (ltype, rtype, op_mask, ltype)
1620                         {
1621                         }
1622
1623                         public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1624                                 : this (type, type, op_mask, return_type)
1625                         {
1626                         }
1627
1628                         public PredefinedOperator (Type type, Operator op_mask)
1629                                 : this (type, type, op_mask, type)
1630                         {
1631                         }
1632
1633                         public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1634                         {
1635                                 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1636                                         throw new InternalErrorException ("Only masked values can be used");
1637
1638                                 this.left = ltype;
1639                                 this.right = rtype;
1640                                 this.OperatorsMask = op_mask;
1641                                 this.ReturnType = return_type;
1642                         }
1643
1644                         public virtual Expression ConvertResult (EmitContext ec, Binary b)
1645                         {
1646                                 b.type = ReturnType;
1647
1648                                 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1649                                 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1650
1651                                 //
1652                                 // A user operators does not support multiple user conversions, but decimal type
1653                                 // is considered to be predefined type therefore we apply predefined operators rules
1654                                 // and then look for decimal user-operator implementation
1655                                 //
1656                                 if (left == TypeManager.decimal_type)
1657                                         return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1658
1659                                 return b;
1660                         }
1661
1662                         public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1663                         {
1664                                 //
1665                                 // We are dealing with primitive types only
1666                                 //
1667                                 return left == ltype && ltype == rtype;
1668                         }
1669
1670                         public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1671                         {
1672                                 if (TypeManager.IsEqual (left, lexpr.Type) &&
1673                                         TypeManager.IsEqual (right, rexpr.Type))
1674                                         return true;
1675
1676                                 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1677                                         Convert.ImplicitConversionExists (ec, rexpr, right);
1678                         }
1679
1680                         public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1681                         {
1682                                 int result = 0;
1683                                 if (left != null && best_operator.left != null) {
1684                                         result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1685                                 }
1686
1687                                 //
1688                                 // When second arguments are same as the first one, the result is same
1689                                 //
1690                                 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1691                                         result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1692                                 }
1693
1694                                 if (result == 0 || result > 2)
1695                                         return null;
1696
1697                                 return result == 1 ? best_operator : this;
1698                         }
1699                 }
1700
1701                 class PredefinedStringOperator : PredefinedOperator {
1702                         public PredefinedStringOperator (Type type, Operator op_mask)
1703                                 : base (type, op_mask, type)
1704                         {
1705                                 ReturnType = TypeManager.string_type;
1706                         }
1707
1708                         public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1709                                 : base (ltype, rtype, op_mask)
1710                         {
1711                                 ReturnType = TypeManager.string_type;
1712                         }
1713
1714                         public override Expression ConvertResult (EmitContext ec, Binary b)
1715                         {
1716                                 //
1717                                 // Use original expression for nullable arguments
1718                                 //
1719                                 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1720                                 if (unwrap != null)
1721                                         b.left = unwrap.Original;
1722
1723                                 unwrap = b.right as Nullable.Unwrap;
1724                                 if (unwrap != null)
1725                                         b.right = unwrap.Original;
1726
1727                                 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1728                                 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1729
1730                                 //
1731                                 // Start a new concat expression using converted expression
1732                                 //
1733                                 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1734                         }
1735                 }
1736
1737                 class PredefinedShiftOperator : PredefinedOperator {
1738                         public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1739                                 base (ltype, TypeManager.int32_type, op_mask)
1740                         {
1741                         }
1742
1743                         public override Expression ConvertResult (EmitContext ec, Binary b)
1744                         {
1745                                 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1746
1747                                 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1748
1749                                 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1750
1751                                 //
1752                                 // b = b.left >> b.right & (0x1f|0x3f)
1753                                 //
1754                                 b.right = new Binary (Operator.BitwiseAnd,
1755                                         b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1756
1757                                 //
1758                                 // Expression tree representation does not use & mask
1759                                 //
1760                                 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1761                                 b.type = ReturnType;
1762                                 return b;
1763                         }
1764                 }
1765
1766                 class PredefinedPointerOperator : PredefinedOperator {
1767                         public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1768                                 : base (ltype, rtype, op_mask)
1769                         {
1770                         }
1771
1772                         public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1773                                 : base (ltype, rtype, op_mask, retType)
1774                         {
1775                         }
1776
1777                         public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1778                                 : base (type, op_mask, return_type)
1779                         {
1780                         }
1781
1782                         public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1783                         {
1784                                 if (left == null) {
1785                                         if (!lexpr.Type.IsPointer)
1786                                                 return false;
1787                                 } else {
1788                                         if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1789                                                 return false;
1790                                 }
1791
1792                                 if (right == null) {
1793                                         if (!rexpr.Type.IsPointer)
1794                                                 return false;
1795                                 } else {
1796                                         if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1797                                                 return false;
1798                                 }
1799
1800                                 return true;
1801                         }
1802
1803                         public override Expression ConvertResult (EmitContext ec, Binary b)
1804                         {
1805                                 if (left != null) {
1806                                         b.left = EmptyCast.Create (b.left, left);
1807                                 } else if (right != null) {
1808                                         b.right = EmptyCast.Create (b.right, right);
1809                                 }
1810
1811                                 Type r_type = ReturnType;
1812                                 if (r_type == null) {
1813                                         if (left == null)
1814                                                 r_type = b.left.Type;
1815                                         else 
1816                                                 r_type = b.right.Type;
1817                                 }
1818
1819                                 return new PointerArithmetic (b.oper, b.left, b.right, r_type, b.loc).Resolve (ec);
1820                         }
1821                 }
1822
1823                 [Flags]
1824                 public enum Operator {
1825                         Multiply        = 0 | ArithmeticMask,
1826                         Division        = 1 | ArithmeticMask,
1827                         Modulus         = 2 | ArithmeticMask,
1828                         Addition        = 3 | ArithmeticMask | AdditionMask,
1829                         Subtraction = 4 | ArithmeticMask | SubtractionMask,
1830
1831                         LeftShift       = 5 | ShiftMask,
1832                         RightShift      = 6 | ShiftMask,
1833
1834                         LessThan        = 7 | ComparisonMask | RelationalMask,
1835                         GreaterThan     = 8 | ComparisonMask | RelationalMask,
1836                         LessThanOrEqual         = 9 | ComparisonMask | RelationalMask,
1837                         GreaterThanOrEqual      = 10 | ComparisonMask | RelationalMask,
1838                         Equality        = 11 | ComparisonMask | EqualityMask,
1839                         Inequality      = 12 | ComparisonMask | EqualityMask,
1840
1841                         BitwiseAnd      = 13 | BitwiseMask,
1842                         ExclusiveOr     = 14 | BitwiseMask,
1843                         BitwiseOr       = 15 | BitwiseMask,
1844
1845                         LogicalAnd      = 16 | LogicalMask,
1846                         LogicalOr       = 17 | LogicalMask,
1847
1848                         //
1849                         // Operator masks
1850                         //
1851                         ValuesOnlyMask  = ArithmeticMask - 1,
1852                         ArithmeticMask  = 1 << 5,
1853                         ShiftMask               = 1 << 6,
1854                         ComparisonMask  = 1 << 7,
1855                         EqualityMask    = 1 << 8,
1856                         BitwiseMask             = 1 << 9,
1857                         LogicalMask             = 1 << 10,
1858                         AdditionMask    = 1 << 11,
1859                         SubtractionMask = 1 << 12,
1860                         RelationalMask  = 1 << 13
1861                 }
1862
1863                 readonly Operator oper;
1864                 protected Expression left, right;
1865                 readonly bool is_compound;
1866                 Expression enum_conversion;
1867
1868                 static PredefinedOperator [] standard_operators;
1869                 static PredefinedOperator [] pointer_operators;
1870                 
1871                 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1872                         : this (oper, left, right)
1873                 {
1874                         this.is_compound = isCompound;
1875                 }
1876
1877                 public Binary (Operator oper, Expression left, Expression right)
1878                 {
1879                         this.oper = oper;
1880                         this.left = left;
1881                         this.right = right;
1882                         this.loc = left.Location;
1883                 }
1884
1885                 public Operator Oper {
1886                         get {
1887                                 return oper;
1888                         }
1889                 }
1890                 
1891                 /// <summary>
1892                 ///   Returns a stringified representation of the Operator
1893                 /// </summary>
1894                 string OperName (Operator oper)
1895                 {
1896                         string s;
1897                         switch (oper){
1898                         case Operator.Multiply:
1899                                 s = "*";
1900                                 break;
1901                         case Operator.Division:
1902                                 s = "/";
1903                                 break;
1904                         case Operator.Modulus:
1905                                 s = "%";
1906                                 break;
1907                         case Operator.Addition:
1908                                 s = "+";
1909                                 break;
1910                         case Operator.Subtraction:
1911                                 s = "-";
1912                                 break;
1913                         case Operator.LeftShift:
1914                                 s = "<<";
1915                                 break;
1916                         case Operator.RightShift:
1917                                 s = ">>";
1918                                 break;
1919                         case Operator.LessThan:
1920                                 s = "<";
1921                                 break;
1922                         case Operator.GreaterThan:
1923                                 s = ">";
1924                                 break;
1925                         case Operator.LessThanOrEqual:
1926                                 s = "<=";
1927                                 break;
1928                         case Operator.GreaterThanOrEqual:
1929                                 s = ">=";
1930                                 break;
1931                         case Operator.Equality:
1932                                 s = "==";
1933                                 break;
1934                         case Operator.Inequality:
1935                                 s = "!=";
1936                                 break;
1937                         case Operator.BitwiseAnd:
1938                                 s = "&";
1939                                 break;
1940                         case Operator.BitwiseOr:
1941                                 s = "|";
1942                                 break;
1943                         case Operator.ExclusiveOr:
1944                                 s = "^";
1945                                 break;
1946                         case Operator.LogicalOr:
1947                                 s = "||";
1948                                 break;
1949                         case Operator.LogicalAnd:
1950                                 s = "&&";
1951                                 break;
1952                         default:
1953                                 s = oper.ToString ();
1954                                 break;
1955                         }
1956
1957                         if (is_compound)
1958                                 return s + "=";
1959
1960                         return s;
1961                 }
1962
1963                 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1964                 {
1965                         new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1966                 }
1967
1968                 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
1969                 {
1970                         string l, r;
1971                         // TODO: This should be handled as Type of method group in CSharpName
1972                         if (left.eclass == ExprClass.MethodGroup)
1973                                 l = left.ExprClassName;
1974                         else
1975                                 l = TypeManager.CSharpName (left.Type);
1976
1977                         if (right.eclass == ExprClass.MethodGroup)
1978                                 r = right.ExprClassName;
1979                         else
1980                                 r = TypeManager.CSharpName (right.Type);
1981
1982                         Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1983                                 oper, l, r);
1984                 }
1985                 
1986                 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
1987                 {
1988                         Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
1989                 }
1990
1991                 static string GetOperatorMetadataName (Operator op)
1992                 {
1993                         CSharp.Operator.OpType op_type;
1994                         switch (op) {
1995                         case Operator.Addition:
1996                                 op_type = CSharp.Operator.OpType.Addition; break;
1997                         case Operator.BitwiseAnd:
1998                                 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
1999                         case Operator.BitwiseOr:
2000                                 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2001                         case Operator.Division:
2002                                 op_type = CSharp.Operator.OpType.Division; break;
2003                         case Operator.Equality:
2004                                 op_type = CSharp.Operator.OpType.Equality; break;
2005                         case Operator.ExclusiveOr:
2006                                 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2007                         case Operator.GreaterThan:
2008                                 op_type = CSharp.Operator.OpType.GreaterThan; break;
2009                         case Operator.GreaterThanOrEqual:
2010                                 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2011                         case Operator.Inequality:
2012                                 op_type = CSharp.Operator.OpType.Inequality; break;
2013                         case Operator.LeftShift:
2014                                 op_type = CSharp.Operator.OpType.LeftShift; break;
2015                         case Operator.LessThan:
2016                                 op_type = CSharp.Operator.OpType.LessThan; break;
2017                         case Operator.LessThanOrEqual:
2018                                 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2019                         case Operator.Modulus:
2020                                 op_type = CSharp.Operator.OpType.Modulus; break;
2021                         case Operator.Multiply:
2022                                 op_type = CSharp.Operator.OpType.Multiply; break;
2023                         case Operator.RightShift:
2024                                 op_type = CSharp.Operator.OpType.RightShift; break;
2025                         case Operator.Subtraction:
2026                                 op_type = CSharp.Operator.OpType.Subtraction; break;
2027                         default:
2028                                 throw new InternalErrorException (op.ToString ());
2029                         }
2030
2031                         return CSharp.Operator.GetMetadataName (op_type);
2032                 }
2033
2034                 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2035                 {
2036                         OpCode opcode;
2037                         ILGenerator ig = ec.ig;
2038
2039                         switch (oper){
2040                         case Operator.Multiply:
2041                                 if (ec.CheckState){
2042                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2043                                                 opcode = OpCodes.Mul_Ovf;
2044                                         else if (!IsFloat (l))
2045                                                 opcode = OpCodes.Mul_Ovf_Un;
2046                                         else
2047                                                 opcode = OpCodes.Mul;
2048                                 } else
2049                                         opcode = OpCodes.Mul;
2050                                 
2051                                 break;
2052                                 
2053                         case Operator.Division:
2054                                 if (IsUnsigned (l))
2055                                         opcode = OpCodes.Div_Un;
2056                                 else
2057                                         opcode = OpCodes.Div;
2058                                 break;
2059                                 
2060                         case Operator.Modulus:
2061                                 if (IsUnsigned (l))
2062                                         opcode = OpCodes.Rem_Un;
2063                                 else
2064                                         opcode = OpCodes.Rem;
2065                                 break;
2066
2067                         case Operator.Addition:
2068                                 if (ec.CheckState){
2069                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2070                                                 opcode = OpCodes.Add_Ovf;
2071                                         else if (!IsFloat (l))
2072                                                 opcode = OpCodes.Add_Ovf_Un;
2073                                         else
2074                                                 opcode = OpCodes.Add;
2075                                 } else
2076                                         opcode = OpCodes.Add;
2077                                 break;
2078
2079                         case Operator.Subtraction:
2080                                 if (ec.CheckState){
2081                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2082                                                 opcode = OpCodes.Sub_Ovf;
2083                                         else if (!IsFloat (l))
2084                                                 opcode = OpCodes.Sub_Ovf_Un;
2085                                         else
2086                                                 opcode = OpCodes.Sub;
2087                                 } else
2088                                         opcode = OpCodes.Sub;
2089                                 break;
2090
2091                         case Operator.RightShift:
2092                                 if (IsUnsigned (l))
2093                                         opcode = OpCodes.Shr_Un;
2094                                 else
2095                                         opcode = OpCodes.Shr;
2096                                 break;
2097                                 
2098                         case Operator.LeftShift:
2099                                 opcode = OpCodes.Shl;
2100                                 break;
2101
2102                         case Operator.Equality:
2103                                 opcode = OpCodes.Ceq;
2104                                 break;
2105
2106                         case Operator.Inequality:
2107                                 ig.Emit (OpCodes.Ceq);
2108                                 ig.Emit (OpCodes.Ldc_I4_0);
2109                                 
2110                                 opcode = OpCodes.Ceq;
2111                                 break;
2112
2113                         case Operator.LessThan:
2114                                 if (IsUnsigned (l))
2115                                         opcode = OpCodes.Clt_Un;
2116                                 else
2117                                         opcode = OpCodes.Clt;
2118                                 break;
2119
2120                         case Operator.GreaterThan:
2121                                 if (IsUnsigned (l))
2122                                         opcode = OpCodes.Cgt_Un;
2123                                 else
2124                                         opcode = OpCodes.Cgt;
2125                                 break;
2126
2127                         case Operator.LessThanOrEqual:
2128                                 if (IsUnsigned (l) || IsFloat (l))
2129                                         ig.Emit (OpCodes.Cgt_Un);
2130                                 else
2131                                         ig.Emit (OpCodes.Cgt);
2132                                 ig.Emit (OpCodes.Ldc_I4_0);
2133                                 
2134                                 opcode = OpCodes.Ceq;
2135                                 break;
2136
2137                         case Operator.GreaterThanOrEqual:
2138                                 if (IsUnsigned (l) || IsFloat (l))
2139                                         ig.Emit (OpCodes.Clt_Un);
2140                                 else
2141                                         ig.Emit (OpCodes.Clt);
2142                                 
2143                                 ig.Emit (OpCodes.Ldc_I4_0);
2144                                 
2145                                 opcode = OpCodes.Ceq;
2146                                 break;
2147
2148                         case Operator.BitwiseOr:
2149                                 opcode = OpCodes.Or;
2150                                 break;
2151
2152                         case Operator.BitwiseAnd:
2153                                 opcode = OpCodes.And;
2154                                 break;
2155
2156                         case Operator.ExclusiveOr:
2157                                 opcode = OpCodes.Xor;
2158                                 break;
2159
2160                         default:
2161                                 throw new InternalErrorException (oper.ToString ());
2162                         }
2163
2164                         ig.Emit (opcode);
2165                 }
2166
2167                 static bool IsUnsigned (Type t)
2168                 {
2169                         if (t.IsPointer)
2170                                 return true;
2171
2172                         return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2173                                 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2174                 }
2175
2176                 static bool IsFloat (Type t)
2177                 {
2178                         return t == TypeManager.float_type || t == TypeManager.double_type;
2179                 }
2180
2181                 Expression ResolveOperator (EmitContext ec)
2182                 {
2183                         Type l = left.Type;
2184                         Type r = right.Type;
2185                         Expression expr;
2186                         bool primitives_only = false;
2187
2188                         if (standard_operators == null)
2189                                 CreateStandardOperatorsTable ();
2190
2191                         //
2192                         // Handles predefined primitive types
2193                         //
2194                         if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2195                                 if ((oper & Operator.ShiftMask) == 0) {
2196                                         if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2197                                                 return null;
2198
2199                                         primitives_only = true;
2200                                 }
2201                         } else {
2202                                 // Pointers
2203                                 if (l.IsPointer || r.IsPointer)
2204                                         return ResolveOperatorPointer (ec, l, r);
2205
2206                                 // Enums
2207                                 bool lenum = TypeManager.IsEnumType (l);
2208                                 bool renum = TypeManager.IsEnumType (r);
2209                                 if (lenum || renum) {
2210                                         expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2211
2212                                         // TODO: Can this be ambiguous
2213                                         if (expr != null)
2214                                                 return expr;
2215                                 }
2216
2217                                 // Delegates
2218                                 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2219                                          (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2220                                                 
2221                                         expr = ResolveOperatorDelegate (ec, l, r);
2222
2223                                         // TODO: Can this be ambiguous
2224                                         if (expr != null)
2225                                                 return expr;
2226                                 }
2227
2228                                 // User operators
2229                                 expr = ResolveUserOperator (ec, l, r);
2230                                 if (expr != null)
2231                                         return expr;
2232
2233                                 // Predefined reference types equality
2234                                 if ((oper & Operator.EqualityMask) != 0) {
2235                                         expr = ResolveOperatorEqualityRerefence (ec, l, r);
2236                                         if (expr != null)
2237                                                 return expr;
2238                                 }
2239                         }
2240
2241                         return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2242                 }
2243
2244                 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2245                 // if 'left' is not an enumeration constant, create one from the type of 'right'
2246                 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2247                 {
2248                         switch (oper) {
2249                         case Operator.BitwiseOr:
2250                         case Operator.BitwiseAnd:
2251                         case Operator.ExclusiveOr:
2252                         case Operator.Equality:
2253                         case Operator.Inequality:
2254                         case Operator.LessThan:
2255                         case Operator.LessThanOrEqual:
2256                         case Operator.GreaterThan:
2257                         case Operator.GreaterThanOrEqual:
2258                                 if (TypeManager.IsEnumType (left.Type))
2259                                         return left;
2260                                 
2261                                 if (left.IsZeroInteger)
2262                                         return left.TryReduce (ec, right.Type, loc);
2263                                 
2264                                 break;
2265                                 
2266                         case Operator.Addition:
2267                         case Operator.Subtraction:
2268                                 return left;
2269                                 
2270                         case Operator.Multiply:
2271                         case Operator.Division:
2272                         case Operator.Modulus:
2273                         case Operator.LeftShift:
2274                         case Operator.RightShift:
2275                                 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2276                                         break;
2277                                 return left;
2278                         }
2279                         Error_OperatorCannotBeApplied (this.left, this.right);
2280                         return null;
2281                 }
2282
2283                 //
2284                 // The `|' operator used on types which were extended is dangerous
2285                 //
2286                 void CheckBitwiseOrOnSignExtended ()
2287                 {
2288                         OpcodeCast lcast = left as OpcodeCast;
2289                         if (lcast != null) {
2290                                 if (IsUnsigned (lcast.UnderlyingType))
2291                                         lcast = null;
2292                         }
2293
2294                         OpcodeCast rcast = right as OpcodeCast;
2295                         if (rcast != null) {
2296                                 if (IsUnsigned (rcast.UnderlyingType))
2297                                         rcast = null;
2298                         }
2299
2300                         if (lcast == null && rcast == null)
2301                                 return;
2302
2303                         // FIXME: consider constants
2304
2305                         Report.Warning (675, 3, loc,
2306                                 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2307                                 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2308                 }
2309
2310                 static void CreatePointerOperatorsTable ()
2311                 {
2312                         ArrayList temp = new ArrayList ();
2313
2314                         //
2315                         // Pointer arithmetic:
2316                         //
2317                         // T* operator + (T* x, int y);         T* operator - (T* x, int y);
2318                         // T* operator + (T* x, uint y);        T* operator - (T* x, uint y);
2319                         // T* operator + (T* x, long y);        T* operator - (T* x, long y);
2320                         // T* operator + (T* x, ulong y);       T* operator - (T* x, ulong y);
2321                         //
2322                         temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2323                         temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2324                         temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2325                         temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2326
2327                         //
2328                         // T* operator + (int y,   T* x);
2329                         // T* operator + (uint y,  T *x);
2330                         // T* operator + (long y,  T *x);
2331                         // T* operator + (ulong y, T *x);
2332                         //
2333                         temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2334                         temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2335                         temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2336                         temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2337
2338                         //
2339                         // long operator - (T* x, T *y)
2340                         //
2341                         temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2342
2343                         pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2344                 }
2345
2346                 static void CreateStandardOperatorsTable ()
2347                 {
2348                         ArrayList temp = new ArrayList ();
2349                         Type bool_type = TypeManager.bool_type;
2350
2351                         temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2352                         temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2353                         temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2354                         temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2355                         temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2356                         temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2357                         temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2358
2359                         temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2360                         temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2361                         temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2362                         temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2363                         temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2364                         temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2365                         temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2366
2367                         temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2368
2369                         temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2370                         temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2371                         temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2372
2373                         temp.Add (new PredefinedOperator (bool_type,
2374                                 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2375
2376                         temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2377                         temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2378                         temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2379                         temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2380
2381                         standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2382                 }
2383
2384                 //
2385                 // Rules used during binary numeric promotion
2386                 //
2387                 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2388                 {
2389                         Expression temp;
2390                         Type etype;
2391
2392                         Constant c = prim_expr as Constant;
2393                         if (c != null) {
2394                                 temp = c.ConvertImplicitly (type);
2395                                 if (temp != null) {
2396                                         prim_expr = temp;
2397                                         return true;
2398                                 }
2399                         }
2400
2401                         if (type == TypeManager.uint32_type) {
2402                                 etype = prim_expr.Type;
2403                                 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2404                                         type = TypeManager.int64_type;
2405
2406                                         if (type != second_expr.Type) {
2407                                                 c = second_expr as Constant;
2408                                                 if (c != null)
2409                                                         temp = c.ConvertImplicitly (type);
2410                                                 else
2411                                                         temp = Convert.ImplicitNumericConversion (second_expr, type);
2412                                                 if (temp == null)
2413                                                         return false;
2414                                                 second_expr = temp;
2415                                         }
2416                                 }
2417                         } else if (type == TypeManager.uint64_type) {
2418                                 //
2419                                 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2420                                 //
2421                                 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2422                                         type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2423                                         return false;
2424                         }
2425
2426                         temp = Convert.ImplicitNumericConversion (prim_expr, type);
2427                         if (temp == null)
2428                                 return false;
2429
2430                         prim_expr = temp;
2431                         return true;
2432                 }
2433
2434                 //
2435                 // 7.2.6.2 Binary numeric promotions
2436                 //
2437                 public bool DoBinaryOperatorPromotion (EmitContext ec)
2438                 {
2439                         Type ltype = left.Type;
2440                         Type rtype = right.Type;
2441                         Expression temp;
2442
2443                         foreach (Type t in ConstantFold.binary_promotions) {
2444                                 if (t == ltype)
2445                                         return t == rtype || DoNumericPromotion (ref right, ref left, t);
2446
2447                                 if (t == rtype)
2448                                         return t == ltype || DoNumericPromotion (ref left, ref right, t);
2449                         }
2450
2451                         Type int32 = TypeManager.int32_type;
2452                         if (ltype != int32) {
2453                                 Constant c = left as Constant;
2454                                 if (c != null)
2455                                         temp = c.ConvertImplicitly (int32);
2456                                 else
2457                                         temp = Convert.ImplicitNumericConversion (left, int32);
2458
2459                                 if (temp == null)
2460                                         return false;
2461                                 left = temp;
2462                         }
2463
2464                         if (rtype != int32) {
2465                                 Constant c = right as Constant;
2466                                 if (c != null)
2467                                         temp = c.ConvertImplicitly (int32);
2468                                 else
2469                                         temp = Convert.ImplicitNumericConversion (right, int32);
2470
2471                                 if (temp == null)
2472                                         return false;
2473                                 right = temp;
2474                         }
2475
2476                         return true;
2477                 }
2478
2479                 public override Expression DoResolve (EmitContext ec)
2480                 {
2481                         if (left == null)
2482                                 return null;
2483
2484                         if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2485                                 left = ((ParenthesizedExpression) left).Expr;
2486                                 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2487                                 if (left == null)
2488                                         return null;
2489
2490                                 if (left.eclass == ExprClass.Type) {
2491                                         Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2492                                         return null;
2493                                 }
2494                         } else
2495                                 left = left.Resolve (ec);
2496
2497                         if (left == null)
2498                                 return null;
2499
2500                         Constant lc = left as Constant;
2501
2502                         if (lc != null && lc.Type == TypeManager.bool_type &&
2503                                 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2504                                  (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2505
2506                                 // FIXME: resolve right expression as unreachable
2507                                 // right.Resolve (ec);
2508
2509                                 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2510                                 return left;
2511                         }
2512
2513                         right = right.Resolve (ec);
2514                         if (right == null)
2515                                 return null;
2516
2517                         eclass = ExprClass.Value;
2518                         Constant rc = right as Constant;
2519
2520                         // The conversion rules are ignored in enum context but why
2521                         if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2522                                 left = lc = EnumLiftUp (ec, lc, rc, loc);
2523                                 if (lc == null)
2524                                         return null;
2525
2526                                 right = rc = EnumLiftUp (ec, rc, lc, loc);
2527                                 if (rc == null)
2528                                         return null;
2529                         }
2530
2531                         if (rc != null && lc != null) {
2532                                 int prev_e = Report.Errors;
2533                                 Expression e = ConstantFold.BinaryFold (
2534                                         ec, oper, lc, rc, loc);
2535                                 if (e != null || Report.Errors != prev_e)
2536                                         return e;
2537                         } else {
2538                                 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2539                                         ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2540
2541                                         if ((ResolveOperator (ec)) == null) {
2542                                                 Error_OperatorCannotBeApplied (left, right);
2543                                                 return null;
2544                                         }
2545
2546                                         //
2547                                         // The result is a constant with side-effect
2548                                         //
2549                                         Constant side_effect = rc == null ?
2550                                                 new SideEffectConstant (lc, right, loc) :
2551                                                 new SideEffectConstant (rc, left, loc);
2552
2553                                         return ReducedExpression.Create (side_effect, this);
2554                                 }
2555                         }
2556
2557                         // Comparison warnings
2558                         if ((oper & Operator.ComparisonMask) != 0) {
2559                                 if (left.Equals (right)) {
2560                                         Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2561                                 }
2562                                 CheckUselessComparison (lc, right.Type);
2563                                 CheckUselessComparison (rc, left.Type);
2564                         }
2565
2566                         if (RootContext.Version >= LanguageVersion.ISO_2 &&
2567                                 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
2568                                 (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)))
2569                                 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2570
2571                         return DoResolveCore (ec, left, right);
2572                 }
2573
2574                 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2575                 {
2576                         Expression expr = ResolveOperator (ec);
2577                         if (expr == null)
2578                                 Error_OperatorCannotBeApplied (left_orig, right_orig);
2579
2580                         if (left == null || right == null)
2581                                 throw new InternalErrorException ("Invalid conversion");
2582
2583                         if (oper == Operator.BitwiseOr)
2584                                 CheckBitwiseOrOnSignExtended ();
2585
2586                         return expr;
2587                 }
2588
2589                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2590                 {
2591                         left.MutateHoistedGenericType (storey);
2592                         right.MutateHoistedGenericType (storey);
2593                 }
2594
2595                 //
2596                 // D operator + (D x, D y)
2597                 // D operator - (D x, D y)
2598                 // bool operator == (D x, D y)
2599                 // bool operator != (D x, D y)
2600                 //
2601                 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2602                 {
2603                         bool is_equality = (oper & Operator.EqualityMask) != 0;
2604                         if (!TypeManager.IsEqual (l, r)) {
2605                                 Expression tmp;
2606                                 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2607                                         tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2608                                         if (tmp == null)
2609                                                 return null;
2610                                         right = tmp;
2611                                         r = right.Type;
2612                                 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2613                                         tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2614                                         if (tmp == null)
2615                                                 return null;
2616                                         left = tmp;
2617                                         l = left.Type;
2618                                 } else {
2619                                         return null;
2620                                 }
2621                         }
2622
2623                         //
2624                         // Resolve delegate equality as a user operator
2625                         //
2626                         if (is_equality)
2627                                 return ResolveUserOperator (ec, l, r);
2628
2629                         MethodInfo method;
2630                         ArrayList args = new ArrayList (2);
2631                         args.Add (new Argument (left, Argument.AType.Expression));
2632                         args.Add (new Argument (right, Argument.AType.Expression));
2633
2634                         if (oper == Operator.Addition) {
2635                                 if (TypeManager.delegate_combine_delegate_delegate == null) {
2636                                         TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2637                                                 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2638                                 }
2639
2640                                 method = TypeManager.delegate_combine_delegate_delegate;
2641                         } else {
2642                                 if (TypeManager.delegate_remove_delegate_delegate == null) {
2643                                         TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2644                                                 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2645                                 }
2646
2647                                 method = TypeManager.delegate_remove_delegate_delegate;
2648                         }
2649
2650                         MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2651                         mg = mg.OverloadResolve (ec, ref args, false, loc);
2652
2653                         return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2654                 }
2655
2656                 //
2657                 // Enumeration operators
2658                 //
2659                 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2660                 {
2661                         //
2662                         // bool operator == (E x, E y);
2663                         // bool operator != (E x, E y);
2664                         // bool operator < (E x, E y);
2665                         // bool operator > (E x, E y);
2666                         // bool operator <= (E x, E y);
2667                         // bool operator >= (E x, E y);
2668                         //
2669                         // E operator & (E x, E y);
2670                         // E operator | (E x, E y);
2671                         // E operator ^ (E x, E y);
2672                         //
2673                         // U operator - (E e, E f)
2674                         // E operator - (E e, U x)
2675                         //
2676                         // E operator + (U x, E e)
2677                         // E operator + (E e, U x)
2678                         //
2679                         if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2680                                 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2681                                 return null;
2682
2683                         Expression ltemp = left;
2684                         Expression rtemp = right;
2685                         Type underlying_type;
2686                         Expression expr;
2687                         
2688                         if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2689                                 if (renum) {
2690                                         expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2691                                         if (expr != null) {
2692                                                 left = expr;
2693                                                 ltype = expr.Type;
2694                                         }
2695                                 } else if (lenum) {
2696                                         expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2697                                         if (expr != null) {
2698                                                 right = expr;
2699                                                 rtype = expr.Type;
2700                                         }
2701                                 }
2702                         }                       
2703
2704                         if (TypeManager.IsEqual (ltype, rtype)) {
2705                                 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2706
2707                                 if (left is Constant)
2708                                         left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2709                                 else
2710                                         left = EmptyCast.Create (left, underlying_type);
2711
2712                                 if (right is Constant)
2713                                         right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2714                                 else
2715                                         right = EmptyCast.Create (right, underlying_type);
2716                         } else if (lenum) {
2717                                 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2718
2719                                 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2720                                         Constant c = right as Constant;
2721                                         if (c == null || !c.IsDefaultValue)
2722                                                 return null;
2723                                 } else {
2724                                         if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2725                                                 return null;
2726
2727                                         right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2728                                 }
2729
2730                                 if (left is Constant)
2731                                         left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2732                                 else
2733                                         left = EmptyCast.Create (left, underlying_type);
2734
2735                         } else if (renum) {
2736                                 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2737
2738                                 if (oper != Operator.Addition) {
2739                                         Constant c = left as Constant;
2740                                         if (c == null || !c.IsDefaultValue)
2741                                                 return null;
2742                                 } else {
2743                                         if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2744                                                 return null;
2745
2746                                         left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2747                                 }
2748
2749                                 if (right is Constant)
2750                                         right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2751                                 else
2752                                         right = EmptyCast.Create (right, underlying_type);
2753
2754                         } else {
2755                                 return null;
2756                         }
2757
2758                         //
2759                         // C# specification uses explicit cast syntax which means binary promotion
2760                         // should happen, however it seems that csc does not do that
2761                         //
2762                         if (!DoBinaryOperatorPromotion (ec)) {
2763                                 left = ltemp;
2764                                 right = rtemp;
2765                                 return null;
2766                         }
2767
2768                         Type res_type = null;
2769                         if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2770                                 Type promoted_type = lenum ? left.Type : right.Type;
2771                                 enum_conversion = Convert.ExplicitNumericConversion (
2772                                         new EmptyExpression (promoted_type), underlying_type);
2773
2774                                 if (oper == Operator.Subtraction && renum && lenum)
2775                                         res_type = underlying_type;
2776                                 else if (oper == Operator.Addition && renum)
2777                                         res_type = rtype;
2778                                 else
2779                                         res_type = ltype;
2780                         }
2781                         
2782                         expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2783                         if (!is_compound || expr == null)
2784                                 return expr;
2785
2786                         //
2787                         // TODO: Need to corectly implemented Coumpound Assigment for all operators
2788                         // Section: 7.16.2
2789                         //
2790                         if (Convert.ImplicitConversionExists (ec, left, rtype))
2791                                 return expr;
2792
2793                         if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2794                                 return null;
2795
2796                         expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2797                         return expr;
2798                 }
2799
2800                 //
2801                 // 7.9.6 Reference type equality operators
2802                 //
2803                 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2804                 {
2805                         //
2806                         // operator != (object a, object b)
2807                         // operator == (object a, object b)
2808                         //
2809
2810                         // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2811
2812                         if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2813                                 return null;
2814
2815                         type = TypeManager.bool_type;
2816                         GenericConstraints constraints;
2817
2818                         bool lgen = TypeManager.IsGenericParameter (l);
2819
2820                         if (TypeManager.IsEqual (l, r)) {
2821                                 if (lgen) {
2822                                         //
2823                                         // Only allow to compare same reference type parameter
2824                                         //
2825                                         constraints = TypeManager.GetTypeParameterConstraints (l);
2826                                         if (constraints != null && constraints.IsReferenceType)
2827                                                 return this;
2828
2829                                         return null;
2830                                 }
2831
2832                                 if (l == TypeManager.anonymous_method_type)
2833                                         return null;
2834
2835                                 if (TypeManager.IsValueType (l))
2836                                         return null;
2837
2838                                 return this;
2839                         }
2840
2841                         bool rgen = TypeManager.IsGenericParameter (r);
2842
2843                         //
2844                         // a, Both operands are reference-type values or the value null
2845                         // b, One operand is a value of type T where T is a type-parameter and
2846                         // the other operand is the value null. Furthermore T does not have the
2847                         // value type constrain
2848                         //
2849                         if (left is NullLiteral || right is NullLiteral) {
2850                                 if (lgen) {
2851                                         constraints = TypeManager.GetTypeParameterConstraints (l);
2852                                         if (constraints != null && constraints.HasValueTypeConstraint)
2853                                                 return null;
2854
2855                                         left = new BoxedCast (left, TypeManager.object_type);
2856                                         return this;
2857                                 }
2858
2859                                 if (rgen) {
2860                                         constraints = TypeManager.GetTypeParameterConstraints (r);
2861                                         if (constraints != null && constraints.HasValueTypeConstraint)
2862                                                 return null;
2863
2864                                         right = new BoxedCast (right, TypeManager.object_type);
2865                                         return this;
2866                                 }
2867                         }
2868
2869                         //
2870                         // An interface is converted to the object before the
2871                         // standard conversion is applied. It's not clear from the
2872                         // standard but it looks like it works like that.
2873                         //
2874                         if (lgen) {
2875                                 constraints = TypeManager.GetTypeParameterConstraints (l);
2876                                 if (constraints == null || constraints.IsReferenceType)
2877                                         return null;
2878                         } else if (l.IsInterface) {
2879                                 l = TypeManager.object_type;
2880                         } else if (l.IsValueType) {
2881                                 return null;
2882                         }
2883
2884                         if (rgen) {
2885                                 constraints = TypeManager.GetTypeParameterConstraints (r);
2886                                 if (constraints == null || constraints.IsReferenceType)
2887                                         return null;
2888                         } else if (r.IsInterface) {
2889                                 r = TypeManager.object_type;
2890                         } else if (r.IsValueType) {
2891                                 return null;
2892                         }
2893
2894
2895                         const string ref_comparison = "Possible unintended reference comparison. " +
2896                                 "Consider casting the {0} side of the expression to `string' to compare the values";
2897
2898                         //
2899                         // A standard implicit conversion exists from the type of either
2900                         // operand to the type of the other operand
2901                         //
2902                         if (Convert.ImplicitReferenceConversionExists (left, r)) {
2903                                 if (l == TypeManager.string_type)
2904                                         Report.Warning (253, 2, loc, ref_comparison, "right");
2905
2906                                 return this;
2907                         }
2908
2909                         if (Convert.ImplicitReferenceConversionExists (right, l)) {
2910                                 if (r == TypeManager.string_type)
2911                                         Report.Warning (252, 2, loc, ref_comparison, "left");
2912
2913                                 return this;
2914                         }
2915
2916                         return null;
2917                 }
2918
2919
2920                 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2921                 {
2922                         //
2923                         // bool operator == (void* x, void* y);
2924                         // bool operator != (void* x, void* y);
2925                         // bool operator < (void* x, void* y);
2926                         // bool operator > (void* x, void* y);
2927                         // bool operator <= (void* x, void* y);
2928                         // bool operator >= (void* x, void* y);
2929                         //
2930                         if ((oper & Operator.ComparisonMask) != 0) {
2931                                 Expression temp;
2932                                 if (!l.IsPointer) {
2933                                         temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2934                                         if (temp == null)
2935                                                 return null;
2936                                         left = temp;
2937                                 }
2938
2939                                 if (!r.IsPointer) {
2940                                         temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2941                                         if (temp == null)
2942                                                 return null;
2943                                         right = temp;
2944                                 }
2945
2946                                 type = TypeManager.bool_type;
2947                                 return this;
2948                         }
2949
2950                         if (pointer_operators == null)
2951                                 CreatePointerOperatorsTable ();
2952
2953                         return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2954                 }
2955
2956                 //
2957                 // Build-in operators method overloading
2958                 //
2959                 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2960                 {
2961                         PredefinedOperator best_operator = null;
2962                         Type l = left.Type;
2963                         Type r = right.Type;
2964                         Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2965
2966                         foreach (PredefinedOperator po in operators) {
2967                                 if ((po.OperatorsMask & oper_mask) == 0)
2968                                         continue;
2969
2970                                 if (primitives_only) {
2971                                         if (!po.IsPrimitiveApplicable (l, r))
2972                                                 continue;
2973                                 } else {
2974                                         if (!po.IsApplicable (ec, left, right))
2975                                                 continue;
2976                                 }
2977
2978                                 if (best_operator == null) {
2979                                         best_operator = po;
2980                                         if (primitives_only)
2981                                                 break;
2982
2983                                         continue;
2984                                 }
2985
2986                                 best_operator = po.ResolveBetterOperator (ec, best_operator);
2987
2988                                 if (best_operator == null) {
2989                                         Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
2990                                                 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
2991
2992                                         best_operator = po;
2993                                         break;
2994                                 }
2995                         }
2996
2997                         if (best_operator == null)
2998                                 return null;
2999
3000                         Expression expr = best_operator.ConvertResult (ec, this);
3001                         if (enum_type == null)
3002                                 return expr;
3003
3004                         //
3005                         // HACK: required by enum_conversion
3006                         //
3007                         expr.Type = enum_type;
3008                         return EmptyCast.Create (expr, enum_type);
3009                 }
3010
3011                 //
3012                 // Performs user-operator overloading
3013                 //
3014                 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3015                 {
3016                         Operator user_oper;
3017                         if (oper == Operator.LogicalAnd)
3018                                 user_oper = Operator.BitwiseAnd;
3019                         else if (oper == Operator.LogicalOr)
3020                                 user_oper = Operator.BitwiseOr;
3021                         else
3022                                 user_oper = oper;
3023
3024                         string op = GetOperatorMetadataName (user_oper);
3025
3026                         MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3027                         MethodGroupExpr right_operators = null;
3028
3029                         if (!TypeManager.IsEqual (r, l)) {
3030                                 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3031                                 if (right_operators == null && left_operators == null)
3032                                         return null;
3033                         } else if (left_operators == null) {
3034                                 return null;
3035                         }
3036
3037                         ArrayList args = new ArrayList (2);
3038                         Argument larg = new Argument (left);
3039                         args.Add (larg);
3040                         Argument rarg = new Argument (right);
3041                         args.Add (rarg);
3042
3043                         MethodGroupExpr union;
3044
3045                         //
3046                         // User-defined operator implementations always take precedence
3047                         // over predefined operator implementations
3048                         //
3049                         if (left_operators != null && right_operators != null) {
3050                                 if (IsPredefinedUserOperator (l, user_oper)) {
3051                                         union = right_operators.OverloadResolve (ec, ref args, true, loc);
3052                                         if (union == null)
3053                                                 union = left_operators;
3054                                 } else if (IsPredefinedUserOperator (r, user_oper)) {
3055                                         union = left_operators.OverloadResolve (ec, ref args, true, loc);
3056                                         if (union == null)
3057                                                 union = right_operators;
3058                                 } else {
3059                                         union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3060                                 }
3061                         } else if (left_operators != null) {
3062                                 union = left_operators;
3063                         } else {
3064                                 union = right_operators;
3065                         }
3066
3067                         union = union.OverloadResolve (ec, ref args, true, loc);
3068                         if (union == null)
3069                                 return null;
3070
3071                         Expression oper_expr;
3072
3073                         // TODO: CreateExpressionTree is allocated every time
3074                         if (user_oper != oper) {
3075                                 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3076                                         oper == Operator.LogicalAnd, loc).Resolve (ec);
3077                         } else {
3078                                 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3079
3080                                 //
3081                                 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3082                                 // and not invoke user operator
3083                                 //
3084                                 if ((oper & Operator.EqualityMask) != 0) {
3085                                         if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3086                                                 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3087                                                 type = TypeManager.bool_type;
3088                                                 if (left is NullLiteral || right is NullLiteral)
3089                                                         oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3090                                         } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
3091                                                 //
3092                                                 // Two System.Delegate(s) are never equal
3093                                                 //
3094                                                 return null;
3095                                         }
3096                                 }
3097                         }
3098
3099                         left = larg.Expr;
3100                         right = rarg.Expr;
3101                         return oper_expr;
3102                 }
3103
3104                 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3105                 {
3106                         return null;
3107                 }
3108
3109                 private void CheckUselessComparison (Constant c, Type type)
3110                 {
3111                         if (c == null || !IsTypeIntegral (type)
3112                                 || c is StringConstant
3113                                 || c is BoolConstant
3114                                 || c is FloatConstant
3115                                 || c is DoubleConstant
3116                                 || c is DecimalConstant
3117                                 )
3118                                 return;
3119
3120                         long value = 0;
3121
3122                         if (c is ULongConstant) {
3123                                 ulong uvalue = ((ULongConstant) c).Value;
3124                                 if (uvalue > long.MaxValue) {
3125                                         if (type == TypeManager.byte_type ||
3126                                             type == TypeManager.sbyte_type ||
3127                                             type == TypeManager.short_type ||
3128                                             type == TypeManager.ushort_type ||
3129                                             type == TypeManager.int32_type ||
3130                                             type == TypeManager.uint32_type ||
3131                                             type == TypeManager.int64_type ||
3132                                                 type == TypeManager.char_type)
3133                                                 WarnUselessComparison (type);
3134                                         return;
3135                                 }
3136                                 value = (long) uvalue;
3137                         }
3138                         else if (c is ByteConstant)
3139                                 value = ((ByteConstant) c).Value;
3140                         else if (c is SByteConstant)
3141                                 value = ((SByteConstant) c).Value;
3142                         else if (c is ShortConstant)
3143                                 value = ((ShortConstant) c).Value;
3144                         else if (c is UShortConstant)
3145                                 value = ((UShortConstant) c).Value;
3146                         else if (c is IntConstant)
3147                                 value = ((IntConstant) c).Value;
3148                         else if (c is UIntConstant)
3149                                 value = ((UIntConstant) c).Value;
3150                         else if (c is LongConstant)
3151                                 value = ((LongConstant) c).Value;
3152                         else if (c is CharConstant)
3153                                 value = ((CharConstant)c).Value;
3154
3155                         if (value == 0)
3156                                 return;
3157
3158                         if (IsValueOutOfRange (value, type))
3159                                 WarnUselessComparison (type);
3160                 }
3161
3162                 static bool IsValueOutOfRange (long value, Type type)
3163                 {
3164                         if (IsTypeUnsigned (type) && value < 0)
3165                                 return true;
3166                         return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3167                                 type == TypeManager.byte_type && value >= 0x100 ||
3168                                 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3169                                 type == TypeManager.ushort_type && value >= 0x10000 ||
3170                                 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3171                                 type == TypeManager.uint32_type && value >= 0x100000000;
3172                 }
3173
3174                 static bool IsBuildInEqualityOperator (Type t)
3175                 {
3176                         return t == TypeManager.object_type || t == TypeManager.string_type ||
3177                                 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3178                 }
3179
3180                 static bool IsPredefinedUserOperator (Type t, Operator op)
3181                 {
3182                         //
3183                         // Some predefined types have user operators
3184                         //
3185                         return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3186                 }
3187
3188                 private static bool IsTypeIntegral (Type type)
3189                 {
3190                         return type == TypeManager.uint64_type ||
3191                                 type == TypeManager.int64_type ||
3192                                 type == TypeManager.uint32_type ||
3193                                 type == TypeManager.int32_type ||
3194                                 type == TypeManager.ushort_type ||
3195                                 type == TypeManager.short_type ||
3196                                 type == TypeManager.sbyte_type ||
3197                                 type == TypeManager.byte_type ||
3198                                 type == TypeManager.char_type;
3199                 }
3200
3201                 private static bool IsTypeUnsigned (Type type)
3202                 {
3203                         return type == TypeManager.uint64_type ||
3204                                 type == TypeManager.uint32_type ||
3205                                 type == TypeManager.ushort_type ||
3206                                 type == TypeManager.byte_type ||
3207                                 type == TypeManager.char_type;
3208                 }
3209
3210                 private void WarnUselessComparison (Type type)
3211                 {
3212                         Report.Warning (652, 2, loc, "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
3213                                 TypeManager.CSharpName (type));
3214                 }
3215
3216                 /// <remarks>
3217                 ///   EmitBranchable is called from Statement.EmitBoolExpression in the
3218                 ///   context of a conditional bool expression.  This function will return
3219                 ///   false if it is was possible to use EmitBranchable, or true if it was.
3220                 ///
3221                 ///   The expression's code is generated, and we will generate a branch to `target'
3222                 ///   if the resulting expression value is equal to isTrue
3223                 /// </remarks>
3224                 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3225                 {
3226                         ILGenerator ig = ec.ig;
3227
3228                         //
3229                         // This is more complicated than it looks, but its just to avoid
3230                         // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3231                         // but on top of that we want for == and != to use a special path
3232                         // if we are comparing against null
3233                         //
3234                         if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3235                                 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3236                                 
3237                                 //
3238                                 // put the constant on the rhs, for simplicity
3239                                 //
3240                                 if (left is Constant) {
3241                                         Expression swap = right;
3242                                         right = left;
3243                                         left = swap;
3244                                 }
3245                                 
3246                                 if (((Constant) right).IsZeroInteger) {
3247                                         left.EmitBranchable (ec, target, my_on_true);
3248                                         return;
3249                                 }
3250                                 if (right.Type == TypeManager.bool_type) {
3251                                         // right is a boolean, and it's not 'false' => it is 'true'
3252                                         left.EmitBranchable (ec, target, !my_on_true);
3253                                         return;
3254                                 }
3255
3256                         } else if (oper == Operator.LogicalAnd) {
3257
3258                                 if (on_true) {
3259                                         Label tests_end = ig.DefineLabel ();
3260                                         
3261                                         left.EmitBranchable (ec, tests_end, false);
3262                                         right.EmitBranchable (ec, target, true);
3263                                         ig.MarkLabel (tests_end);                                       
3264                                 } else {
3265                                         //
3266                                         // This optimizes code like this 
3267                                         // if (true && i > 4)
3268                                         //
3269                                         if (!(left is Constant))
3270                                                 left.EmitBranchable (ec, target, false);
3271
3272                                         if (!(right is Constant)) 
3273                                                 right.EmitBranchable (ec, target, false);
3274                                 }
3275                                 
3276                                 return;
3277                                 
3278                         } else if (oper == Operator.LogicalOr){
3279                                 if (on_true) {
3280                                         left.EmitBranchable (ec, target, true);
3281                                         right.EmitBranchable (ec, target, true);
3282                                         
3283                                 } else {
3284                                         Label tests_end = ig.DefineLabel ();
3285                                         left.EmitBranchable (ec, tests_end, true);
3286                                         right.EmitBranchable (ec, target, false);
3287                                         ig.MarkLabel (tests_end);
3288                                 }
3289                                 
3290                                 return;
3291                                 
3292                         } else if (!(oper == Operator.LessThan        || oper == Operator.GreaterThan ||
3293                                      oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3294                                      oper == Operator.Equality        || oper == Operator.Inequality)) {
3295                                 base.EmitBranchable (ec, target, on_true);
3296                                 return;
3297                         }
3298                         
3299                         left.Emit (ec);
3300                         right.Emit (ec);
3301
3302                         Type t = left.Type;
3303                         bool is_float = IsFloat (t);
3304                         bool is_unsigned = is_float || IsUnsigned (t);
3305                         
3306                         switch (oper){
3307                         case Operator.Equality:
3308                                 if (on_true)
3309                                         ig.Emit (OpCodes.Beq, target);
3310                                 else
3311                                         ig.Emit (OpCodes.Bne_Un, target);
3312                                 break;
3313
3314                         case Operator.Inequality:
3315                                 if (on_true)
3316                                         ig.Emit (OpCodes.Bne_Un, target);
3317                                 else
3318                                         ig.Emit (OpCodes.Beq, target);
3319                                 break;
3320
3321                         case Operator.LessThan:
3322                                 if (on_true)
3323                                         if (is_unsigned && !is_float)
3324                                                 ig.Emit (OpCodes.Blt_Un, target);
3325                                         else
3326                                                 ig.Emit (OpCodes.Blt, target);
3327                                 else
3328                                         if (is_unsigned)
3329                                                 ig.Emit (OpCodes.Bge_Un, target);
3330                                         else
3331                                                 ig.Emit (OpCodes.Bge, target);
3332                                 break;
3333
3334                         case Operator.GreaterThan:
3335                                 if (on_true)
3336                                         if (is_unsigned && !is_float)
3337                                                 ig.Emit (OpCodes.Bgt_Un, target);
3338                                         else
3339                                                 ig.Emit (OpCodes.Bgt, target);
3340                                 else
3341                                         if (is_unsigned)
3342                                                 ig.Emit (OpCodes.Ble_Un, target);
3343                                         else
3344                                                 ig.Emit (OpCodes.Ble, target);
3345                                 break;
3346
3347                         case Operator.LessThanOrEqual:
3348                                 if (on_true)
3349                                         if (is_unsigned && !is_float)
3350                                                 ig.Emit (OpCodes.Ble_Un, target);
3351                                         else
3352                                                 ig.Emit (OpCodes.Ble, target);
3353                                 else
3354                                         if (is_unsigned)
3355                                                 ig.Emit (OpCodes.Bgt_Un, target);
3356                                         else
3357                                                 ig.Emit (OpCodes.Bgt, target);
3358                                 break;
3359
3360
3361                         case Operator.GreaterThanOrEqual:
3362                                 if (on_true)
3363                                         if (is_unsigned && !is_float)
3364                                                 ig.Emit (OpCodes.Bge_Un, target);
3365                                         else
3366                                                 ig.Emit (OpCodes.Bge, target);
3367                                 else
3368                                         if (is_unsigned)
3369                                                 ig.Emit (OpCodes.Blt_Un, target);
3370                                         else
3371                                                 ig.Emit (OpCodes.Blt, target);
3372                                 break;
3373                         default:
3374                                 throw new InternalErrorException (oper.ToString ());
3375                         }
3376                 }
3377                 
3378                 public override void Emit (EmitContext ec)
3379                 {
3380                         EmitOperator (ec, left.Type);
3381                 }
3382
3383                 protected virtual void EmitOperator (EmitContext ec, Type l)
3384                 {
3385                         ILGenerator ig = ec.ig;
3386
3387                         //
3388                         // Handle short-circuit operators differently
3389                         // than the rest
3390                         //
3391                         if ((oper & Operator.LogicalMask) != 0) {
3392                                 Label load_result = ig.DefineLabel ();
3393                                 Label end = ig.DefineLabel ();
3394
3395                                 bool is_or = oper == Operator.LogicalOr;
3396                                 left.EmitBranchable (ec, load_result, is_or);
3397                                 right.Emit (ec);
3398                                 ig.Emit (OpCodes.Br_S, end);
3399                                 
3400                                 ig.MarkLabel (load_result);
3401                                 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3402                                 ig.MarkLabel (end);
3403                                 return;
3404                         }
3405
3406                         left.Emit (ec);
3407
3408                         //
3409                         // Optimize zero-based operations
3410                         //
3411                         // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3412                         //
3413                         if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3414                                 Constant rc = right as Constant;
3415                                 if (rc != null && rc.IsDefaultValue) {
3416                                         return;
3417                                 }
3418                         }
3419
3420                         right.Emit (ec);
3421                         EmitOperatorOpcode (ec, oper, l);
3422
3423                         //
3424                         // Nullable enum could require underlying type cast and we cannot simply wrap binary
3425                         // expression because that would wrap lifted binary operation
3426                         //
3427                         if (enum_conversion != null)
3428                                 enum_conversion.Emit (ec);
3429                 }
3430
3431                 public override void EmitSideEffect (EmitContext ec)
3432                 {
3433                         if ((oper & Operator.LogicalMask) != 0 ||
3434                             (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3435                                 base.EmitSideEffect (ec);
3436                         } else {
3437                                 left.EmitSideEffect (ec);
3438                                 right.EmitSideEffect (ec);
3439                         }
3440                 }
3441
3442                 protected override void CloneTo (CloneContext clonectx, Expression t)
3443                 {
3444                         Binary target = (Binary) t;
3445
3446                         target.left = left.Clone (clonectx);
3447                         target.right = right.Clone (clonectx);
3448                 }
3449                 
3450                 public override Expression CreateExpressionTree (EmitContext ec)
3451                 {
3452                         return CreateExpressionTree (ec, null);
3453                 }
3454
3455                 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)                
3456                 {
3457                         string method_name;
3458                         bool lift_arg = false;
3459                         
3460                         switch (oper) {
3461                         case Operator.Addition:
3462                                 if (method == null && ec.CheckState && !IsFloat (type))
3463                                         method_name = "AddChecked";
3464                                 else
3465                                         method_name = "Add";
3466                                 break;
3467                         case Operator.BitwiseAnd:
3468                                 method_name = "And";
3469                                 break;
3470                         case Operator.BitwiseOr:
3471                                 method_name = "Or";
3472                                 break;
3473                         case Operator.Division:
3474                                 method_name = "Divide";
3475                                 break;
3476                         case Operator.Equality:
3477                                 method_name = "Equal";
3478                                 lift_arg = true;
3479                                 break;
3480                         case Operator.ExclusiveOr:
3481                                 method_name = "ExclusiveOr";
3482                                 break;                          
3483                         case Operator.GreaterThan:
3484                                 method_name = "GreaterThan";
3485                                 lift_arg = true;
3486                                 break;
3487                         case Operator.GreaterThanOrEqual:
3488                                 method_name = "GreaterThanOrEqual";
3489                                 lift_arg = true;
3490                                 break;
3491                         case Operator.Inequality:
3492                                 method_name = "NotEqual";
3493                                 lift_arg = true;
3494                                 break;
3495                         case Operator.LeftShift:
3496                                 method_name = "LeftShift";
3497                                 break;
3498                         case Operator.LessThan:
3499                                 method_name = "LessThan";
3500                                 lift_arg = true;
3501                                 break;
3502                         case Operator.LessThanOrEqual:
3503                                 method_name = "LessThanOrEqual";
3504                                 lift_arg = true;
3505                                 break;
3506                         case Operator.LogicalAnd:
3507                                 method_name = "AndAlso";
3508                                 break;
3509                         case Operator.LogicalOr:
3510                                 method_name = "OrElse";
3511                                 break;
3512                         case Operator.Modulus:
3513                                 method_name = "Modulo";
3514                                 break;
3515                         case Operator.Multiply:
3516                                 if (method == null && ec.CheckState && !IsFloat (type))
3517                                         method_name = "MultiplyChecked";
3518                                 else
3519                                         method_name = "Multiply";
3520                                 break;
3521                         case Operator.RightShift:
3522                                 method_name = "RightShift";
3523                                 break;
3524                         case Operator.Subtraction:
3525                                 if (method == null && ec.CheckState && !IsFloat (type))
3526                                         method_name = "SubtractChecked";
3527                                 else
3528                                         method_name = "Subtract";
3529                                 break;
3530
3531                         default:
3532                                 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3533                         }
3534
3535                         ArrayList args = new ArrayList (2);
3536                         args.Add (new Argument (left.CreateExpressionTree (ec)));
3537                         args.Add (new Argument (right.CreateExpressionTree (ec)));
3538                         if (method != null) {
3539                                 if (lift_arg)
3540                                         args.Add (new Argument (new BoolConstant (false, loc)));
3541                                 
3542                                 args.Add (new Argument (method.CreateExpressionTree (ec)));
3543                         }
3544                         
3545                         return CreateExpressionFactoryCall (method_name, args);
3546                 }
3547         }
3548         
3549         //
3550         // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3551         // b, c, d... may be strings or objects.
3552         //
3553         public class StringConcat : Expression {
3554                 ArrayList arguments;
3555                 
3556                 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3557                 {
3558                         this.loc = loc;
3559                         type = TypeManager.string_type;
3560                         eclass = ExprClass.Value;
3561
3562                         arguments = new ArrayList (2);
3563                         Append (ec, left);
3564                         Append (ec, right);
3565                 }
3566
3567                 public override Expression CreateExpressionTree (EmitContext ec)
3568                 {
3569                         Argument arg = (Argument) arguments [0];
3570                         return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3571                 }
3572
3573                 //
3574                 // Creates nested calls tree from an array of arguments used for IL emit
3575                 //
3576                 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3577                 {
3578                         ArrayList concat_args = new ArrayList (2);
3579                         ArrayList add_args = new ArrayList (3);
3580
3581                         concat_args.Add (left);
3582                         add_args.Add (new Argument (left_etree));
3583
3584                         concat_args.Add (arguments [pos]);
3585                         add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3586
3587                         MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3588                         if (method == null)
3589                                 return null;
3590
3591                         method = method.OverloadResolve (ec, ref concat_args, false, loc);
3592                         if (method == null)
3593                                 return null;
3594
3595                         add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3596
3597                         Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3598                         if (++pos == arguments.Count)
3599                                 return expr;
3600
3601                         left = new Argument (new EmptyExpression (method.Type));
3602                         return CreateExpressionAddCall (ec, left, expr, pos);
3603                 }
3604
3605                 public override Expression DoResolve (EmitContext ec)
3606                 {
3607                         return this;
3608                 }
3609                 
3610                 public void Append (EmitContext ec, Expression operand)
3611                 {
3612                         //
3613                         // Constant folding
3614                         //
3615                         StringConstant sc = operand as StringConstant;
3616                         if (sc != null) {
3617                                 if (arguments.Count != 0) {
3618                                         Argument last_argument = (Argument) arguments [arguments.Count - 1];
3619                                         StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3620                                         if (last_expr_constant != null) {
3621                                                 last_argument.Expr = new StringConstant (
3622                                                         last_expr_constant.Value + sc.Value, sc.Location);
3623                                                 return;
3624                                         }
3625                                 }
3626                         } else {
3627                                 //
3628                                 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3629                                 //
3630                                 StringConcat concat_oper = operand as StringConcat;
3631                                 if (concat_oper != null) {
3632                                         arguments.AddRange (concat_oper.arguments);
3633                                         return;
3634                                 }
3635                         }
3636
3637                         arguments.Add (new Argument (operand));
3638                 }
3639
3640                 Expression CreateConcatMemberExpression ()
3641                 {
3642                         return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3643                 }
3644
3645                 public override void Emit (EmitContext ec)
3646                 {
3647                         Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3648                         concat = concat.Resolve (ec);
3649                         if (concat != null)
3650                                 concat.Emit (ec);
3651                 }
3652                 
3653                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3654                 {
3655                         foreach (Argument a in arguments)
3656                                 a.Expr.MutateHoistedGenericType (storey);
3657                 }               
3658         }
3659
3660         //
3661         // User-defined conditional logical operator
3662         //
3663         public class ConditionalLogicalOperator : UserOperatorCall {
3664                 readonly bool is_and;
3665                 Expression oper;
3666
3667                 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3668                         ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3669                         : base (oper_method, arguments, expr_tree, loc)
3670                 {
3671                         this.is_and = is_and;
3672                 }
3673                 
3674                 public override Expression DoResolve (EmitContext ec)
3675                 {
3676                         MethodInfo method = (MethodInfo)mg;
3677                         type = TypeManager.TypeToCoreType (method.ReturnType);
3678                         AParametersCollection pd = TypeManager.GetParameterData (method);
3679                         if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3680                                 Report.Error (217, loc,
3681                                         "A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator",
3682                                         TypeManager.CSharpSignature (method));
3683                                 return null;
3684                         }
3685
3686                         Expression left_dup = new EmptyExpression (type);
3687                         Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3688                         Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3689                         if (op_true == null || op_false == null) {
3690                                 Report.Error (218, loc,
3691                                         "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3692                                         TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3693                                 return null;
3694                         }
3695
3696                         oper = is_and ? op_false : op_true;
3697                         eclass = ExprClass.Value;
3698                         return this;
3699                 }
3700
3701                 public override void Emit (EmitContext ec)
3702                 {
3703                         ILGenerator ig = ec.ig;
3704                         Label end_target = ig.DefineLabel ();
3705
3706                         //
3707                         // Emit and duplicate left argument
3708                         //
3709                         ((Argument)arguments [0]).Expr.Emit (ec);
3710                         ig.Emit (OpCodes.Dup);
3711                         arguments.RemoveAt (0);
3712
3713                         oper.EmitBranchable (ec, end_target, true);
3714                         base.Emit (ec);
3715                         ig.MarkLabel (end_target);
3716                 }
3717         }
3718
3719         public class PointerArithmetic : Expression {
3720                 Expression left, right;
3721                 Binary.Operator op;
3722
3723                 //
3724                 // We assume that `l' is always a pointer
3725                 //
3726                 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3727                 {
3728                         type = t;
3729                         this.loc = loc;
3730                         left = l;
3731                         right = r;
3732                         this.op = op;
3733                 }
3734
3735                 public override Expression CreateExpressionTree (EmitContext ec)
3736                 {
3737                         Error_PointerInsideExpressionTree ();
3738                         return null;
3739                 }
3740
3741                 public override Expression DoResolve (EmitContext ec)
3742                 {
3743                         eclass = ExprClass.Variable;
3744                         
3745                         if (left.Type == TypeManager.void_ptr_type) {
3746                                 Error (242, "The operation in question is undefined on void pointers");
3747                                 return null;
3748                         }
3749                         
3750                         return this;
3751                 }
3752
3753                 public override void Emit (EmitContext ec)
3754                 {
3755                         Type op_type = left.Type;
3756                         ILGenerator ig = ec.ig;
3757                         
3758                         // It must be either array or fixed buffer
3759                         Type element;
3760                         if (TypeManager.HasElementType (op_type)) {
3761                                 element = TypeManager.GetElementType (op_type);
3762                         } else {
3763                                 FieldExpr fe = left as FieldExpr;
3764                                 if (fe != null)
3765                                         element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3766                                 else
3767                                         element = op_type;
3768                         }
3769
3770                         int size = GetTypeSize (element);
3771                         Type rtype = right.Type;
3772                         
3773                         if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3774                                 //
3775                                 // handle (pointer - pointer)
3776                                 //
3777                                 left.Emit (ec);
3778                                 right.Emit (ec);
3779                                 ig.Emit (OpCodes.Sub);
3780
3781                                 if (size != 1){
3782                                         if (size == 0)
3783                                                 ig.Emit (OpCodes.Sizeof, element);
3784                                         else 
3785                                                 IntLiteral.EmitInt (ig, size);
3786                                         ig.Emit (OpCodes.Div);
3787                                 }
3788                                 ig.Emit (OpCodes.Conv_I8);
3789                         } else {
3790                                 //
3791                                 // handle + and - on (pointer op int)
3792                                 //
3793                                 left.Emit (ec);
3794
3795                                 Constant right_const = right as Constant;
3796                                 if (right_const != null) {
3797                                         //
3798                                         // Optimize 0-based arithmetic
3799                                         //
3800                                         if (right_const.IsDefaultValue)
3801                                                 return;
3802
3803                                         if (size != 0) {
3804                                                 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3805                                                 if (right == null)
3806                                                         return;
3807                                         } else {
3808                                                 ig.Emit (OpCodes.Sizeof, element);
3809                                                 right = EmptyExpression.Null;
3810                                         }
3811                                 }
3812
3813                                 right.Emit (ec);
3814                                 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3815                                         rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3816                                         ig.Emit (OpCodes.Conv_I);
3817                                 } else if (rtype == TypeManager.uint32_type) {
3818                                         ig.Emit (OpCodes.Conv_U);
3819                                 }
3820
3821                                 if (right_const == null && size != 1){
3822                                         if (size == 0)
3823                                                 ig.Emit (OpCodes.Sizeof, element);
3824                                         else 
3825                                                 IntLiteral.EmitInt (ig, size);
3826                                         if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3827                                                 ig.Emit (OpCodes.Conv_I8);
3828
3829                                         Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3830                                 }
3831
3832                                 if (rtype == TypeManager.int64_type)
3833                                         ig.Emit (OpCodes.Conv_I);
3834                                 else if (rtype == TypeManager.uint64_type)
3835                                         ig.Emit (OpCodes.Conv_U);
3836
3837                                 Binary.EmitOperatorOpcode (ec, op, op_type);
3838                         }
3839                 }
3840         }
3841         
3842         /// <summary>
3843         ///   Implements the ternary conditional operator (?:)
3844         /// </summary>
3845         public class Conditional : Expression {
3846                 Expression expr, true_expr, false_expr;
3847                 
3848                 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3849                 {
3850                         this.expr = expr;
3851                         this.true_expr = true_expr;
3852                         this.false_expr = false_expr;
3853                         this.loc = expr.Location;
3854                 }
3855
3856                 public Expression Expr {
3857                         get {
3858                                 return expr;
3859                         }
3860                 }
3861
3862                 public Expression TrueExpr {
3863                         get {
3864                                 return true_expr;
3865                         }
3866                 }
3867
3868                 public Expression FalseExpr {
3869                         get {
3870                                 return false_expr;
3871                         }
3872                 }
3873
3874                 public override Expression CreateExpressionTree (EmitContext ec)
3875                 {
3876                         ArrayList args = new ArrayList (3);
3877                         args.Add (new Argument (expr.CreateExpressionTree (ec)));
3878                         args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3879                         args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3880                         return CreateExpressionFactoryCall ("Condition", args);
3881                 }
3882
3883                 public override Expression DoResolve (EmitContext ec)
3884                 {
3885                         expr = expr.Resolve (ec);
3886
3887                         if (expr == null)
3888                                 return null;
3889
3890                         if (expr.Type != TypeManager.bool_type){
3891                                 expr = Expression.ResolveBoolean (
3892                                         ec, expr, loc);
3893                                 
3894                                 if (expr == null)
3895                                         return null;
3896                         }
3897                         
3898                         Assign ass = expr as Assign;
3899                         if (ass != null && ass.Source is Constant) {
3900                                 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3901                         }
3902
3903                         true_expr = true_expr.Resolve (ec);
3904                         false_expr = false_expr.Resolve (ec);
3905
3906                         if (true_expr == null || false_expr == null)
3907                                 return null;
3908
3909                         eclass = ExprClass.Value;
3910                         Type true_type = true_expr.Type;
3911                         Type false_type = false_expr.Type;
3912                         type = true_type;
3913
3914                         //
3915                         // First, if an implicit conversion exists from true_expr
3916                         // to false_expr, then the result type is of type false_expr.Type
3917                         //
3918                         if (!TypeManager.IsEqual (true_type, false_type)) {
3919                                 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3920                                 if (conv != null) {
3921                                         //
3922                                         // Check if both can convert implicitl to each other's type
3923                                         //
3924                                         if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3925                                                 Error (172,
3926                                                            "Can not compute type of conditional expression " +
3927                                                            "as `" + TypeManager.CSharpName (true_expr.Type) +
3928                                                            "' and `" + TypeManager.CSharpName (false_expr.Type) +
3929                                                            "' convert implicitly to each other");
3930                                                 return null;
3931                                         }
3932                                         type = false_type;
3933                                         true_expr = conv;
3934                                 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3935                                         false_expr = conv;
3936                                 } else {
3937                                         Report.Error (173, loc,
3938                                                 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3939                                                 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3940                                         return null;
3941                                 }
3942                         }                       
3943
3944                         // Dead code optimalization
3945                         Constant c = expr as Constant;
3946                         if (c != null){
3947                                 bool is_false = c.IsDefaultValue;
3948                                 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
3949                                 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
3950                         }
3951
3952                         return this;
3953                 }
3954
3955                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3956                 {
3957                         expr.MutateHoistedGenericType (storey);
3958                         true_expr.MutateHoistedGenericType (storey);
3959                         false_expr.MutateHoistedGenericType (storey);
3960                         type = storey.MutateType (type);
3961                 }
3962
3963                 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3964                 {
3965                         return null;
3966                 }
3967
3968                 public override void Emit (EmitContext ec)
3969                 {
3970                         ILGenerator ig = ec.ig;
3971                         Label false_target = ig.DefineLabel ();
3972                         Label end_target = ig.DefineLabel ();
3973
3974                         expr.EmitBranchable (ec, false_target, false);
3975                         true_expr.Emit (ec);
3976
3977                         if (type.IsInterface) {
3978                                 LocalBuilder temp = ec.GetTemporaryLocal (type);
3979                                 ig.Emit (OpCodes.Stloc, temp);
3980                                 ig.Emit (OpCodes.Ldloc, temp);
3981                                 ec.FreeTemporaryLocal (temp, type);
3982                         }
3983
3984                         ig.Emit (OpCodes.Br, end_target);
3985                         ig.MarkLabel (false_target);
3986                         false_expr.Emit (ec);
3987                         ig.MarkLabel (end_target);
3988                 }
3989
3990                 protected override void CloneTo (CloneContext clonectx, Expression t)
3991                 {
3992                         Conditional target = (Conditional) t;
3993
3994                         target.expr = expr.Clone (clonectx);
3995                         target.true_expr = true_expr.Clone (clonectx);
3996                         target.false_expr = false_expr.Clone (clonectx);
3997                 }
3998         }
3999
4000         public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4001                 LocalTemporary temp;
4002
4003                 #region Abstract
4004                 public abstract HoistedVariable HoistedVariable { get; }
4005                 public abstract bool IsFixed { get; }
4006                 public abstract bool IsRef { get; }
4007                 public abstract string Name { get; }
4008                 public abstract void SetHasAddressTaken ();
4009
4010                 //
4011                 // Variable IL data, it has to be protected to encapsulate hoisted variables
4012                 //
4013                 protected abstract ILocalVariable Variable { get; }
4014                 
4015                 //
4016                 // Variable flow-analysis data
4017                 //
4018                 public abstract VariableInfo VariableInfo { get; }
4019                 #endregion
4020
4021                 public void AddressOf (EmitContext ec, AddressOp mode)
4022                 {
4023                         if (IsHoistedEmitRequired (ec)) {
4024                                 HoistedVariable.AddressOf (ec, mode);
4025                                 return;
4026                         }
4027
4028                         Variable.EmitAddressOf (ec);
4029                 }
4030
4031                 public override void Emit (EmitContext ec)
4032                 {
4033                         Emit (ec, false);
4034                 }
4035
4036                 public override void EmitSideEffect (EmitContext ec)
4037                 {
4038                         // do nothing
4039                 }
4040
4041                 //
4042                 // This method is used by parameters that are references, that are
4043                 // being passed as references:  we only want to pass the pointer (that
4044                 // is already stored in the parameter, not the address of the pointer,
4045                 // and not the value of the variable).
4046                 //
4047                 public void EmitLoad (EmitContext ec)
4048                 {
4049                         Variable.Emit (ec);
4050                 }
4051
4052                 public void Emit (EmitContext ec, bool leave_copy)
4053                 {
4054                         Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4055
4056                         if (IsHoistedEmitRequired (ec)) {
4057                                 HoistedVariable.Emit (ec, leave_copy);
4058                                 return;
4059                         }
4060
4061                         EmitLoad (ec);
4062
4063                         if (IsRef) {
4064                                 //
4065                                 // If we are a reference, we loaded on the stack a pointer
4066                                 // Now lets load the real value
4067                                 //
4068                                 LoadFromPtr (ec.ig, type);
4069                         }
4070
4071                         if (leave_copy) {
4072                                 ec.ig.Emit (OpCodes.Dup);
4073
4074                                 if (IsRef) {
4075                                         temp = new LocalTemporary (Type);
4076                                         temp.Store (ec);
4077                                 }
4078                         }
4079                 }
4080
4081                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4082                                         bool prepare_for_load)
4083                 {
4084                         Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
4085                                       source, loc);
4086
4087                         if (IsHoistedEmitRequired (ec)) {
4088                                 HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
4089                                 return;
4090                         }
4091
4092                         if (IsRef)
4093                                 Variable.Emit (ec);
4094
4095                         source.Emit (ec);
4096
4097                         // HACK: variable is already emitted when source is an initializer 
4098                         if (source is NewInitialize) {
4099                                 if (leave_copy) {
4100                                         Variable.Emit (ec);
4101                                 }
4102                                 return;
4103                         }
4104
4105                         if (leave_copy) {
4106                                 ec.ig.Emit (OpCodes.Dup);
4107                                 if (IsRef) {
4108                                         temp = new LocalTemporary (Type);
4109                                         temp.Store (ec);
4110                                 }
4111                         }
4112
4113                         if (IsRef)
4114                                 StoreFromPtr (ec.ig, type);
4115                         else
4116                                 Variable.EmitAssign (ec);
4117
4118                         if (temp != null) {
4119                                 temp.Emit (ec);
4120                                 temp.Release (ec);
4121                         }
4122                 }
4123
4124                 public bool IsHoisted {
4125                         get { return HoistedVariable != null; }
4126                 }
4127
4128                 protected virtual bool IsHoistedEmitRequired (EmitContext ec)
4129                 {
4130                         //
4131                         // Default implementation return true when there is a hosted variable
4132                         //
4133                         return HoistedVariable != null;
4134                 }
4135
4136                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4137                 {
4138                         type = storey.MutateType (type);
4139                 }
4140         }
4141
4142         /// <summary>
4143         ///   Local variables
4144         /// </summary>
4145         public class LocalVariableReference : VariableReference {
4146                 readonly string name;
4147                 public Block Block;
4148                 public LocalInfo local_info;
4149                 bool is_readonly;
4150
4151                 public LocalVariableReference (Block block, string name, Location l)
4152                 {
4153                         Block = block;
4154                         this.name = name;
4155                         loc = l;
4156                         eclass = ExprClass.Variable;
4157                 }
4158
4159                 //
4160                 // Setting `is_readonly' to false will allow you to create a writable
4161                 // reference to a read-only variable.  This is used by foreach and using.
4162                 //
4163                 public LocalVariableReference (Block block, string name, Location l,
4164                                                LocalInfo local_info, bool is_readonly)
4165                         : this (block, name, l)
4166                 {
4167                         this.local_info = local_info;
4168                         this.is_readonly = is_readonly;
4169                 }
4170
4171                 public override VariableInfo VariableInfo {
4172                         get { return local_info.VariableInfo; }
4173                 }
4174
4175                 public override HoistedVariable HoistedVariable {
4176                         get { return local_info.HoistedVariableReference; }
4177                 }
4178
4179                 //              
4180                 // A local variable is always fixed
4181                 //
4182                 public override bool IsFixed {
4183                         get { return true; }
4184                 }
4185
4186                 public override bool IsRef {
4187                         get { return false; }
4188                 }
4189
4190                 public bool IsReadOnly {
4191                         get { return is_readonly; }
4192                 }
4193
4194                 public override string Name {
4195                         get { return name; }
4196                 }
4197
4198                 public bool VerifyAssigned (EmitContext ec)
4199                 {
4200                         VariableInfo variable_info = local_info.VariableInfo;
4201                         return variable_info == null || variable_info.IsAssigned (ec, loc);
4202                 }
4203
4204                 void ResolveLocalInfo ()
4205                 {
4206                         if (local_info == null) {
4207                                 local_info = Block.GetLocalInfo (Name);
4208                                 type = local_info.VariableType;
4209                                 is_readonly = local_info.ReadOnly;
4210                         }
4211                 }
4212
4213                 public override void SetHasAddressTaken ()
4214                 {
4215                         local_info.AddressTaken = true;
4216                 }
4217
4218                 public override Expression CreateExpressionTree (EmitContext ec)
4219                 {
4220                         ArrayList arg = new ArrayList (1);
4221                         arg.Add (new Argument (this));
4222                         return CreateExpressionFactoryCall ("Constant", arg);
4223                 }
4224
4225                 Expression DoResolveBase (EmitContext ec)
4226                 {
4227                         type = local_info.VariableType;
4228
4229                         Expression e = Block.GetConstantExpression (Name);
4230                         if (e != null)
4231                                 return e.Resolve (ec);
4232
4233                         VerifyAssigned (ec);
4234
4235                         //
4236                         // If we are referencing a variable from the external block
4237                         // flag it for capturing
4238                         //
4239                         if (ec.MustCaptureVariable (local_info)) {
4240                                 if (local_info.AddressTaken)
4241                                         AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4242
4243                                 if (ec.IsVariableCapturingRequired) {
4244                                         AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4245                                         storey.CaptureLocalVariable (ec, local_info);
4246                                 }
4247                         }
4248
4249                         return this;
4250                 }
4251
4252                 public override Expression DoResolve (EmitContext ec)
4253                 {
4254                         ResolveLocalInfo ();
4255                         local_info.Used = true;
4256
4257                         if (type == null && local_info.Type is VarExpr) {
4258                             local_info.VariableType = TypeManager.object_type;
4259                                 Error_VariableIsUsedBeforeItIsDeclared (Name);
4260                             return null;
4261                         }
4262                         
4263                         return DoResolveBase (ec);
4264                 }
4265
4266                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4267                 {
4268                         ResolveLocalInfo ();
4269
4270                         // is out param
4271                         if (right_side == EmptyExpression.OutAccess)
4272                                 local_info.Used = true;
4273
4274                         // Infer implicitly typed local variable
4275                         if (type == null) {
4276                                 VarExpr ve = local_info.Type as VarExpr;
4277                                 if (ve != null) {
4278                                         if (!ve.InferType (ec, right_side))
4279                                                 return null;
4280                                         type = local_info.VariableType = ve.Type;
4281                                 }
4282                         }
4283                                                 
4284                         if (is_readonly) {
4285                                 int code;
4286                                 string msg;
4287                                 if (right_side == EmptyExpression.OutAccess) {
4288                                         code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4289                                 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4290                                         code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4291                                 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4292                                         code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4293                                 } else if (right_side == EmptyExpression.UnaryAddress) {
4294                                         code = 459; msg = "Cannot take the address of {1} `{0}'";
4295                                 } else {
4296                                         code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4297                                 }
4298                                 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4299                         } else if (VariableInfo != null) {
4300                                 VariableInfo.SetAssigned (ec);
4301                         }
4302
4303                         return DoResolveBase (ec);
4304                 }
4305
4306                 public override int GetHashCode ()
4307                 {
4308                         return Name.GetHashCode ();
4309                 }
4310
4311                 public override bool Equals (object obj)
4312                 {
4313                         LocalVariableReference lvr = obj as LocalVariableReference;
4314                         if (lvr == null)
4315                                 return false;
4316
4317                         return Name == lvr.Name && Block == lvr.Block;
4318                 }
4319
4320                 protected override ILocalVariable Variable {
4321                         get { return local_info; }
4322                 }
4323
4324                 public override string ToString ()
4325                 {
4326                         return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4327                 }
4328
4329                 protected override void CloneTo (CloneContext clonectx, Expression t)
4330                 {
4331                         LocalVariableReference target = (LocalVariableReference) t;
4332                         
4333                         target.Block = clonectx.LookupBlock (Block);
4334                         if (local_info != null)
4335                                 target.local_info = clonectx.LookupVariable (local_info);
4336                 }
4337         }
4338
4339         /// <summary>
4340         ///   This represents a reference to a parameter in the intermediate
4341         ///   representation.
4342         /// </summary>
4343         public class ParameterReference : VariableReference {
4344                 readonly ToplevelParameterInfo pi;
4345                 readonly ToplevelBlock referenced;
4346
4347                 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4348                 {
4349                         this.pi = pi;
4350                         this.referenced = referenced;
4351                         this.loc = loc;
4352                 }
4353
4354                 public override bool IsRef {
4355                         get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4356                 }
4357
4358                 bool HasOutModifier {
4359                         get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4360                 }
4361
4362                 public override HoistedVariable HoistedVariable {
4363                         get { return pi.Parameter.HoistedVariableReference; }
4364                 }
4365
4366                 //
4367                 // A ref or out parameter is classified as a moveable variable, even 
4368                 // if the argument given for the parameter is a fixed variable
4369                 //              
4370                 public override bool IsFixed {
4371                         get { return !IsRef; }
4372                 }
4373
4374                 public override string Name {
4375                         get { return Parameter.Name; }
4376                 }
4377
4378                 public Parameter Parameter {
4379                         get { return pi.Parameter; }
4380                 }
4381
4382                 public override VariableInfo VariableInfo {
4383                         get { return pi.VariableInfo; }
4384                 }
4385
4386                 protected override ILocalVariable Variable {
4387                         get { return Parameter; }
4388                 }
4389
4390                 public bool IsAssigned (EmitContext ec, Location loc)
4391                 {
4392                         // HACK: Variables are not captured in probing mode
4393                         if (ec.IsInProbingMode)
4394                                 return true;
4395                         
4396                         if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4397                                 return true;
4398
4399                         Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4400                         return false;
4401                 }
4402
4403                 public override void SetHasAddressTaken ()
4404                 {
4405                         Parameter.HasAddressTaken = true;
4406                 }
4407
4408                 void SetAssigned (EmitContext ec)
4409                 {
4410                         if (HasOutModifier && ec.DoFlowAnalysis)
4411                                 ec.CurrentBranching.SetAssigned (VariableInfo);
4412                 }
4413
4414                 bool DoResolveBase (EmitContext ec)
4415                 {
4416                         type = pi.ParameterType;
4417                         eclass = ExprClass.Variable;
4418
4419                         AnonymousExpression am = ec.CurrentAnonymousMethod;
4420                         if (am == null)
4421                                 return true;
4422
4423                         ToplevelBlock declared = pi.Block;
4424                         if (declared != referenced) {
4425                                 if (IsRef) {
4426                                         Report.Error (1628, loc,
4427                                                 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4428                                                 Name, am.ContainerType);
4429                                         return false;
4430                                 }
4431                         } else {
4432                                 if (!am.IsIterator)
4433                                         return true;
4434                         }
4435
4436                         if (ec.IsVariableCapturingRequired) {
4437                                 if (pi.Parameter.HasAddressTaken)
4438                                         AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4439
4440                                 AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
4441                                 storey.CaptureParameter (ec, this);
4442                         }
4443
4444                         return true;
4445                 }
4446
4447                 public override int GetHashCode ()
4448                 {
4449                         return Name.GetHashCode ();
4450                 }
4451
4452                 public override bool Equals (object obj)
4453                 {
4454                         ParameterReference pr = obj as ParameterReference;
4455                         if (pr == null)
4456                                 return false;
4457
4458                         return Name == pr.Name && referenced == pr.referenced;
4459                 }
4460                 
4461                 protected override void CloneTo (CloneContext clonectx, Expression target)
4462                 {
4463                         // Nothing to clone
4464                 }
4465
4466                 public override Expression CreateExpressionTree (EmitContext ec)
4467                 {
4468                         if (IsHoistedEmitRequired (ec))
4469                                 return HoistedVariable.CreateExpressionTree (ec);
4470
4471                         return Parameter.ExpressionTreeVariableReference ();
4472                 }
4473
4474                 //
4475                 // Notice that for ref/out parameters, the type exposed is not the
4476                 // same type exposed externally.
4477                 //
4478                 // for "ref int a":
4479                 //   externally we expose "int&"
4480                 //   here we expose       "int".
4481                 //
4482                 // We record this in "is_ref".  This means that the type system can treat
4483                 // the type as it is expected, but when we generate the code, we generate
4484                 // the alternate kind of code.
4485                 //
4486                 public override Expression DoResolve (EmitContext ec)
4487                 {
4488                         if (!DoResolveBase (ec))
4489                                 return null;
4490
4491                         if (HasOutModifier && ec.DoFlowAnalysis &&
4492                             (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4493                                 return null;
4494
4495                         return this;
4496                 }
4497
4498                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4499                 {
4500                         if (!DoResolveBase (ec))
4501                                 return null;
4502
4503                         // HACK: parameters are not captured when probing is on
4504                         if (!ec.IsInProbingMode)
4505                                 SetAssigned (ec);
4506
4507                         return this;
4508                 }
4509
4510                 static public void EmitLdArg (ILGenerator ig, int x)
4511                 {
4512                         if (x <= 255){
4513                                 switch (x){
4514                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4515                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4516                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4517                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4518                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4519                                 }
4520                         } else
4521                                 ig.Emit (OpCodes.Ldarg, x);
4522                 }
4523         }
4524         
4525         /// <summary>
4526         ///   Used for arguments to New(), Invocation()
4527         /// </summary>
4528         public class Argument {
4529                 public enum AType : byte {
4530                         Expression,
4531                         Ref,
4532                         Out,
4533                         ArgList
4534                 };
4535
4536                 public static readonly Argument[] Empty = new Argument [0];
4537
4538                 public readonly AType ArgType;
4539                 public Expression Expr;
4540                 
4541                 public Argument (Expression expr, AType type)
4542                 {
4543                         this.Expr = expr;
4544                         this.ArgType = type;
4545                 }
4546
4547                 public Argument (Expression expr)
4548                 {
4549                         this.Expr = expr;
4550                         this.ArgType = AType.Expression;
4551                 }
4552
4553                 public Type Type {
4554                         get { return Expr.Type; }
4555                 }
4556
4557                 public Parameter.Modifier Modifier
4558                 {
4559                         get {
4560                                 switch (ArgType) {
4561                                 case AType.Out:
4562                                         return Parameter.Modifier.OUT;
4563                                         
4564                                 case AType.Ref:
4565                                         return Parameter.Modifier.REF;
4566                                         
4567                                 default:
4568                                         return Parameter.Modifier.NONE;
4569                                 }
4570                         }
4571                 }
4572
4573                 public string GetSignatureForError ()
4574                 {
4575                         if (Expr.eclass == ExprClass.MethodGroup)
4576                                 return Expr.ExprClassName;
4577
4578                         return TypeManager.CSharpName (Expr.Type);
4579                 }               
4580
4581                 public bool ResolveMethodGroup (EmitContext ec)
4582                 {
4583                         SimpleName sn = Expr as SimpleName;
4584                         if (sn != null)
4585                                 Expr = sn.GetMethodGroup ();
4586
4587                         // FIXME: csc doesn't report any error if you try to use `ref' or
4588                         //        `out' in a delegate creation expression.
4589                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4590                         if (Expr == null)
4591                                 return false;
4592
4593                         return true;
4594                 }
4595
4596                 public bool Resolve (EmitContext ec, Location loc)
4597                 {
4598                         if (Expr == null)
4599                                 return false;
4600
4601                         using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4602                                 // Verify that the argument is readable
4603                                 if (ArgType != AType.Out)
4604                                         Expr = Expr.Resolve (ec);
4605
4606                                 // Verify that the argument is writeable
4607                                 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4608                                         Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4609
4610                                 return Expr != null;
4611                         }
4612                 }
4613
4614                 public void Emit (EmitContext ec)
4615                 {
4616                         if (ArgType != AType.Ref && ArgType != AType.Out) {
4617                                 Expr.Emit (ec);
4618                                 return;
4619                         }
4620
4621                         AddressOp mode = AddressOp.Store;
4622                         if (ArgType == AType.Ref)
4623                                 mode |= AddressOp.Load;
4624                                 
4625                         IMemoryLocation ml = (IMemoryLocation) Expr;
4626                         ParameterReference pr = ml as ParameterReference;
4627
4628                         //
4629                         // ParameterReferences might already be references, so we want
4630                         // to pass just the value
4631                         //
4632                         if (pr != null && pr.IsRef)
4633                                 pr.EmitLoad (ec);
4634                         else
4635                                 ml.AddressOf (ec, mode);
4636                 }
4637
4638                 public Argument Clone (CloneContext clonectx)
4639                 {
4640                         return new Argument (Expr.Clone (clonectx), ArgType);
4641                 }
4642         }
4643
4644         /// <summary>
4645         ///   Invocation of methods or delegates.
4646         /// </summary>
4647         public class Invocation : ExpressionStatement {
4648                 protected ArrayList Arguments;
4649                 protected Expression expr;
4650                 protected MethodGroupExpr mg;
4651                 bool arguments_resolved;
4652                 
4653                 //
4654                 // arguments is an ArrayList, but we do not want to typecast,
4655                 // as it might be null.
4656                 //
4657                 public Invocation (Expression expr, ArrayList arguments)
4658                 {
4659                         SimpleName sn = expr as SimpleName;
4660                         if (sn != null)
4661                                 this.expr = sn.GetMethodGroup ();
4662                         else
4663                                 this.expr = expr;
4664                         
4665                         Arguments = arguments;
4666                         if (expr != null)
4667                                 loc = expr.Location;
4668                 }
4669
4670                 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4671                         : this (expr, arguments)
4672                 {
4673                         this.arguments_resolved = arguments_resolved;
4674                 }
4675
4676                 public override Expression CreateExpressionTree (EmitContext ec)
4677                 {
4678                         ArrayList args;
4679
4680                         //
4681                         // Special conversion for nested expression trees
4682                         //
4683                         if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4684                                 args = new ArrayList (1);
4685                                 args.Add (new Argument (this));
4686                                 return CreateExpressionFactoryCall ("Quote", args);
4687                         }
4688
4689                         ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4690
4691                         int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4692                         if (emg != null)
4693                                 ++arg_count;
4694                         args = new ArrayList (arg_count);
4695
4696                         if (mg.IsInstance)
4697                                 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4698                         else
4699                                 args.Add (new Argument (new NullLiteral (loc)));
4700
4701                         args.Add (new Argument (mg.CreateExpressionTree (ec)));
4702
4703                         //
4704                         // Use extension argument when exists
4705                         //
4706                         if (emg != null) {
4707                                 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4708                                 if (e != null)
4709                                         args.Add (new Argument (e));
4710                         }
4711
4712                         if (Arguments != null) {
4713                                 foreach (Argument a in Arguments) {
4714                                         Expression e = a.Expr.CreateExpressionTree (ec);
4715                                         if (e != null)
4716                                                 args.Add (new Argument (e));
4717                                 }
4718                         }
4719
4720                         if (mg.IsBase)
4721                                 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4722
4723                         return CreateExpressionFactoryCall ("Call", args);
4724                 }
4725
4726                 public override Expression DoResolve (EmitContext ec)
4727                 {
4728                         // Don't resolve already resolved expression
4729                         if (eclass != ExprClass.Invalid)
4730                                 return this;
4731                         
4732                         Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4733                         if (expr_resolved == null)
4734                                 return null;
4735
4736                         mg = expr_resolved as MethodGroupExpr;
4737                         if (mg == null) {
4738                                 Type expr_type = expr_resolved.Type;
4739
4740                                 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4741                                         return (new DelegateInvocation (
4742                                                 expr_resolved, Arguments, loc)).Resolve (ec);
4743                                 }
4744
4745                                 MemberExpr me = expr_resolved as MemberExpr;
4746                                 if (me == null) {
4747                                         expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4748                                         return null;
4749                                 }
4750                                 
4751                                 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4752                                 if (mg == null) {
4753                                         Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4754                                                 expr_resolved.GetSignatureForError ());
4755                                         return null;
4756                                 }
4757
4758                                 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4759                         }
4760
4761                         //
4762                         // Next, evaluate all the expressions in the argument list
4763                         //
4764                         if (Arguments != null && !arguments_resolved) {
4765                                 for (int i = 0; i < Arguments.Count; ++i)
4766                                 {
4767                                         if (!((Argument)Arguments[i]).Resolve(ec, loc))
4768                                                 return null;
4769                                 }
4770                         }
4771
4772                         mg = DoResolveOverload (ec);
4773                         if (mg == null)
4774                                 return null;
4775
4776                         MethodInfo method = (MethodInfo)mg;
4777                         if (method != null) {
4778                                 type = TypeManager.TypeToCoreType (method.ReturnType);
4779
4780                                 // TODO: this is a copy of mg.ResolveMemberAccess method
4781                                 Expression iexpr = mg.InstanceExpression;
4782                                 if (method.IsStatic) {
4783                                         if (iexpr == null ||
4784                                                 iexpr is This || iexpr is EmptyExpression ||
4785                                                 mg.IdenticalTypeName) {
4786                                                 mg.InstanceExpression = null;
4787                                         } else {
4788                                                 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4789                                                 return null;
4790                                         }
4791                                 } else {
4792                                         if (iexpr == null) {
4793                                                 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4794                                         }
4795                                 }
4796                         }
4797
4798                         if (type.IsPointer){
4799                                 if (!ec.InUnsafe){
4800                                         UnsafeError (loc);
4801                                         return null;
4802                                 }
4803                         }
4804                         
4805                         //
4806                         // Only base will allow this invocation to happen.
4807                         //
4808                         if (mg.IsBase && method.IsAbstract){
4809                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4810                                 return null;
4811                         }
4812
4813                         if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4814                                 if (mg.IsBase)
4815                                         Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4816                                 else
4817                                         Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4818                                 return null;
4819                         }
4820
4821                         IsSpecialMethodInvocation (method, loc);
4822                         
4823                         if (mg.InstanceExpression != null)
4824                                 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4825
4826                         eclass = ExprClass.Value;
4827                         return this;
4828                 }
4829
4830                 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4831                 {
4832                         return mg.OverloadResolve (ec, ref Arguments, false, loc);
4833                 }
4834
4835                 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4836                 {
4837                         if (!TypeManager.IsSpecialMethod (method))
4838                                 return false;
4839
4840                         Report.SymbolRelatedToPreviousError (method);
4841                         Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4842                                 TypeManager.CSharpSignature (method, true));
4843         
4844                         return true;
4845                 }
4846
4847                 /// <summary>
4848                 ///   Emits a list of resolved Arguments that are in the arguments
4849                 ///   ArrayList.
4850                 /// 
4851                 ///   The MethodBase argument might be null if the
4852                 ///   emission of the arguments is known not to contain
4853                 ///   a `params' field (for example in constructors or other routines
4854                 ///   that keep their arguments in this structure)
4855                 ///   
4856                 ///   if `dup_args' is true, a copy of the arguments will be left
4857                 ///   on the stack. If `dup_args' is true, you can specify `this_arg'
4858                 ///   which will be duplicated before any other args. Only EmitCall
4859                 ///   should be using this interface.
4860                 /// </summary>
4861                 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4862                 {
4863                         if (arguments == null)
4864                                 return;
4865
4866                         int top = arguments.Count;
4867                         LocalTemporary [] temps = null;
4868                         
4869                         if (dup_args && top != 0)
4870                                 temps = new LocalTemporary [top];
4871
4872                         int argument_index = 0;
4873                         Argument a;
4874                         for (int i = 0; i < top; i++) {
4875                                 a = (Argument) arguments [argument_index++];
4876                                 a.Emit (ec);
4877                                 if (dup_args) {
4878                                         ec.ig.Emit (OpCodes.Dup);
4879                                         (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4880                                 }
4881                         }
4882                         
4883                         if (dup_args) {
4884                                 if (this_arg != null)
4885                                         this_arg.Emit (ec);
4886                                 
4887                                 for (int i = 0; i < top; i ++) {
4888                                         temps [i].Emit (ec);
4889                                         temps [i].Release (ec);
4890                                 }
4891                         }
4892                 }
4893
4894                 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4895                 {
4896                         AParametersCollection pd = TypeManager.GetParameterData (mb);
4897                         
4898                         Argument a = (Argument) arguments [pd.Count - 1];
4899                         Arglist list = (Arglist) a.Expr;
4900
4901                         return list.ArgumentTypes;
4902                 }
4903
4904                 /// <summary>
4905                 /// This checks the ConditionalAttribute on the method 
4906                 /// </summary>
4907                 public static bool IsMethodExcluded (MethodBase method, Location loc)
4908                 {
4909                         if (method.IsConstructor)
4910                                 return false;
4911
4912                         method = TypeManager.DropGenericMethodArguments (method);
4913                         if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4914                                 IMethodData md = TypeManager.GetMethod (method);
4915                                 if (md != null)
4916                                         return md.IsExcluded ();
4917
4918                                 // For some methods (generated by delegate class) GetMethod returns null
4919                                 // because they are not included in builder_to_method table
4920                                 return false;
4921                         }
4922
4923                         return AttributeTester.IsConditionalMethodExcluded (method, loc);
4924                 }
4925
4926                 /// <remarks>
4927                 ///   is_base tells whether we want to force the use of the `call'
4928                 ///   opcode instead of using callvirt.  Call is required to call
4929                 ///   a specific method, while callvirt will always use the most
4930                 ///   recent method in the vtable.
4931                 ///
4932                 ///   is_static tells whether this is an invocation on a static method
4933                 ///
4934                 ///   instance_expr is an expression that represents the instance
4935                 ///   it must be non-null if is_static is false.
4936                 ///
4937                 ///   method is the method to invoke.
4938                 ///
4939                 ///   Arguments is the list of arguments to pass to the method or constructor.
4940                 /// </remarks>
4941                 public static void EmitCall (EmitContext ec, bool is_base,
4942                                              Expression instance_expr,
4943                                              MethodBase method, ArrayList Arguments, Location loc)
4944                 {
4945                         EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4946                 }
4947                 
4948                 // `dup_args' leaves an extra copy of the arguments on the stack
4949                 // `omit_args' does not leave any arguments at all.
4950                 // So, basically, you could make one call with `dup_args' set to true,
4951                 // and then another with `omit_args' set to true, and the two calls
4952                 // would have the same set of arguments. However, each argument would
4953                 // only have been evaluated once.
4954                 public static void EmitCall (EmitContext ec, bool is_base,
4955                                              Expression instance_expr,
4956                                              MethodBase method, ArrayList Arguments, Location loc,
4957                                              bool dup_args, bool omit_args)
4958                 {
4959                         ILGenerator ig = ec.ig;
4960                         bool struct_call = false;
4961                         bool this_call = false;
4962                         LocalTemporary this_arg = null;
4963
4964                         Type decl_type = method.DeclaringType;
4965
4966                         if (IsMethodExcluded (method, loc))
4967                                 return;
4968                         
4969                         bool is_static = method.IsStatic;
4970                         if (!is_static){
4971                                 this_call = instance_expr is This;
4972                                 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4973                                         struct_call = true;
4974
4975                                 //
4976                                 // If this is ourselves, push "this"
4977                                 //
4978                                 if (!omit_args) {
4979                                         Type t = null;
4980                                         Type iexpr_type = instance_expr.Type;
4981
4982                                         //
4983                                         // Push the instance expression
4984                                         //
4985                                         if (TypeManager.IsValueType (iexpr_type)) {
4986                                                 //
4987                                                 // Special case: calls to a function declared in a 
4988                                                 // reference-type with a value-type argument need
4989                                                 // to have their value boxed.
4990                                                 if (decl_type.IsValueType ||
4991                                                     TypeManager.IsGenericParameter (iexpr_type)) {
4992                                                         //
4993                                                         // If the expression implements IMemoryLocation, then
4994                                                         // we can optimize and use AddressOf on the
4995                                                         // return.
4996                                                         //
4997                                                         // If not we have to use some temporary storage for
4998                                                         // it.
4999                                                         if (instance_expr is IMemoryLocation) {
5000                                                                 ((IMemoryLocation)instance_expr).
5001                                                                         AddressOf (ec, AddressOp.LoadStore);
5002                                                         } else {
5003                                                                 LocalTemporary temp = new LocalTemporary (iexpr_type);
5004                                                                 instance_expr.Emit (ec);
5005                                                                 temp.Store (ec);
5006                                                                 temp.AddressOf (ec, AddressOp.Load);
5007                                                         }
5008
5009                                                         // avoid the overhead of doing this all the time.
5010                                                         if (dup_args)
5011                                                                 t = TypeManager.GetReferenceType (iexpr_type);
5012                                                 } else {
5013                                                         instance_expr.Emit (ec);
5014                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
5015                                                         t = TypeManager.object_type;
5016                                                 }
5017                                         } else {
5018                                                 instance_expr.Emit (ec);
5019                                                 t = instance_expr.Type;
5020                                         }
5021
5022                                         if (dup_args) {
5023                                                 ig.Emit (OpCodes.Dup);
5024                                                 if (Arguments != null && Arguments.Count != 0) {
5025                                                         this_arg = new LocalTemporary (t);
5026                                                         this_arg.Store (ec);
5027                                                 }
5028                                         }
5029                                 }
5030                         }
5031
5032                         if (!omit_args)
5033                                 EmitArguments (ec, Arguments, dup_args, this_arg);
5034
5035 #if GMCS_SOURCE
5036                         if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5037                                 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5038 #endif
5039
5040                         OpCode call_op;
5041                         if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5042                                 call_op = OpCodes.Call;
5043                         else
5044                                 call_op = OpCodes.Callvirt;
5045
5046                         if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5047                                 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5048                                 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5049                                 return;
5050                         }
5051
5052                         //
5053                         // If you have:
5054                         // this.DoFoo ();
5055                         // and DoFoo is not virtual, you can omit the callvirt,
5056                         // because you don't need the null checking behavior.
5057                         //
5058                         if (method is MethodInfo)
5059                                 ig.Emit (call_op, (MethodInfo) method);
5060                         else
5061                                 ig.Emit (call_op, (ConstructorInfo) method);
5062                 }
5063
5064                 public override void Emit (EmitContext ec)
5065                 {
5066                         mg.EmitCall (ec, Arguments);
5067                 }
5068                 
5069                 public override void EmitStatement (EmitContext ec)
5070                 {
5071                         Emit (ec);
5072
5073                         // 
5074                         // Pop the return value if there is one
5075                         //
5076                         if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5077                                 ec.ig.Emit (OpCodes.Pop);
5078                 }
5079
5080                 protected override void CloneTo (CloneContext clonectx, Expression t)
5081                 {
5082                         Invocation target = (Invocation) t;
5083
5084                         if (Arguments != null) {
5085                                 target.Arguments = new ArrayList (Arguments.Count);
5086                                 foreach (Argument a in Arguments)
5087                                         target.Arguments.Add (a.Clone (clonectx));
5088                         }
5089
5090                         target.expr = expr.Clone (clonectx);
5091                 }
5092
5093                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5094                 {
5095                         mg.MutateHoistedGenericType (storey);
5096                         if (Arguments != null) {
5097                                 foreach (Argument a in Arguments)
5098                                         a.Expr.MutateHoistedGenericType (storey);
5099                         }
5100                 }
5101         }
5102
5103         //
5104         // It's either a cast or delegate invocation
5105         //
5106         public class InvocationOrCast : ExpressionStatement
5107         {
5108                 Expression expr;
5109                 Expression argument;
5110
5111                 public InvocationOrCast (Expression expr, Expression argument)
5112                 {
5113                         this.expr = expr;
5114                         this.argument = argument;
5115                         this.loc = expr.Location;
5116                 }
5117
5118                 public override Expression CreateExpressionTree (EmitContext ec)
5119                 {
5120                         throw new NotSupportedException ("ET");
5121                 }
5122
5123                 public override Expression DoResolve (EmitContext ec)
5124                 {
5125                         Expression e = ResolveCore (ec);
5126                         if (e == null)
5127                                 return null;
5128
5129                         return e.Resolve (ec);
5130                 }
5131
5132                 Expression ResolveCore (EmitContext ec)
5133                 {
5134                         //
5135                         // First try to resolve it as a cast.
5136                         //
5137                         TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5138                         if (te != null) {
5139                                 return new Cast (te, argument, loc);
5140                         }
5141
5142                         //
5143                         // This can either be a type or a delegate invocation.
5144                         // Let's just resolve it and see what we'll get.
5145                         //
5146                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5147                         if (expr == null)
5148                                 return null;
5149
5150                         //
5151                         // Ok, so it's a Cast.
5152                         //
5153                         if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5154                                 return new Cast (expr, argument, loc);
5155                         }
5156
5157                         if (expr.eclass == ExprClass.Namespace) {
5158                                 expr.Error_UnexpectedKind (null, "type", loc);
5159                                 return null;
5160                         }                       
5161
5162                         //
5163                         // It's a delegate invocation.
5164                         //
5165                         if (!TypeManager.IsDelegateType (expr.Type)) {
5166                                 Error (149, "Method name expected");
5167                                 return null;
5168                         }
5169
5170                         ArrayList args = new ArrayList (1);
5171                         args.Add (new Argument (argument, Argument.AType.Expression));
5172                         return new DelegateInvocation (expr, args, loc);
5173                 }
5174
5175                 public override ExpressionStatement ResolveStatement (EmitContext ec)
5176                 {
5177                         Expression e = ResolveCore (ec);
5178                         if (e == null)
5179                                 return null;
5180
5181                         ExpressionStatement s = e as ExpressionStatement;
5182                         if (s == null) {
5183                                 Error_InvalidExpressionStatement ();
5184                                 return null;
5185                         }
5186
5187                         return s.ResolveStatement (ec);
5188                 }
5189
5190                 public override void Emit (EmitContext ec)
5191                 {
5192                         throw new Exception ("Cannot happen");
5193                 }
5194
5195                 public override void EmitStatement (EmitContext ec)
5196                 {
5197                         throw new Exception ("Cannot happen");
5198                 }
5199
5200                 protected override void CloneTo (CloneContext clonectx, Expression t)
5201                 {
5202                         InvocationOrCast target = (InvocationOrCast) t;
5203
5204                         target.expr = expr.Clone (clonectx);
5205                         target.argument = argument.Clone (clonectx);
5206                 }
5207         }
5208
5209         //
5210         // This class is used to "disable" the code generation for the
5211         // temporary variable when initializing value types.
5212         //
5213         sealed class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5214                 public void AddressOf (EmitContext ec, AddressOp Mode)
5215                 {
5216                         // nothing
5217                 }
5218         }
5219         
5220         /// <summary>
5221         ///    Implements the new expression 
5222         /// </summary>
5223         public class New : ExpressionStatement, IMemoryLocation {
5224                 ArrayList Arguments;
5225
5226                 //
5227                 // During bootstrap, it contains the RequestedType,
5228                 // but if `type' is not null, it *might* contain a NewDelegate
5229                 // (because of field multi-initialization)
5230                 //
5231                 public Expression RequestedType;
5232
5233                 MethodGroupExpr method;
5234
5235                 //
5236                 // If set, the new expression is for a value_target, and
5237                 // we will not leave anything on the stack.
5238                 //
5239                 protected Expression value_target;
5240                 protected bool value_target_set;
5241                 bool is_type_parameter = false;
5242                 
5243                 public New (Expression requested_type, ArrayList arguments, Location l)
5244                 {
5245                         RequestedType = requested_type;
5246                         Arguments = arguments;
5247                         loc = l;
5248                 }
5249
5250                 public bool SetTargetVariable (Expression value)
5251                 {
5252                         value_target = value;
5253                         value_target_set = true;
5254                         if (!(value_target is IMemoryLocation)){
5255                                 Error_UnexpectedKind (null, "variable", loc);
5256                                 return false;
5257                         }
5258                         return true;
5259                 }
5260
5261                 //
5262                 // This function is used to disable the following code sequence for
5263                 // value type initialization:
5264                 //
5265                 // AddressOf (temporary)
5266                 // Construct/Init
5267                 // LoadTemporary
5268                 //
5269                 // Instead the provide will have provided us with the address on the
5270                 // stack to store the results.
5271                 //
5272                 static Expression MyEmptyExpression;
5273                 
5274                 public void DisableTemporaryValueType ()
5275                 {
5276                         if (MyEmptyExpression == null)
5277                                 MyEmptyExpression = new EmptyAddressOf ();
5278
5279                         //
5280                         // To enable this, look into:
5281                         // test-34 and test-89 and self bootstrapping.
5282                         //
5283                         // For instance, we can avoid a copy by using `newobj'
5284                         // instead of Call + Push-temp on value types.
5285 //                      value_target = MyEmptyExpression;
5286                 }
5287
5288
5289                 /// <summary>
5290                 /// Converts complex core type syntax like 'new int ()' to simple constant
5291                 /// </summary>
5292                 public static Constant Constantify (Type t)
5293                 {
5294                         if (t == TypeManager.int32_type)
5295                                 return new IntConstant (0, Location.Null);
5296                         if (t == TypeManager.uint32_type)
5297                                 return new UIntConstant (0, Location.Null);
5298                         if (t == TypeManager.int64_type)
5299                                 return new LongConstant (0, Location.Null);
5300                         if (t == TypeManager.uint64_type)
5301                                 return new ULongConstant (0, Location.Null);
5302                         if (t == TypeManager.float_type)
5303                                 return new FloatConstant (0, Location.Null);
5304                         if (t == TypeManager.double_type)
5305                                 return new DoubleConstant (0, Location.Null);
5306                         if (t == TypeManager.short_type)
5307                                 return new ShortConstant (0, Location.Null);
5308                         if (t == TypeManager.ushort_type)
5309                                 return new UShortConstant (0, Location.Null);
5310                         if (t == TypeManager.sbyte_type)
5311                                 return new SByteConstant (0, Location.Null);
5312                         if (t == TypeManager.byte_type)
5313                                 return new ByteConstant (0, Location.Null);
5314                         if (t == TypeManager.char_type)
5315                                 return new CharConstant ('\0', Location.Null);
5316                         if (t == TypeManager.bool_type)
5317                                 return new BoolConstant (false, Location.Null);
5318                         if (t == TypeManager.decimal_type)
5319                                 return new DecimalConstant (0, Location.Null);
5320                         if (TypeManager.IsEnumType (t))
5321                                 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5322
5323                         return null;
5324                 }
5325
5326                 //
5327                 // Checks whether the type is an interface that has the
5328                 // [ComImport, CoClass] attributes and must be treated
5329                 // specially
5330                 //
5331                 public Expression CheckComImport (EmitContext ec)
5332                 {
5333                         if (!type.IsInterface)
5334                                 return null;
5335
5336                         //
5337                         // Turn the call into:
5338                         // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5339                         //
5340                         Type real_class = AttributeTester.GetCoClassAttribute (type);
5341                         if (real_class == null)
5342                                 return null;
5343
5344                         New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5345                         Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5346                         return cast.Resolve (ec);
5347                 }
5348
5349                 public override Expression CreateExpressionTree (EmitContext ec)
5350                 {
5351                         ArrayList args = Arguments == null ?
5352                                 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5353
5354                         if (method == null) {
5355                                 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5356                         } else {
5357                                 args.Add (new Argument (method.CreateExpressionTree (ec)));
5358                                 if (Arguments != null) {
5359                                         Expression expr;
5360                                         foreach (Argument a in Arguments) {
5361                                                 expr = a.Expr.CreateExpressionTree (ec);
5362                                                 if (expr != null)
5363                                                         args.Add (new Argument (expr));
5364                                         }
5365                                 }
5366                         }
5367
5368                         return CreateExpressionFactoryCall ("New", args);
5369                 }
5370                 
5371                 public override Expression DoResolve (EmitContext ec)
5372                 {
5373                         //
5374                         // The New DoResolve might be called twice when initializing field
5375                         // expressions (see EmitFieldInitializers, the call to
5376                         // GetInitializerExpression will perform a resolve on the expression,
5377                         // and later the assign will trigger another resolution
5378                         //
5379                         // This leads to bugs (#37014)
5380                         //
5381                         if (type != null){
5382                                 if (RequestedType is NewDelegate)
5383                                         return RequestedType;
5384                                 return this;
5385                         }
5386
5387                         TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5388                         if (texpr == null)
5389                                 return null;
5390
5391                         type = texpr.Type;
5392
5393                         if (type.IsPointer) {
5394                                 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5395                                         TypeManager.CSharpName (type));
5396                                 return null;
5397                         }
5398
5399                         if (Arguments == null) {
5400                                 Constant c = Constantify (type);
5401                                 if (c != null)
5402                                         return ReducedExpression.Create (c, this);
5403                         }
5404
5405                         if (TypeManager.IsDelegateType (type)) {
5406                                 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5407                         }
5408
5409 #if GMCS_SOURCE
5410                         if (type.IsGenericParameter) {
5411                                 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5412
5413                                 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5414                                         Error (304, String.Format (
5415                                                        "Cannot create an instance of the " +
5416                                                        "variable type '{0}' because it " +
5417                                                        "doesn't have the new() constraint",
5418                                                        type));
5419                                         return null;
5420                                 }
5421
5422                                 if ((Arguments != null) && (Arguments.Count != 0)) {
5423                                         Error (417, String.Format (
5424                                                        "`{0}': cannot provide arguments " +
5425                                                        "when creating an instance of a " +
5426                                                        "variable type.", type));
5427                                         return null;
5428                                 }
5429
5430                                 if (TypeManager.activator_create_instance == null) {
5431                                         Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5432                                         if (activator_type != null) {
5433                                                 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5434                                                         activator_type, "CreateInstance", loc, Type.EmptyTypes);
5435                                         }
5436                                 }
5437
5438                                 is_type_parameter = true;
5439                                 eclass = ExprClass.Value;
5440                                 return this;
5441                         }
5442 #endif
5443
5444                         if (type.IsAbstract && type.IsSealed) {
5445                                 Report.SymbolRelatedToPreviousError (type);
5446                                 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5447                                 return null;
5448                         }
5449
5450                         if (type.IsInterface || type.IsAbstract){
5451                                 if (!TypeManager.IsGenericType (type)) {
5452                                         RequestedType = CheckComImport (ec);
5453                                         if (RequestedType != null)
5454                                                 return RequestedType;
5455                                 }
5456                                 
5457                                 Report.SymbolRelatedToPreviousError (type);
5458                                 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5459                                 return null;
5460                         }
5461
5462                         bool is_struct = type.IsValueType;
5463                         eclass = ExprClass.Value;
5464
5465                         //
5466                         // SRE returns a match for .ctor () on structs (the object constructor), 
5467                         // so we have to manually ignore it.
5468                         //
5469                         if (is_struct && Arguments == null)
5470                                 return this;
5471
5472                         // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5473                         Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5474                                 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5475
5476                         if (Arguments != null){
5477                                 foreach (Argument a in Arguments){
5478                                         if (!a.Resolve (ec, loc))
5479                                                 return null;
5480                                 }
5481                         }
5482
5483                         if (ml == null)
5484                                 return null;
5485
5486                         method = ml as MethodGroupExpr;
5487                         if (method == null) {
5488                                 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5489                                 return null;
5490                         }
5491
5492                         method = method.OverloadResolve (ec, ref Arguments, false, loc);
5493                         if (method == null)
5494                                 return null;
5495
5496                         return this;
5497                 }
5498
5499                 bool DoEmitTypeParameter (EmitContext ec)
5500                 {
5501 #if GMCS_SOURCE
5502                         ILGenerator ig = ec.ig;
5503 //                      IMemoryLocation ml;
5504
5505                         MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5506                                 new Type [] { type });
5507
5508                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5509                         if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5510                                 ig.Emit (OpCodes.Call, ci);
5511                                 return true;
5512                         }
5513
5514                         // Allow DoEmit() to be called multiple times.
5515                         // We need to create a new LocalTemporary each time since
5516                         // you can't share LocalBuilders among ILGeneators.
5517                         LocalTemporary temp = new LocalTemporary (type);
5518
5519                         Label label_activator = ig.DefineLabel ();
5520                         Label label_end = ig.DefineLabel ();
5521
5522                         temp.AddressOf (ec, AddressOp.Store);
5523                         ig.Emit (OpCodes.Initobj, type);
5524
5525                         temp.Emit (ec);
5526                         ig.Emit (OpCodes.Box, type);
5527                         ig.Emit (OpCodes.Brfalse, label_activator);
5528
5529                         temp.AddressOf (ec, AddressOp.Store);
5530                         ig.Emit (OpCodes.Initobj, type);
5531                         temp.Emit (ec);
5532                         ig.Emit (OpCodes.Br, label_end);
5533
5534                         ig.MarkLabel (label_activator);
5535
5536                         ig.Emit (OpCodes.Call, ci);
5537                         ig.MarkLabel (label_end);
5538                         return true;
5539 #else
5540                         throw new InternalErrorException ();
5541 #endif
5542                 }
5543
5544                 //
5545                 // This DoEmit can be invoked in two contexts:
5546                 //    * As a mechanism that will leave a value on the stack (new object)
5547                 //    * As one that wont (init struct)
5548                 //
5549                 // You can control whether a value is required on the stack by passing
5550                 // need_value_on_stack.  The code *might* leave a value on the stack
5551                 // so it must be popped manually
5552                 //
5553                 // If we are dealing with a ValueType, we have a few
5554                 // situations to deal with:
5555                 //
5556                 //    * The target is a ValueType, and we have been provided
5557                 //      the instance (this is easy, we are being assigned).
5558                 //
5559                 //    * The target of New is being passed as an argument,
5560                 //      to a boxing operation or a function that takes a
5561                 //      ValueType.
5562                 //
5563                 //      In this case, we need to create a temporary variable
5564                 //      that is the argument of New.
5565                 //
5566                 // Returns whether a value is left on the stack
5567                 //
5568                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5569                 {
5570                         bool is_value_type = TypeManager.IsValueType (type);
5571                         ILGenerator ig = ec.ig;
5572
5573                         if (is_value_type){
5574                                 IMemoryLocation ml;
5575
5576                                 // Allow DoEmit() to be called multiple times.
5577                                 // We need to create a new LocalTemporary each time since
5578                                 // you can't share LocalBuilders among ILGeneators.
5579                                 if (!value_target_set)
5580                                         value_target = new LocalTemporary (type);
5581
5582                                 ml = (IMemoryLocation) value_target;
5583                                 ml.AddressOf (ec, AddressOp.Store);
5584                         }
5585
5586                         if (method != null)
5587                                 method.EmitArguments (ec, Arguments);
5588
5589                         if (is_value_type){
5590                                 if (method == null)
5591                                         ig.Emit (OpCodes.Initobj, type);
5592                                 else
5593                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5594                                 if (need_value_on_stack){
5595                                         value_target.Emit (ec);
5596                                         return true;
5597                                 }
5598                                 return false;
5599                         } else {
5600                                 ConstructorInfo ci = (ConstructorInfo) method;
5601 #if MS_COMPATIBLE
5602                                 if (TypeManager.IsGenericType (type))
5603                                         ci = TypeBuilder.GetConstructor (type, ci);
5604 #endif
5605                                 ig.Emit (OpCodes.Newobj, ci);
5606                                 return true;
5607                         }
5608                 }
5609
5610                 public override void Emit (EmitContext ec)
5611                 {
5612                         if (is_type_parameter)
5613                                 DoEmitTypeParameter (ec);
5614                         else
5615                                 DoEmit (ec, true);
5616                 }
5617                 
5618                 public override void EmitStatement (EmitContext ec)
5619                 {
5620                         bool value_on_stack;
5621
5622                         if (is_type_parameter)
5623                                 value_on_stack = DoEmitTypeParameter (ec);
5624                         else
5625                                 value_on_stack = DoEmit (ec, false);
5626
5627                         if (value_on_stack)
5628                                 ec.ig.Emit (OpCodes.Pop);
5629
5630                 }
5631
5632                 public virtual bool HasInitializer {
5633                         get {
5634                                 return false;
5635                         }
5636                 }
5637
5638                 public void AddressOf (EmitContext ec, AddressOp Mode)
5639                 {
5640                         if (is_type_parameter) {
5641                                 LocalTemporary temp = new LocalTemporary (type);
5642                                 DoEmitTypeParameter (ec);
5643                                 temp.Store (ec);
5644                                 temp.AddressOf (ec, Mode);
5645                                 return;
5646                         }
5647
5648                         if (!type.IsValueType){
5649                                 //
5650                                 // We throw an exception.  So far, I believe we only need to support
5651                                 // value types:
5652                                 // foreach (int j in new StructType ())
5653                                 // see bug 42390
5654                                 //
5655                                 throw new Exception ("AddressOf should not be used for classes");
5656                         }
5657
5658                         if (!value_target_set)
5659                                 value_target = new LocalTemporary (type);
5660                         IMemoryLocation ml = (IMemoryLocation) value_target;
5661
5662                         ml.AddressOf (ec, AddressOp.Store);
5663                         if (method == null) {
5664                                 ec.ig.Emit (OpCodes.Initobj, type);
5665                         } else {
5666                                 method.EmitArguments (ec, Arguments);
5667                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5668                         }
5669                         
5670                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5671                 }
5672
5673                 protected override void CloneTo (CloneContext clonectx, Expression t)
5674                 {
5675                         New target = (New) t;
5676
5677                         target.RequestedType = RequestedType.Clone (clonectx);
5678                         if (Arguments != null){
5679                                 target.Arguments = new ArrayList ();
5680                                 foreach (Argument a in Arguments){
5681                                         target.Arguments.Add (a.Clone (clonectx));
5682                                 }
5683                         }
5684                 }
5685
5686                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5687                 {
5688                         if (method != null) {
5689                                 method.MutateHoistedGenericType (storey);
5690                                 if (Arguments != null) {
5691                                         foreach (Argument a in Arguments)
5692                                                 a.Expr.MutateHoistedGenericType (storey);
5693                                 }
5694                         }
5695
5696                         type = storey.MutateType (type);
5697                 }
5698         }
5699
5700         /// <summary>
5701         ///   14.5.10.2: Represents an array creation expression.
5702         /// </summary>
5703         ///
5704         /// <remarks>
5705         ///   There are two possible scenarios here: one is an array creation
5706         ///   expression that specifies the dimensions and optionally the
5707         ///   initialization data and the other which does not need dimensions
5708         ///   specified but where initialization data is mandatory.
5709         /// </remarks>
5710         public class ArrayCreation : Expression {
5711                 FullNamedExpression requested_base_type;
5712                 ArrayList initializers;
5713
5714                 //
5715                 // The list of Argument types.
5716                 // This is used to construct the `newarray' or constructor signature
5717                 //
5718                 protected ArrayList arguments;
5719                 
5720                 protected Type array_element_type;
5721                 bool expect_initializers = false;
5722                 int num_arguments = 0;
5723                 protected int dimensions;
5724                 protected readonly string rank;
5725
5726                 protected ArrayList array_data;
5727
5728                 IDictionary bounds;
5729
5730                 // The number of constants in array initializers
5731                 int const_initializers_count;
5732                 bool only_constant_initializers;
5733                 
5734                 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5735                 {
5736                         this.requested_base_type = requested_base_type;
5737                         this.initializers = initializers;
5738                         this.rank = rank;
5739                         loc = l;
5740
5741                         arguments = new ArrayList (exprs.Count);
5742
5743                         foreach (Expression e in exprs) {
5744                                 arguments.Add (new Argument (e, Argument.AType.Expression));
5745                                 num_arguments++;
5746                         }
5747                 }
5748
5749                 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5750                 {
5751                         this.requested_base_type = requested_base_type;
5752                         this.initializers = initializers;
5753                         this.rank = rank;
5754                         loc = l;
5755
5756                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5757                         //
5758                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
5759                         //
5760                         //dimensions = tmp.Length - 1;
5761                         expect_initializers = true;
5762                 }
5763
5764                 void Error_IncorrectArrayInitializer ()
5765                 {
5766                         Error (178, "Invalid rank specifier: expected `,' or `]'");
5767                 }
5768
5769                 protected override void Error_NegativeArrayIndex (Location loc)
5770                 {
5771                         Report.Error (248, loc, "Cannot create an array with a negative size");
5772                 }
5773                 
5774                 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5775                 {
5776                         if (specified_dims) { 
5777                                 Argument a = (Argument) arguments [idx];
5778
5779                                 if (!a.Resolve (ec, loc))
5780                                         return false;
5781
5782                                 Constant c = a.Expr as Constant;
5783                                 if (c != null) {
5784                                         c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5785                                 }
5786
5787                                 if (c == null) {
5788                                         Report.Error (150, a.Expr.Location, "A constant value is expected");
5789                                         return false;
5790                                 }
5791
5792                                 int value = (int) c.GetValue ();
5793                                 
5794                                 if (value != probe.Count) {
5795                                         Error_IncorrectArrayInitializer ();
5796                                         return false;
5797                                 }
5798                                 
5799                                 bounds [idx] = value;
5800                         }
5801
5802                         int child_bounds = -1;
5803                         only_constant_initializers = true;
5804                         for (int i = 0; i < probe.Count; ++i) {
5805                                 object o = probe [i];
5806                                 if (o is ArrayList) {
5807                                         ArrayList sub_probe = o as ArrayList;
5808                                         int current_bounds = sub_probe.Count;
5809                                         
5810                                         if (child_bounds == -1) 
5811                                                 child_bounds = current_bounds;
5812
5813                                         else if (child_bounds != current_bounds){
5814                                                 Error_IncorrectArrayInitializer ();
5815                                                 return false;
5816                                         }
5817                                         if (idx + 1 >= dimensions){
5818                                                 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5819                                                 return false;
5820                                         }
5821                                         
5822                                         bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5823                                         if (!ret)
5824                                                 return false;
5825                                 } else {
5826                                         if (child_bounds != -1){
5827                                                 Error_IncorrectArrayInitializer ();
5828                                                 return false;
5829                                         }
5830                                         
5831                                         Expression element = ResolveArrayElement (ec, (Expression) o);
5832                                         if (element == null)
5833                                                 continue;
5834
5835                                         // Initializers with the default values can be ignored
5836                                         Constant c = element as Constant;
5837                                         if (c != null) {
5838                                                 if (c.IsDefaultInitializer (array_element_type)) {
5839                                                         element = null;
5840                                                 }
5841                                                 else {
5842                                                         ++const_initializers_count;
5843                                                 }
5844                                         } else {
5845                                                 only_constant_initializers = false;
5846                                         }
5847                                         
5848                                         array_data.Add (element);
5849                                 }
5850                         }
5851
5852                         return true;
5853                 }
5854
5855                 public override Expression CreateExpressionTree (EmitContext ec)
5856                 {
5857                         ArrayList args;
5858
5859                         if (array_data == null) {
5860                                 args = new ArrayList (arguments.Count + 1);
5861                                 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5862                                 foreach (Argument a in arguments) {
5863                                         if (arguments.Count == 1) {
5864                                                 Constant c = a.Expr as Constant;
5865                                                 if (c.IsDefaultValue)
5866                                                         return CreateExpressionFactoryCall ("NewArrayInit", args);
5867                                         }
5868                                         args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5869                                 }
5870
5871                                 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5872                         }
5873
5874                         if (dimensions > 1) {
5875                                 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5876                                 return null;
5877                         }
5878
5879                         args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5880                         args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5881                         if (array_data != null) {
5882                                 for (int i = 0; i < array_data.Count; ++i) {
5883                                         Expression e = (Expression) array_data [i];
5884                                         if (e == null)
5885                                                 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5886
5887                                         args.Add (new Argument (e.CreateExpressionTree (ec)));
5888                                 }
5889                         }
5890
5891                         return CreateExpressionFactoryCall ("NewArrayInit", args);
5892                 }               
5893                 
5894                 public void UpdateIndices ()
5895                 {
5896                         int i = 0;
5897                         for (ArrayList probe = initializers; probe != null;) {
5898                                 if (probe.Count > 0 && probe [0] is ArrayList) {
5899                                         Expression e = new IntConstant (probe.Count, Location.Null);
5900                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5901
5902                                         bounds [i++] =  probe.Count;
5903                                         
5904                                         probe = (ArrayList) probe [0];
5905                                         
5906                                 } else {
5907                                         Expression e = new IntConstant (probe.Count, Location.Null);
5908                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5909
5910                                         bounds [i++] = probe.Count;
5911                                         return;
5912                                 }
5913                         }
5914
5915                 }
5916
5917                 Expression first_emit;
5918                 LocalTemporary first_emit_temp;
5919
5920                 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5921                 {
5922                         element = element.Resolve (ec);
5923                         if (element == null)
5924                                 return null;
5925
5926                         if (element is CompoundAssign.Helper) {
5927                                 if (first_emit != null)
5928                                         throw new InternalErrorException ("Can only handle one mutator at a time");
5929                                 first_emit = element;
5930                                 element = first_emit_temp = new LocalTemporary (element.Type);
5931                         }
5932
5933                         return Convert.ImplicitConversionRequired (
5934                                 ec, element, array_element_type, loc);
5935                 }
5936
5937                 protected bool ResolveInitializers (EmitContext ec)
5938                 {
5939                         if (initializers == null) {
5940                                 return !expect_initializers;
5941                         }
5942                                                 
5943                         //
5944                         // We use this to store all the date values in the order in which we
5945                         // will need to store them in the byte blob later
5946                         //
5947                         array_data = new ArrayList ();
5948                         bounds = new System.Collections.Specialized.HybridDictionary ();
5949                         
5950                         if (arguments != null)
5951                                 return CheckIndices (ec, initializers, 0, true);
5952
5953                         arguments = new ArrayList ();
5954
5955                         if (!CheckIndices (ec, initializers, 0, false))
5956                                 return false;
5957                                 
5958                         UpdateIndices ();
5959                                 
5960                         return true;
5961                 }
5962
5963                 //
5964                 // Resolved the type of the array
5965                 //
5966                 bool ResolveArrayType (EmitContext ec)
5967                 {
5968                         if (requested_base_type == null) {
5969                                 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5970                                 return false;
5971                         }
5972
5973                         if (requested_base_type is VarExpr) {
5974                                 Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5975                                 return false;
5976                         }
5977                         
5978                         StringBuilder array_qualifier = new StringBuilder (rank);
5979
5980                         //
5981                         // `In the first form allocates an array instace of the type that results
5982                         // from deleting each of the individual expression from the expression list'
5983                         //
5984                         if (num_arguments > 0) {
5985                                 array_qualifier.Append ("[");
5986                                 for (int i = num_arguments-1; i > 0; i--)
5987                                         array_qualifier.Append (",");
5988                                 array_qualifier.Append ("]");
5989                         }
5990
5991                         //
5992                         // Lookup the type
5993                         //
5994                         TypeExpr array_type_expr;
5995                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5996                         array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5997                         if (array_type_expr == null)
5998                                 return false;
5999
6000                         type = array_type_expr.Type;
6001                         array_element_type = TypeManager.GetElementType (type);
6002                         dimensions = type.GetArrayRank ();
6003
6004                         return true;
6005                 }
6006
6007                 public override Expression DoResolve (EmitContext ec)
6008                 {
6009                         if (type != null)
6010                                 return this;
6011
6012                         if (!ResolveArrayType (ec))
6013                                 return null;
6014
6015                         //
6016                         // First step is to validate the initializers and fill
6017                         // in any missing bits
6018                         //
6019                         if (!ResolveInitializers (ec))
6020                                 return null;
6021
6022                         if (arguments.Count != dimensions) {
6023                                 Error_IncorrectArrayInitializer ();
6024                         }
6025
6026                         foreach (Argument a in arguments){
6027                                 if (!a.Resolve (ec, loc))
6028                                         continue;
6029
6030                                 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6031                         }
6032                                                         
6033                         eclass = ExprClass.Value;
6034                         return this;
6035                 }
6036
6037                 MethodInfo GetArrayMethod (int arguments)
6038                 {
6039                         ModuleBuilder mb = CodeGen.Module.Builder;
6040
6041                         Type[] arg_types = new Type[arguments];
6042                         for (int i = 0; i < arguments; i++)
6043                                 arg_types[i] = TypeManager.int32_type;
6044
6045                         MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6046                                                         arg_types);
6047
6048                         if (mi == null) {
6049                                 Report.Error (-6, "New invocation: Can not find a constructor for " +
6050                                                   "this argument list");
6051                                 return null;
6052                         }
6053
6054                         return mi; 
6055                 }
6056
6057                 byte [] MakeByteBlob ()
6058                 {
6059                         int factor;
6060                         byte [] data;
6061                         byte [] element;
6062                         int count = array_data.Count;
6063
6064                         if (TypeManager.IsEnumType (array_element_type))
6065                                 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6066                         
6067                         factor = GetTypeSize (array_element_type);
6068                         if (factor == 0)
6069                                 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6070
6071                         data = new byte [(count * factor + 3) & ~3];
6072                         int idx = 0;
6073
6074                         for (int i = 0; i < count; ++i) {
6075                                 object v = array_data [i];
6076
6077                                 if (v is EnumConstant)
6078                                         v = ((EnumConstant) v).Child;
6079                                 
6080                                 if (v is Constant && !(v is StringConstant))
6081                                         v = ((Constant) v).GetValue ();
6082                                 else {
6083                                         idx += factor;
6084                                         continue;
6085                                 }
6086                                 
6087                                 if (array_element_type == TypeManager.int64_type){
6088                                         if (!(v is Expression)){
6089                                                 long val = (long) v;
6090                                                 
6091                                                 for (int j = 0; j < factor; ++j) {
6092                                                         data [idx + j] = (byte) (val & 0xFF);
6093                                                         val = (val >> 8);
6094                                                 }
6095                                         }
6096                                 } else if (array_element_type == TypeManager.uint64_type){
6097                                         if (!(v is Expression)){
6098                                                 ulong val = (ulong) v;
6099
6100                                                 for (int j = 0; j < factor; ++j) {
6101                                                         data [idx + j] = (byte) (val & 0xFF);
6102                                                         val = (val >> 8);
6103                                                 }
6104                                         }
6105                                 } else if (array_element_type == TypeManager.float_type) {
6106                                         if (!(v is Expression)){
6107                                                 element = BitConverter.GetBytes ((float) v);
6108                                                         
6109                                                 for (int j = 0; j < factor; ++j)
6110                                                         data [idx + j] = element [j];
6111                                                 if (!BitConverter.IsLittleEndian)
6112                                                         System.Array.Reverse (data, idx, 4);
6113                                         }
6114                                 } else if (array_element_type == TypeManager.double_type) {
6115                                         if (!(v is Expression)){
6116                                                 element = BitConverter.GetBytes ((double) v);
6117
6118                                                 for (int j = 0; j < factor; ++j)
6119                                                         data [idx + j] = element [j];
6120
6121                                                 // FIXME: Handle the ARM float format.
6122                                                 if (!BitConverter.IsLittleEndian)
6123                                                         System.Array.Reverse (data, idx, 8);
6124                                         }
6125                                 } else if (array_element_type == TypeManager.char_type){
6126                                         if (!(v is Expression)){
6127                                                 int val = (int) ((char) v);
6128                                                 
6129                                                 data [idx] = (byte) (val & 0xff);
6130                                                 data [idx+1] = (byte) (val >> 8);
6131                                         }
6132                                 } else if (array_element_type == TypeManager.short_type){
6133                                         if (!(v is Expression)){
6134                                                 int val = (int) ((short) v);
6135                                         
6136                                                 data [idx] = (byte) (val & 0xff);
6137                                                 data [idx+1] = (byte) (val >> 8);
6138                                         }
6139                                 } else if (array_element_type == TypeManager.ushort_type){
6140                                         if (!(v is Expression)){
6141                                                 int val = (int) ((ushort) v);
6142                                         
6143                                                 data [idx] = (byte) (val & 0xff);
6144                                                 data [idx+1] = (byte) (val >> 8);
6145                                         }
6146                                 } else if (array_element_type == TypeManager.int32_type) {
6147                                         if (!(v is Expression)){
6148                                                 int val = (int) v;
6149                                         
6150                                                 data [idx]   = (byte) (val & 0xff);
6151                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6152                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6153                                                 data [idx+3] = (byte) (val >> 24);
6154                                         }
6155                                 } else if (array_element_type == TypeManager.uint32_type) {
6156                                         if (!(v is Expression)){
6157                                                 uint val = (uint) v;
6158                                         
6159                                                 data [idx]   = (byte) (val & 0xff);
6160                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6161                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6162                                                 data [idx+3] = (byte) (val >> 24);
6163                                         }
6164                                 } else if (array_element_type == TypeManager.sbyte_type) {
6165                                         if (!(v is Expression)){
6166                                                 sbyte val = (sbyte) v;
6167                                                 data [idx] = (byte) val;
6168                                         }
6169                                 } else if (array_element_type == TypeManager.byte_type) {
6170                                         if (!(v is Expression)){
6171                                                 byte val = (byte) v;
6172                                                 data [idx] = (byte) val;
6173                                         }
6174                                 } else if (array_element_type == TypeManager.bool_type) {
6175                                         if (!(v is Expression)){
6176                                                 bool val = (bool) v;
6177                                                 data [idx] = (byte) (val ? 1 : 0);
6178                                         }
6179                                 } else if (array_element_type == TypeManager.decimal_type){
6180                                         if (!(v is Expression)){
6181                                                 int [] bits = Decimal.GetBits ((decimal) v);
6182                                                 int p = idx;
6183
6184                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
6185                                                 int [] nbits = new int [4];
6186                                                 nbits [0] = bits [3];
6187                                                 nbits [1] = bits [2];
6188                                                 nbits [2] = bits [0];
6189                                                 nbits [3] = bits [1];
6190                                                 
6191                                                 for (int j = 0; j < 4; j++){
6192                                                         data [p++] = (byte) (nbits [j] & 0xff);
6193                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6194                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6195                                                         data [p++] = (byte) (nbits [j] >> 24);
6196                                                 }
6197                                         }
6198                                 } else
6199                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6200
6201                                 idx += factor;
6202                         }
6203
6204                         return data;
6205                 }
6206
6207                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6208                 {
6209                         array_element_type = storey.MutateType (array_element_type);
6210                         type = storey.MutateType (type);
6211                         if (arguments != null) {
6212                                 foreach (Argument a in arguments)
6213                                         a.Expr.MutateHoistedGenericType (storey);
6214                         }
6215                         
6216                         if (array_data != null) {
6217                                 foreach (Expression e in array_data)
6218                                         e.MutateHoistedGenericType (storey);
6219                         }
6220                 }
6221
6222                 //
6223                 // Emits the initializers for the array
6224                 //
6225                 void EmitStaticInitializers (EmitContext ec)
6226                 {
6227                         // FIXME: This should go to Resolve !
6228                         if (TypeManager.void_initializearray_array_fieldhandle == null) {
6229                                 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6230                                         TypeManager.runtime_helpers_type, "InitializeArray", loc,
6231                                         TypeManager.array_type, TypeManager.runtime_field_handle_type);
6232                                 if (TypeManager.void_initializearray_array_fieldhandle == null)
6233                                         return;
6234                         }
6235
6236                         //
6237                         // First, the static data
6238                         //
6239                         FieldBuilder fb;
6240                         ILGenerator ig = ec.ig;
6241                         
6242                         byte [] data = MakeByteBlob ();
6243
6244                         fb = RootContext.MakeStaticData (data);
6245
6246                         ig.Emit (OpCodes.Dup);
6247                         ig.Emit (OpCodes.Ldtoken, fb);
6248                         ig.Emit (OpCodes.Call,
6249                                  TypeManager.void_initializearray_array_fieldhandle);
6250                 }
6251
6252                 //
6253                 // Emits pieces of the array that can not be computed at compile
6254                 // time (variables and string locations).
6255                 //
6256                 // This always expect the top value on the stack to be the array
6257                 //
6258                 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6259                 {
6260                         ILGenerator ig = ec.ig;
6261                         int dims = bounds.Count;
6262                         int [] current_pos = new int [dims];
6263
6264                         MethodInfo set = null;
6265
6266                         if (dims != 1){
6267                                 Type [] args = new Type [dims + 1];
6268
6269                                 for (int j = 0; j < dims; j++)
6270                                         args [j] = TypeManager.int32_type;
6271                                 args [dims] = array_element_type;
6272                                 
6273                                 set = CodeGen.Module.Builder.GetArrayMethod (
6274                                         type, "Set",
6275                                         CallingConventions.HasThis | CallingConventions.Standard,
6276                                         TypeManager.void_type, args);
6277                         }
6278
6279                         for (int i = 0; i < array_data.Count; i++){
6280
6281                                 Expression e = (Expression)array_data [i];
6282
6283                                 // Constant can be initialized via StaticInitializer
6284                                 if (e != null && !(!emitConstants && e is Constant)) {
6285                                         Type etype = e.Type;
6286
6287                                         ig.Emit (OpCodes.Dup);
6288
6289                                         for (int idx = 0; idx < dims; idx++) 
6290                                                 IntConstant.EmitInt (ig, current_pos [idx]);
6291
6292                                         //
6293                                         // If we are dealing with a struct, get the
6294                                         // address of it, so we can store it.
6295                                         //
6296                                         if ((dims == 1) && etype.IsValueType &&
6297                                             (!TypeManager.IsBuiltinOrEnum (etype) ||
6298                                              etype == TypeManager.decimal_type)) {
6299                                                 if (e is New){
6300                                                         New n = (New) e;
6301
6302                                                         //
6303                                                         // Let new know that we are providing
6304                                                         // the address where to store the results
6305                                                         //
6306                                                         n.DisableTemporaryValueType ();
6307                                                 }
6308
6309                                                 ig.Emit (OpCodes.Ldelema, etype);
6310                                         }
6311
6312                                         e.Emit (ec);
6313
6314                                         if (dims == 1) {
6315                                                 bool is_stobj, has_type_arg;
6316                                                 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6317                                                 if (is_stobj)
6318                                                         ig.Emit (OpCodes.Stobj, etype);
6319                                                 else if (has_type_arg)
6320                                                         ig.Emit (op, etype);
6321                                                 else
6322                                                         ig.Emit (op);
6323                                         } else 
6324                                                 ig.Emit (OpCodes.Call, set);
6325
6326                                 }
6327                                 
6328                                 //
6329                                 // Advance counter
6330                                 //
6331                                 for (int j = dims - 1; j >= 0; j--){
6332                                         current_pos [j]++;
6333                                         if (current_pos [j] < (int) bounds [j])
6334                                                 break;
6335                                         current_pos [j] = 0;
6336                                 }
6337                         }
6338                 }
6339
6340                 public override void Emit (EmitContext ec)
6341                 {
6342                         ILGenerator ig = ec.ig;
6343
6344                         if (first_emit != null) {
6345                                 first_emit.Emit (ec);
6346                                 first_emit_temp.Store (ec);
6347                         }
6348
6349                         foreach (Argument a in arguments)
6350                                 a.Emit (ec);
6351
6352                         if (arguments.Count == 1)
6353                                 ig.Emit (OpCodes.Newarr, array_element_type);
6354                         else {
6355                                 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6356                         }
6357                         
6358                         if (initializers == null)
6359                                 return;
6360
6361                         // Emit static initializer for arrays which have contain more than 4 items and
6362                         // the static initializer will initialize at least 25% of array values.
6363                         // NOTE: const_initializers_count does not contain default constant values.
6364                         if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6365                                 TypeManager.IsPrimitiveType (array_element_type)) {
6366                                 EmitStaticInitializers (ec);
6367
6368                                 if (!only_constant_initializers)
6369                                         EmitDynamicInitializers (ec, false);
6370                         } else {
6371                                 EmitDynamicInitializers (ec, true);
6372                         }
6373
6374                         if (first_emit_temp != null)
6375                                 first_emit_temp.Release (ec);
6376                 }
6377
6378                 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6379                 {
6380                         if (arguments.Count != 1) {
6381                                 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6382                                 return base.GetAttributableValue (ec, null, out value);
6383                         }
6384
6385                         if (array_data == null) {
6386                                 Constant c = (Constant)((Argument)arguments [0]).Expr;
6387                                 if (c.IsDefaultValue) {
6388                                         value = Array.CreateInstance (array_element_type, 0);
6389                                         return true;
6390                                 }
6391                                 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6392                                 return base.GetAttributableValue (ec, null, out value);
6393                         }
6394                         
6395                         Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6396                         object element_value;
6397                         for (int i = 0; i < ret.Length; ++i)
6398                         {
6399                                 Expression e = (Expression)array_data [i];
6400
6401                                 // Is null when an initializer is optimized (value == predefined value)
6402                                 if (e == null) 
6403                                         continue;
6404
6405                                 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6406                                         value = null;
6407                                         return false;
6408                                 }
6409                                 ret.SetValue (element_value, i);
6410                         }
6411                         value = ret;
6412                         return true;
6413                 }
6414                 
6415                 protected override void CloneTo (CloneContext clonectx, Expression t)
6416                 {
6417                         ArrayCreation target = (ArrayCreation) t;
6418
6419                         if (requested_base_type != null)
6420                                 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6421
6422                         if (arguments != null){
6423                                 target.arguments = new ArrayList (arguments.Count);
6424                                 foreach (Argument a in arguments)
6425                                         target.arguments.Add (a.Clone (clonectx));
6426                         }
6427
6428                         if (initializers != null){
6429                                 target.initializers = new ArrayList (initializers.Count);
6430                                 foreach (object initializer in initializers)
6431                                         if (initializer is ArrayList) {
6432                                                 ArrayList this_al = (ArrayList)initializer;
6433                                                 ArrayList al = new ArrayList (this_al.Count);
6434                                                 target.initializers.Add (al);
6435                                                 foreach (Expression e in this_al)
6436                                                         al.Add (e.Clone (clonectx));
6437                                         } else {
6438                                                 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6439                                         }
6440                         }
6441                 }
6442         }
6443         
6444         //
6445         // Represents an implicitly typed array epxression
6446         //
6447         public class ImplicitlyTypedArrayCreation : ArrayCreation
6448         {
6449                 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6450                         : base (null, rank, initializers, loc)
6451                 {
6452                         if (RootContext.Version <= LanguageVersion.ISO_2)
6453                                 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6454                                 
6455                         if (rank.Length > 2) {
6456                                 while (rank [++dimensions] == ',');
6457                         } else {
6458                                 dimensions = 1;
6459                         }
6460                 }
6461
6462                 public override Expression DoResolve (EmitContext ec)
6463                 {
6464                         if (type != null)
6465                                 return this;
6466
6467                         if (!ResolveInitializers (ec))
6468                                 return null;
6469
6470                         if (array_element_type == null || array_element_type == TypeManager.null_type ||
6471                                 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6472                                 arguments.Count != dimensions) {
6473                                 Error_NoBestType ();
6474                                 return null;
6475                         }
6476
6477                         //
6478                         // At this point we found common base type for all initializer elements
6479                         // but we have to be sure that all static initializer elements are of
6480                         // same type
6481                         //
6482                         UnifyInitializerElement (ec);
6483
6484                         type = TypeManager.GetConstructedType (array_element_type, rank);
6485                         eclass = ExprClass.Value;
6486                         return this;
6487                 }
6488
6489                 void Error_NoBestType ()
6490                 {
6491                         Report.Error (826, loc,
6492                                 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6493                 }
6494
6495                 //
6496                 // Converts static initializer only
6497                 //
6498                 void UnifyInitializerElement (EmitContext ec)
6499                 {
6500                         for (int i = 0; i < array_data.Count; ++i) {
6501                                 Expression e = (Expression)array_data[i];
6502                                 if (e != null)
6503                                         array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6504                         }
6505                 }
6506
6507                 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6508                 {
6509                         element = element.Resolve (ec);
6510                         if (element == null)
6511                                 return null;
6512                         
6513                         if (array_element_type == null) {
6514                                 array_element_type = element.Type;
6515                                 return element;
6516                         }
6517
6518                         if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6519                                 return element;
6520                         }
6521
6522                         if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6523                                 array_element_type = element.Type;
6524                                 return element;
6525                         }
6526
6527                         Error_NoBestType ();
6528                         return null;
6529                 }
6530         }       
6531         
6532         public sealed class CompilerGeneratedThis : This
6533         {
6534                 public static This Instance = new CompilerGeneratedThis ();
6535
6536                 private CompilerGeneratedThis ()
6537                         : base (Location.Null)
6538                 {
6539                 }
6540
6541                 public CompilerGeneratedThis (Type type, Location loc)
6542                         : base (loc)
6543                 {
6544                         this.type = type;
6545                 }
6546
6547                 public override Expression DoResolve (EmitContext ec)
6548                 {
6549                         eclass = ExprClass.Variable;
6550                         if (type == null)
6551                                 type = ec.ContainerType;
6552                         return this;
6553                 }
6554
6555                 public override HoistedVariable HoistedVariable {
6556                         get { return null; }
6557                 }
6558         }
6559         
6560         /// <summary>
6561         ///   Represents the `this' construct
6562         /// </summary>
6563
6564         public class This : VariableReference
6565         {
6566                 sealed class ThisVariable : ILocalVariable
6567                 {
6568                         public static readonly ILocalVariable Instance = new ThisVariable ();
6569
6570                         public void Emit (EmitContext ec)
6571                         {
6572                                 ec.ig.Emit (OpCodes.Ldarg_0);
6573                         }
6574
6575                         public void EmitAssign (EmitContext ec)
6576                         {
6577                                 throw new InvalidOperationException ();
6578                         }
6579
6580                         public void EmitAddressOf (EmitContext ec)
6581                         {
6582                                 ec.ig.Emit (OpCodes.Ldarg_0);
6583                         }
6584                 }
6585
6586                 Block block;
6587                 VariableInfo variable_info;
6588                 bool is_struct;
6589
6590                 public This (Block block, Location loc)
6591                 {
6592                         this.loc = loc;
6593                         this.block = block;
6594                 }
6595
6596                 public This (Location loc)
6597                 {
6598                         this.loc = loc;
6599                 }
6600
6601                 public override VariableInfo VariableInfo {
6602                         get { return variable_info; }
6603                 }
6604
6605                 public override bool IsFixed {
6606                         get { return false; }
6607                 }
6608
6609                 protected override bool IsHoistedEmitRequired (EmitContext ec)
6610                 {
6611                         //
6612                         // Handle 'this' differently, it cannot be assigned hence
6613                         // when we are not inside anonymous method we can emit direct access 
6614                         //
6615                         return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
6616                 }
6617
6618                 public override HoistedVariable HoistedVariable {
6619                         get { return TopToplevelBlock.HoistedThisVariable; }
6620                 }
6621
6622                 public override bool IsRef {
6623                         get { return is_struct; }
6624                 }
6625
6626                 protected override ILocalVariable Variable {
6627                         get { return ThisVariable.Instance; }
6628                 }
6629
6630                 // TODO: Move to ToplevelBlock
6631                 ToplevelBlock TopToplevelBlock {
6632                         get {
6633                                 ToplevelBlock tl = block.Toplevel;
6634                                 while (tl.Parent != null) tl = tl.Parent.Toplevel;
6635                                 return tl;
6636                         }
6637                 }
6638
6639                 public static bool IsThisAvailable (EmitContext ec)
6640                 {
6641                         if (ec.IsStatic || ec.IsInFieldInitializer)
6642                                 return false;
6643
6644                         if (ec.CurrentAnonymousMethod == null)
6645                                 return true;
6646
6647                         if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6648                                 return false;
6649
6650                         return true;
6651                 }
6652
6653                 public bool ResolveBase (EmitContext ec)
6654                 {
6655                         if (eclass != ExprClass.Invalid)
6656                                 return true;
6657
6658                         eclass = ExprClass.Variable;
6659
6660                         if (ec.TypeContainer.CurrentType != null)
6661                                 type = ec.TypeContainer.CurrentType;
6662                         else
6663                                 type = ec.ContainerType;
6664
6665                         if (!IsThisAvailable (ec)) {
6666                                 if (ec.IsStatic) {
6667                                         Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6668                                 } else {
6669                                         Report.Error (1673, loc,
6670                                                 "Anonymous methods inside structs cannot access instance members of `this'. " +
6671                                                 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6672                                 }
6673                         }
6674
6675                         is_struct = ec.TypeContainer is Struct;
6676
6677                         if (block != null) {
6678                                 if (block.Toplevel.ThisVariable != null)
6679                                         variable_info = block.Toplevel.ThisVariable.VariableInfo;
6680
6681                                 AnonymousExpression am = ec.CurrentAnonymousMethod;
6682                                 if (am != null) {
6683                                         //
6684                                         // this is hoisted to very top level block
6685                                         //
6686                                         if (ec.IsVariableCapturingRequired) {
6687                                                 // TODO: it could be optimized
6688                                                 AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
6689                                                 if (HoistedVariable == null) {
6690                                                         TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
6691                                                 }
6692                                         }
6693                                 }
6694                         }
6695                         
6696                         return true;
6697                 }
6698
6699                 //
6700                 // Called from Invocation to check if the invocation is correct
6701                 //
6702                 public override void CheckMarshalByRefAccess (EmitContext ec)
6703                 {
6704                         if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6705                             !variable_info.IsAssigned (ec)) {
6706                                 Error (188, "The `this' object cannot be used before all of its " +
6707                                        "fields are assigned to");
6708                                 variable_info.SetAssigned (ec);
6709                         }
6710                 }
6711
6712                 public override Expression CreateExpressionTree (EmitContext ec)
6713                 {
6714                         ArrayList args = new ArrayList (2);
6715                         args.Add (new Argument (this));
6716                         args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6717                         return CreateExpressionFactoryCall ("Constant", args);
6718                 }
6719                 
6720                 public override Expression DoResolve (EmitContext ec)
6721                 {
6722                         if (!ResolveBase (ec))
6723                                 return null;
6724
6725
6726                         if (ec.IsInFieldInitializer) {
6727                                 Error (27, "Keyword `this' is not available in the current context");
6728                                 return null;
6729                         }
6730                         
6731                         return this;
6732                 }
6733
6734                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6735                 {
6736                         if (!ResolveBase (ec))
6737                                 return null;
6738
6739                         if (variable_info != null)
6740                                 variable_info.SetAssigned (ec);
6741
6742                         if (ec.TypeContainer is Class){
6743                                 if (right_side == EmptyExpression.UnaryAddress)
6744                                         Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6745                                 else if (right_side == EmptyExpression.OutAccess)
6746                                         Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6747                                 else
6748                                         Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6749                         }
6750
6751                         return this;
6752                 }
6753
6754                 public override int GetHashCode()
6755                 {
6756                         return block.GetHashCode ();
6757                 }
6758
6759                 public override string Name {
6760                         get { return "this"; }
6761                 }
6762
6763                 public override bool Equals (object obj)
6764                 {
6765                         This t = obj as This;
6766                         if (t == null)
6767                                 return false;
6768
6769                         return block == t.block;
6770                 }
6771
6772                 protected override void CloneTo (CloneContext clonectx, Expression t)
6773                 {
6774                         This target = (This) t;
6775
6776                         target.block = clonectx.LookupBlock (block);
6777                 }
6778
6779                 public void RemoveHoisting ()
6780                 {
6781                         TopToplevelBlock.HoistedThisVariable = null;
6782                 }
6783
6784                 public override void SetHasAddressTaken ()
6785                 {
6786                         // Nothing
6787                 }
6788         }
6789
6790         /// <summary>
6791         ///   Represents the `__arglist' construct
6792         /// </summary>
6793         public class ArglistAccess : Expression
6794         {
6795                 public ArglistAccess (Location loc)
6796                 {
6797                         this.loc = loc;
6798                 }
6799
6800                 public override Expression CreateExpressionTree (EmitContext ec)
6801                 {
6802                         throw new NotSupportedException ("ET");
6803                 }
6804
6805                 public override Expression DoResolve (EmitContext ec)
6806                 {
6807                         eclass = ExprClass.Variable;
6808                         type = TypeManager.runtime_argument_handle_type;
6809
6810                         if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist) 
6811                         {
6812                                 Error (190, "The __arglist construct is valid only within " +
6813                                        "a variable argument method");
6814                                 return null;
6815                         }
6816
6817                         return this;
6818                 }
6819
6820                 public override void Emit (EmitContext ec)
6821                 {
6822                         ec.ig.Emit (OpCodes.Arglist);
6823                 }
6824
6825                 protected override void CloneTo (CloneContext clonectx, Expression target)
6826                 {
6827                         // nothing.
6828                 }
6829         }
6830
6831         /// <summary>
6832         ///   Represents the `__arglist (....)' construct
6833         /// </summary>
6834         public class Arglist : Expression
6835         {
6836                 Argument[] Arguments;
6837
6838                 public Arglist (Location loc)
6839                         : this (Argument.Empty, loc)
6840                 {
6841                 }
6842
6843                 public Arglist (Argument[] args, Location l)
6844                 {
6845                         Arguments = args;
6846                         loc = l;
6847                 }
6848
6849                 public Type[] ArgumentTypes {
6850                         get {
6851                                 Type[] retval = new Type [Arguments.Length];
6852                                 for (int i = 0; i < Arguments.Length; i++)
6853                                         retval [i] = Arguments [i].Type;
6854                                 return retval;
6855                         }
6856                 }
6857                 
6858                 public override Expression CreateExpressionTree (EmitContext ec)
6859                 {
6860                         Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6861                         return null;
6862                 }
6863
6864                 public override Expression DoResolve (EmitContext ec)
6865                 {
6866                         eclass = ExprClass.Variable;
6867                         type = TypeManager.runtime_argument_handle_type;
6868
6869                         foreach (Argument arg in Arguments) {
6870                                 if (!arg.Resolve (ec, loc))
6871                                         return null;
6872                         }
6873
6874                         return this;
6875                 }
6876
6877                 public override void Emit (EmitContext ec)
6878                 {
6879                         foreach (Argument arg in Arguments)
6880                                 arg.Emit (ec);
6881                 }
6882
6883                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6884                 {
6885                         foreach (Argument arg in Arguments)
6886                                 arg.Expr.MutateHoistedGenericType (storey);
6887                 }
6888
6889                 protected override void CloneTo (CloneContext clonectx, Expression t)
6890                 {
6891                         Arglist target = (Arglist) t;
6892
6893                         target.Arguments = new Argument [Arguments.Length];
6894                         for (int i = 0; i < Arguments.Length; i++)
6895                                 target.Arguments [i] = Arguments [i].Clone (clonectx);
6896                 }
6897         }
6898
6899         /// <summary>
6900         ///   Implements the typeof operator
6901         /// </summary>
6902         public class TypeOf : Expression {
6903                 Expression QueriedType;
6904                 protected Type typearg;
6905                 
6906                 public TypeOf (Expression queried_type, Location l)
6907                 {
6908                         QueriedType = queried_type;
6909                         loc = l;
6910                 }
6911
6912                 public override Expression CreateExpressionTree (EmitContext ec)
6913                 {
6914                         ArrayList args = new ArrayList (2);
6915                         args.Add (new Argument (this));
6916                         args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6917                         return CreateExpressionFactoryCall ("Constant", args);
6918                 }
6919
6920                 public override Expression DoResolve (EmitContext ec)
6921                 {
6922                         if (eclass != ExprClass.Invalid)
6923                                 return this;
6924
6925                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6926                         if (texpr == null)
6927                                 return null;
6928
6929                         typearg = texpr.Type;
6930
6931                         if (typearg == TypeManager.void_type) {
6932                                 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6933                                 return null;
6934                         }
6935
6936                         if (typearg.IsPointer && !ec.InUnsafe){
6937                                 UnsafeError (loc);
6938                                 return null;
6939                         }
6940
6941                         type = TypeManager.type_type;
6942
6943                         return DoResolveBase ();
6944                 }
6945
6946                 protected Expression DoResolveBase ()
6947                 {
6948                         if (TypeManager.system_type_get_type_from_handle == null) {
6949                                 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6950                                         TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6951                         }
6952
6953                         // Even though what is returned is a type object, it's treated as a value by the compiler.
6954                         // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6955                         eclass = ExprClass.Value;
6956                         return this;
6957                 }
6958
6959                 public override void Emit (EmitContext ec)
6960                 {
6961                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
6962                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6963                 }
6964
6965                 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6966                 {
6967                         if (TypeManager.ContainsGenericParameters (typearg) &&
6968                                 !TypeManager.IsGenericTypeDefinition (typearg)) {
6969                                 Report.SymbolRelatedToPreviousError (typearg);
6970                                 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6971                                              TypeManager.CSharpName (typearg));
6972                                 value = null;
6973                                 return false;
6974                         }
6975
6976                         if (value_type == TypeManager.object_type) {
6977                                 value = (object)typearg;
6978                                 return true;
6979                         }
6980                         value = typearg;
6981                         return true;
6982                 }
6983
6984                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6985                 {
6986                         typearg = storey.MutateType (typearg);
6987                 }
6988
6989                 public Type TypeArgument {
6990                         get {
6991                                 return typearg;
6992                         }
6993                 }
6994
6995                 protected override void CloneTo (CloneContext clonectx, Expression t)
6996                 {
6997                         TypeOf target = (TypeOf) t;
6998                         if (QueriedType != null)
6999                                 target.QueriedType = QueriedType.Clone (clonectx);
7000                 }
7001         }
7002
7003         /// <summary>
7004         ///   Implements the `typeof (void)' operator
7005         /// </summary>
7006         public class TypeOfVoid : TypeOf {
7007                 public TypeOfVoid (Location l) : base (null, l)
7008                 {
7009                         loc = l;
7010                 }
7011
7012                 public override Expression DoResolve (EmitContext ec)
7013                 {
7014                         type = TypeManager.type_type;
7015                         typearg = TypeManager.void_type;
7016
7017                         return DoResolveBase ();
7018                 }
7019         }
7020
7021         class TypeOfMethodInfo : TypeOfMethod
7022         {
7023                 public TypeOfMethodInfo (MethodBase method, Location loc)
7024                         : base (method, loc)
7025                 {
7026                 }
7027
7028                 public override Expression DoResolve (EmitContext ec)
7029                 {
7030                         type = typeof (MethodInfo);
7031                         return base.DoResolve (ec);
7032                 }
7033
7034                 public override void Emit (EmitContext ec)
7035                 {
7036                         ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7037                         base.Emit (ec);
7038                         ec.ig.Emit (OpCodes.Castclass, type);
7039                 }
7040         }
7041
7042         class TypeOfConstructorInfo : TypeOfMethod
7043         {
7044                 public TypeOfConstructorInfo (MethodBase method, Location loc)
7045                         : base (method, loc)
7046                 {
7047                 }
7048
7049                 public override Expression DoResolve (EmitContext ec)
7050                 {
7051                         type = typeof (ConstructorInfo);
7052                         return base.DoResolve (ec);
7053                 }
7054
7055                 public override void Emit (EmitContext ec)
7056                 {
7057                         ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7058                         base.Emit (ec);
7059                         ec.ig.Emit (OpCodes.Castclass, type);
7060                 }
7061         }
7062
7063         abstract class TypeOfMethod : Expression
7064         {
7065                 protected readonly MethodBase method;
7066
7067                 protected TypeOfMethod (MethodBase method, Location loc)
7068                 {
7069                         this.method = method;
7070                         this.loc = loc;
7071                 }
7072
7073                 public override Expression CreateExpressionTree (EmitContext ec)
7074                 {
7075                         ArrayList args = new ArrayList (2);
7076                         args.Add (new Argument (this));
7077                         args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7078                         return CreateExpressionFactoryCall ("Constant", args);
7079                 }
7080
7081                 public override Expression DoResolve (EmitContext ec)
7082                 {
7083                         bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7084                         MethodInfo mi = is_generic ?
7085                                 TypeManager.methodbase_get_type_from_handle_generic :
7086                                 TypeManager.methodbase_get_type_from_handle;
7087
7088                         if (mi == null) {
7089                                 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7090                                 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7091
7092                                 if (t == null || handle_type == null)
7093                                         return null;
7094
7095                                 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7096                                         is_generic ?
7097                                         new Type[] { handle_type, TypeManager.runtime_handle_type } :
7098                                         new Type[] { handle_type } );
7099
7100                                 if (is_generic)
7101                                         TypeManager.methodbase_get_type_from_handle_generic = mi;
7102                                 else
7103                                         TypeManager.methodbase_get_type_from_handle = mi;
7104                         }
7105
7106                         eclass = ExprClass.Value;
7107                         return this;
7108                 }
7109
7110                 public override void Emit (EmitContext ec)
7111                 {
7112                         bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7113                         MethodInfo mi;
7114                         if (is_generic) {
7115                                 mi = TypeManager.methodbase_get_type_from_handle_generic;
7116                                 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7117                         } else {
7118                                 mi = TypeManager.methodbase_get_type_from_handle;
7119                         }
7120
7121                         ec.ig.Emit (OpCodes.Call, mi);
7122                 }
7123         }
7124
7125         internal class TypeOfField : Expression
7126         {
7127                 readonly FieldInfo field;
7128
7129                 public TypeOfField (FieldInfo field, Location loc)
7130                 {
7131                         this.field = field;
7132                         this.loc = loc;
7133                 }
7134
7135                 public override Expression CreateExpressionTree (EmitContext ec)
7136                 {
7137                         throw new NotSupportedException ("ET");
7138                 }
7139
7140                 public override Expression DoResolve (EmitContext ec)
7141                 {
7142                         if (TypeManager.fieldinfo_get_field_from_handle == null) {
7143                                 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7144                                 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7145
7146                                 if (t != null && handle_type != null)
7147                                         TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7148                                                 "GetFieldFromHandle", loc, handle_type);
7149                         }
7150
7151                         type = typeof (FieldInfo);
7152                         eclass = ExprClass.Value;
7153                         return this;
7154                 }
7155
7156                 public override void Emit (EmitContext ec)
7157                 {
7158                         ec.ig.Emit (OpCodes.Ldtoken, field);
7159                         ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7160                 }
7161         }
7162
7163         /// <summary>
7164         ///   Implements the sizeof expression
7165         /// </summary>
7166         public class SizeOf : Expression {
7167                 readonly Expression QueriedType;
7168                 Type type_queried;
7169                 
7170                 public SizeOf (Expression queried_type, Location l)
7171                 {
7172                         this.QueriedType = queried_type;
7173                         loc = l;
7174                 }
7175
7176                 public override Expression CreateExpressionTree (EmitContext ec)
7177                 {
7178                         Error_PointerInsideExpressionTree ();
7179                         return null;
7180                 }
7181
7182                 public override Expression DoResolve (EmitContext ec)
7183                 {
7184                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7185                         if (texpr == null)
7186                                 return null;
7187
7188                         type_queried = texpr.Type;
7189                         if (TypeManager.IsEnumType (type_queried))
7190                                 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7191
7192                         int size_of = GetTypeSize (type_queried);
7193                         if (size_of > 0) {
7194                                 return new IntConstant (size_of, loc);
7195                         }
7196
7197                         if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7198                                 return null;
7199                         }
7200
7201                         if (!ec.InUnsafe) {
7202                                 Report.Error (233, loc,
7203                                         "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7204                                         TypeManager.CSharpName (type_queried));
7205                         }
7206                         
7207                         type = TypeManager.int32_type;
7208                         eclass = ExprClass.Value;
7209                         return this;
7210                 }
7211
7212                 public override void Emit (EmitContext ec)
7213                 {
7214                         int size = GetTypeSize (type_queried);
7215
7216                         if (size == 0)
7217                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7218                         else
7219                                 IntConstant.EmitInt (ec.ig, size);
7220                 }
7221
7222                 protected override void CloneTo (CloneContext clonectx, Expression t)
7223                 {
7224                 }
7225         }
7226
7227         /// <summary>
7228         ///   Implements the qualified-alias-member (::) expression.
7229         /// </summary>
7230         public class QualifiedAliasMember : MemberAccess
7231         {
7232                 readonly string alias;
7233                 public static readonly string GlobalAlias = "global";
7234
7235                 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7236                         : base (null, identifier, targs, l)
7237                 {
7238                         this.alias = alias;
7239                 }
7240
7241                 public QualifiedAliasMember (string alias, string identifier, Location l)
7242                         : base (null, identifier, l)
7243                 {
7244                         this.alias = alias;
7245                 }
7246
7247                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7248                 {
7249                         if (alias == GlobalAlias) {
7250                                 expr = RootNamespace.Global;
7251                                 return base.ResolveAsTypeStep (ec, silent);
7252                         }
7253
7254                         int errors = Report.Errors;
7255                         expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7256                         if (expr == null) {
7257                                 if (errors == Report.Errors)
7258                                         Report.Error (432, loc, "Alias `{0}' not found", alias);
7259                                 return null;
7260                         }
7261
7262                         FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7263                         if (fne == null)
7264                                 return null;
7265
7266                         if (expr.eclass == ExprClass.Type) {
7267                                 if (!silent) {
7268                                         Report.Error (431, loc,
7269                                                 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7270                                 }
7271                                 return null;
7272                         }
7273
7274                         return fne;
7275                 }
7276
7277                 public override Expression DoResolve (EmitContext ec)
7278                 {
7279                         return ResolveAsTypeStep (ec, false);
7280                 }
7281
7282                 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7283                 {
7284                         Report.Error (687, loc,
7285                                 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7286                                 GetSignatureForError ());
7287                 }
7288
7289                 public override string GetSignatureForError ()
7290                 {
7291                         string name = Name;
7292                         if (targs != null) {
7293                                 name = TypeManager.RemoveGenericArity (Name) + "<" +
7294                                         targs.GetSignatureForError () + ">";
7295                         }
7296
7297                         return alias + "::" + name;
7298                 }
7299
7300                 protected override void CloneTo (CloneContext clonectx, Expression t)
7301                 {
7302                         // Nothing 
7303                 }
7304         }
7305
7306         /// <summary>
7307         ///   Implements the member access expression
7308         /// </summary>
7309         public class MemberAccess : ATypeNameExpression {
7310                 protected Expression expr;
7311
7312                 public MemberAccess (Expression expr, string id)
7313                         : base (id, expr.Location)
7314                 {
7315                         this.expr = expr;
7316                 }
7317
7318                 public MemberAccess (Expression expr, string identifier, Location loc)
7319                         : base (identifier, loc)
7320                 {
7321                         this.expr = expr;
7322                 }
7323
7324                 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7325                         : base (identifier, args, loc)
7326                 {
7327                         this.expr = expr;
7328                 }
7329
7330                 // TODO: this method has very poor performace for Enum fields and
7331                 // probably for other constants as well
7332                 Expression DoResolve (EmitContext ec, Expression right_side)
7333                 {
7334                         if (type != null)
7335                                 throw new Exception ();
7336
7337                         //
7338                         // Resolve the expression with flow analysis turned off, we'll do the definite
7339                         // assignment checks later.  This is because we don't know yet what the expression
7340                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7341                         // definite assignment check on the actual field and not on the whole struct.
7342                         //
7343
7344                         SimpleName original = expr as SimpleName;
7345                         Expression expr_resolved = expr.Resolve (ec,
7346                                 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7347                                 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7348
7349                         if (expr_resolved == null)
7350                                 return null;
7351
7352                         string LookupIdentifier = MemberName.MakeName (Name, targs);
7353
7354                         if (expr_resolved is Namespace) {
7355                                 Namespace ns = (Namespace) expr_resolved;
7356                                 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7357 #if GMCS_SOURCE
7358                                 if ((retval != null) && (targs != null))
7359                                         retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
7360 #endif
7361
7362                                 if (retval == null)
7363                                         ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
7364                                 return retval;
7365                         }
7366
7367                         Type expr_type = expr_resolved.Type;
7368                         if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7369                                 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7370                                 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7371                                 return null;
7372                         }
7373
7374                         Constant c = expr_resolved as Constant;
7375                         if (c != null && c.GetValue () == null) {
7376                                 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7377                                         "System.NullReferenceException");
7378                         }
7379
7380                         if (targs != null) {
7381                                 if (!targs.Resolve (ec))
7382                                         return null;
7383                         }
7384
7385                         Expression member_lookup;
7386                         member_lookup = MemberLookup (
7387                                 ec.ContainerType, expr_type, expr_type, Name, loc);
7388 #if GMCS_SOURCE
7389                         if ((member_lookup == null) && (targs != null)) {
7390                                 member_lookup = MemberLookup (
7391                                         ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7392                         }
7393 #endif
7394                         if (member_lookup == null) {
7395                                 ExprClass expr_eclass = expr_resolved.eclass;
7396
7397                                 //
7398                                 // Extension methods are not allowed on all expression types
7399                                 //
7400                                 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7401                                         expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7402                                         expr_eclass == ExprClass.EventAccess) {
7403                                         ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7404                                         if (ex_method_lookup != null) {
7405                                                 ex_method_lookup.ExtensionExpression = expr_resolved;
7406
7407                                                 if (targs != null) {
7408                                                         ex_method_lookup.SetTypeArguments (targs);
7409                                                 }
7410
7411                                                 return ex_method_lookup.DoResolve (ec);
7412                                         }
7413                                 }
7414
7415                                 expr = expr_resolved;
7416                                 Error_MemberLookupFailed (
7417                                         ec.ContainerType, expr_type, expr_type, Name, null,
7418                                         AllMemberTypes, AllBindingFlags);
7419                                 return null;
7420                         }
7421
7422                         TypeExpr texpr = member_lookup as TypeExpr;
7423                         if (texpr != null) {
7424                                 if (!(expr_resolved is TypeExpr) && 
7425                                     (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7426                                         Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7427                                                 Name, member_lookup.GetSignatureForError ());
7428                                         return null;
7429                                 }
7430
7431                                 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7432                                         Report.SymbolRelatedToPreviousError (member_lookup.Type);
7433                                         ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7434                                         return null;
7435                                 }
7436
7437 #if GMCS_SOURCE
7438                                 ConstructedType ct = expr_resolved as ConstructedType;
7439                                 if (ct != null) {
7440                                         //
7441                                         // When looking up a nested type in a generic instance
7442                                         // via reflection, we always get a generic type definition
7443                                         // and not a generic instance - so we have to do this here.
7444                                         //
7445                                         // See gtest-172-lib.cs and gtest-172.cs for an example.
7446                                         //
7447                                         ct = new ConstructedType (
7448                                                 member_lookup.Type, ct.TypeArguments, loc);
7449
7450                                         return ct.ResolveAsTypeStep (ec, false);
7451                                 }
7452 #endif
7453                                 return member_lookup;
7454                         }
7455
7456                         MemberExpr me = (MemberExpr) member_lookup;
7457                         me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7458                         if (me == null)
7459                                 return null;
7460
7461                         if (targs != null) {
7462                                 me.SetTypeArguments (targs);
7463                         }
7464
7465                         if (original != null && !TypeManager.IsValueType (expr_type)) {
7466                                 if (me.IsInstance) {
7467                                         LocalVariableReference var = expr_resolved as LocalVariableReference;
7468                                         if (var != null && !var.VerifyAssigned (ec))
7469                                                 return null;
7470                                 }
7471                         }
7472
7473                         // The following DoResolve/DoResolveLValue will do the definite assignment
7474                         // check.
7475
7476                         if (right_side != null)
7477                                 return me.DoResolveLValue (ec, right_side);
7478                         else
7479                                 return me.DoResolve (ec);
7480                 }
7481
7482                 public override Expression DoResolve (EmitContext ec)
7483                 {
7484                         return DoResolve (ec, null);
7485                 }
7486
7487                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7488                 {
7489                         return DoResolve (ec, right_side);
7490                 }
7491
7492                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7493                 {
7494                         return ResolveNamespaceOrType (ec, silent);
7495                 }
7496
7497                 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7498                 {
7499                         FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7500
7501                         if (new_expr == null)
7502                                 return null;
7503
7504                         string LookupIdentifier = MemberName.MakeName (Name, targs);
7505
7506                         if (new_expr is Namespace) {
7507                                 Namespace ns = (Namespace) new_expr;
7508                                 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7509 #if GMCS_SOURCE
7510                                 if ((retval != null) && (targs != null))
7511                                         retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
7512 #endif
7513                                 if (!silent && retval == null)
7514                                         ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7515                                 return retval;
7516                         }
7517
7518                         TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7519                         if (tnew_expr == null)
7520                                 return null;
7521
7522                         if (tnew_expr is TypeParameterExpr) {
7523                                 Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7524                                         tnew_expr.GetSignatureForError ());
7525                                 return null;
7526                         }
7527
7528                         Type expr_type = tnew_expr.Type;
7529                         Expression member_lookup = MemberLookup (
7530                                 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7531                                 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7532                         if (member_lookup == null) {
7533                                 if (silent)
7534                                         return null;
7535
7536                                 Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
7537                                 return null;
7538                         }
7539
7540                         TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7541                         if (texpr == null)
7542                                 return null;
7543
7544 #if GMCS_SOURCE
7545                         TypeArguments the_args = targs;
7546                         Type declaring_type = texpr.Type.DeclaringType;
7547                         if (TypeManager.HasGenericArguments (declaring_type)) {
7548                                 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7549                                         expr_type = expr_type.BaseType;
7550                                 }
7551                                 
7552                                 TypeArguments new_args = new TypeArguments (loc);
7553                                 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7554                                         new_args.Add (new TypeExpression (decl, loc));
7555
7556                                 if (targs != null)
7557                                         new_args.Add (targs);
7558
7559                                 the_args = new_args;
7560                         }
7561
7562                         if (the_args != null) {
7563                                 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7564                                 return ctype.ResolveAsTypeStep (rc, false);
7565                         }
7566 #endif
7567
7568                         return texpr;
7569                 }
7570
7571                 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7572                 {
7573                         Expression member_lookup = MemberLookup (
7574                                 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7575                                 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7576
7577                         if (member_lookup != null) {
7578                                 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7579                                 if (expr_type == null)
7580                                         return;
7581
7582                                 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
7583                                 return;
7584                         }
7585
7586                         member_lookup = MemberLookup (
7587                                 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7588                                         MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7589
7590                         if (member_lookup == null) {
7591                                 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7592                                                   Name, expr_type.GetSignatureForError ());
7593                         } else {
7594                                 // TODO: Report.SymbolRelatedToPreviousError
7595                                 member_lookup.Error_UnexpectedKind (null, "type", loc);
7596                         }
7597                 }
7598
7599                 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7600                 {
7601                         if (RootContext.Version > LanguageVersion.ISO_2 &&
7602                                 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7603                                 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7604                                         "extension method `{1}' of type `{0}' could be found " +
7605                                         "(are you missing a using directive or an assembly reference?)",
7606                                         TypeManager.CSharpName (type), name);
7607                                 return;
7608                         }
7609
7610                         base.Error_TypeDoesNotContainDefinition (type, name);
7611                 }
7612
7613                 public override string GetSignatureForError ()
7614                 {
7615                         return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7616                 }
7617
7618                 protected override void CloneTo (CloneContext clonectx, Expression t)
7619                 {
7620                         MemberAccess target = (MemberAccess) t;
7621
7622                         target.expr = expr.Clone (clonectx);
7623                 }
7624         }
7625
7626         /// <summary>
7627         ///   Implements checked expressions
7628         /// </summary>
7629         public class CheckedExpr : Expression {
7630
7631                 public Expression Expr;
7632
7633                 public CheckedExpr (Expression e, Location l)
7634                 {
7635                         Expr = e;
7636                         loc = l;
7637                 }
7638                 
7639                 public override Expression CreateExpressionTree (EmitContext ec)
7640                 {
7641                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7642                                 return Expr.CreateExpressionTree (ec);
7643                 }
7644
7645                 public override Expression DoResolve (EmitContext ec)
7646                 {
7647                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7648                                 Expr = Expr.Resolve (ec);
7649                         
7650                         if (Expr == null)
7651                                 return null;
7652
7653                         if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7654                                 return Expr;
7655                         
7656                         eclass = Expr.eclass;
7657                         type = Expr.Type;
7658                         return this;
7659                 }
7660
7661                 public override void Emit (EmitContext ec)
7662                 {
7663                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7664                                 Expr.Emit (ec);
7665                 }
7666
7667                 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7668                 {
7669                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7670                                 Expr.EmitBranchable (ec, target, on_true);
7671                 }
7672
7673                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7674                 {
7675                         Expr.MutateHoistedGenericType (storey);
7676                 }
7677
7678                 protected override void CloneTo (CloneContext clonectx, Expression t)
7679                 {
7680                         CheckedExpr target = (CheckedExpr) t;
7681
7682                         target.Expr = Expr.Clone (clonectx);
7683                 }
7684         }
7685
7686         /// <summary>
7687         ///   Implements the unchecked expression
7688         /// </summary>
7689         public class UnCheckedExpr : Expression {
7690
7691                 public Expression Expr;
7692
7693                 public UnCheckedExpr (Expression e, Location l)
7694                 {
7695                         Expr = e;
7696                         loc = l;
7697                 }
7698                 
7699                 public override Expression CreateExpressionTree (EmitContext ec)
7700                 {
7701                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7702                                 return Expr.CreateExpressionTree (ec);
7703                 }
7704
7705                 public override Expression DoResolve (EmitContext ec)
7706                 {
7707                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7708                                 Expr = Expr.Resolve (ec);
7709
7710                         if (Expr == null)
7711                                 return null;
7712
7713                         if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7714                                 return Expr;
7715                         
7716                         eclass = Expr.eclass;
7717                         type = Expr.Type;
7718                         return this;
7719                 }
7720
7721                 public override void Emit (EmitContext ec)
7722                 {
7723                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7724                                 Expr.Emit (ec);
7725                 }
7726                 
7727                 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7728                 {
7729                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7730                                 Expr.EmitBranchable (ec, target, on_true);
7731                 }
7732
7733                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7734                 {
7735                         Expr.MutateHoistedGenericType (storey);
7736                 }
7737
7738                 protected override void CloneTo (CloneContext clonectx, Expression t)
7739                 {
7740                         UnCheckedExpr target = (UnCheckedExpr) t;
7741
7742                         target.Expr = Expr.Clone (clonectx);
7743                 }
7744         }
7745
7746         /// <summary>
7747         ///   An Element Access expression.
7748         ///
7749         ///   During semantic analysis these are transformed into 
7750         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7751         /// </summary>
7752         public class ElementAccess : Expression {
7753                 public ArrayList  Arguments;
7754                 public Expression Expr;
7755                 
7756                 public ElementAccess (Expression e, ArrayList e_list)
7757                 {
7758                         Expr = e;
7759                         loc  = e.Location;
7760                         
7761                         if (e_list == null)
7762                                 return;
7763                         
7764                         Arguments = new ArrayList (e_list.Count);
7765                         foreach (Expression tmp in e_list)
7766                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7767                 }
7768
7769                 bool CommonResolve (EmitContext ec)
7770                 {
7771                         Expr = Expr.Resolve (ec);
7772
7773                         if (Arguments == null)
7774                                 return false;
7775
7776                         foreach (Argument a in Arguments){
7777                                 if (!a.Resolve (ec, loc))
7778                                         return false;
7779                         }
7780
7781                         return Expr != null;
7782                 }
7783
7784                 public override Expression CreateExpressionTree (EmitContext ec)
7785                 {
7786                         ArrayList args = new ArrayList (Arguments.Count + 1);
7787                         args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7788                         foreach (Argument a in Arguments)
7789                                 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7790
7791                         return CreateExpressionFactoryCall ("ArrayIndex", args);
7792                 }
7793
7794                 Expression MakePointerAccess (EmitContext ec, Type t)
7795                 {
7796                         if (Arguments.Count != 1){
7797                                 Error (196, "A pointer must be indexed by only one value");
7798                                 return null;
7799                         }
7800
7801                         Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7802                         if (p == null)
7803                                 return null;
7804                         return new Indirection (p, loc).Resolve (ec);
7805                 }
7806                 
7807                 public override Expression DoResolve (EmitContext ec)
7808                 {
7809                         if (!CommonResolve (ec))
7810                                 return null;
7811
7812                         //
7813                         // We perform some simple tests, and then to "split" the emit and store
7814                         // code we create an instance of a different class, and return that.
7815                         //
7816                         // I am experimenting with this pattern.
7817                         //
7818                         Type t = Expr.Type;
7819
7820                         if (t == TypeManager.array_type){
7821                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7822                                 return null;
7823                         }
7824                         
7825                         if (t.IsArray)
7826                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7827                         if (t.IsPointer)
7828                                 return MakePointerAccess (ec, t);
7829
7830                         FieldExpr fe = Expr as FieldExpr;
7831                         if (fe != null) {
7832                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7833                                 if (ff != null) {
7834                                         return MakePointerAccess (ec, ff.ElementType);
7835                                 }
7836                         }
7837                         return (new IndexerAccess (this, loc)).Resolve (ec);
7838                 }
7839
7840                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7841                 {
7842                         if (!CommonResolve (ec))
7843                                 return null;
7844
7845                         type = Expr.Type;
7846                         if (type.IsArray)
7847                                 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7848
7849                         if (type.IsPointer)
7850                                 return MakePointerAccess (ec, type);
7851
7852                         if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7853                                 Error_CannotModifyIntermediateExpressionValue (ec);
7854
7855                         return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7856                 }
7857                 
7858                 public override void Emit (EmitContext ec)
7859                 {
7860                         throw new Exception ("Should never be reached");
7861                 }
7862
7863                 public override string GetSignatureForError ()
7864                 {
7865                         return Expr.GetSignatureForError ();
7866                 }
7867
7868                 protected override void CloneTo (CloneContext clonectx, Expression t)
7869                 {
7870                         ElementAccess target = (ElementAccess) t;
7871
7872                         target.Expr = Expr.Clone (clonectx);
7873                         target.Arguments = new ArrayList (Arguments.Count);
7874                         foreach (Argument a in Arguments)
7875                                 target.Arguments.Add (a.Clone (clonectx));
7876                 }
7877         }
7878
7879         /// <summary>
7880         ///   Implements array access 
7881         /// </summary>
7882         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7883                 //
7884                 // Points to our "data" repository
7885                 //
7886                 ElementAccess ea;
7887
7888                 LocalTemporary temp;
7889
7890                 bool prepared;
7891                 
7892                 public ArrayAccess (ElementAccess ea_data, Location l)
7893                 {
7894                         ea = ea_data;
7895                         loc = l;
7896                 }
7897
7898                 public override Expression CreateExpressionTree (EmitContext ec)
7899                 {
7900                         return ea.CreateExpressionTree (ec);
7901                 }
7902
7903                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7904                 {
7905                         return DoResolve (ec);
7906                 }
7907
7908                 public override Expression DoResolve (EmitContext ec)
7909                 {
7910 #if false
7911                         ExprClass eclass = ea.Expr.eclass;
7912
7913                         // As long as the type is valid
7914                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7915                               eclass == ExprClass.Value)) {
7916                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7917                                 return null;
7918                         }
7919 #endif
7920
7921                         if (eclass != ExprClass.Invalid)
7922                                 return this;
7923
7924                         Type t = ea.Expr.Type;
7925                         int rank = ea.Arguments.Count;
7926                         if (t.GetArrayRank () != rank) {
7927                                 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7928                                           ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7929                                 return null;
7930                         }
7931
7932                         type = TypeManager.GetElementType (t);
7933                         if (type.IsPointer && !ec.InUnsafe) {
7934                                 UnsafeError (ea.Location);
7935                                 return null;
7936                         }
7937
7938                         foreach (Argument a in ea.Arguments) {
7939                                 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7940                         }
7941                         
7942                         eclass = ExprClass.Variable;
7943
7944                         return this;
7945                 }
7946
7947                 /// <summary>
7948                 ///    Emits the right opcode to load an object of Type `t'
7949                 ///    from an array of T
7950                 /// </summary>
7951                 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7952                 {
7953                         if (rank > 1) {
7954                                 MethodInfo get = FetchGetMethod ();
7955                                 ig.Emit (OpCodes.Call, get);
7956                                 return;
7957                         }
7958
7959                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7960                                 ig.Emit (OpCodes.Ldelem_U1);
7961                         else if (type == TypeManager.sbyte_type)
7962                                 ig.Emit (OpCodes.Ldelem_I1);
7963                         else if (type == TypeManager.short_type)
7964                                 ig.Emit (OpCodes.Ldelem_I2);
7965                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7966                                 ig.Emit (OpCodes.Ldelem_U2);
7967                         else if (type == TypeManager.int32_type)
7968                                 ig.Emit (OpCodes.Ldelem_I4);
7969                         else if (type == TypeManager.uint32_type)
7970                                 ig.Emit (OpCodes.Ldelem_U4);
7971                         else if (type == TypeManager.uint64_type)
7972                                 ig.Emit (OpCodes.Ldelem_I8);
7973                         else if (type == TypeManager.int64_type)
7974                                 ig.Emit (OpCodes.Ldelem_I8);
7975                         else if (type == TypeManager.float_type)
7976                                 ig.Emit (OpCodes.Ldelem_R4);
7977                         else if (type == TypeManager.double_type)
7978                                 ig.Emit (OpCodes.Ldelem_R8);
7979                         else if (type == TypeManager.intptr_type)
7980                                 ig.Emit (OpCodes.Ldelem_I);
7981                         else if (TypeManager.IsEnumType (type)){
7982                                 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7983                         } else if (type.IsValueType){
7984                                 ig.Emit (OpCodes.Ldelema, type);
7985                                 ig.Emit (OpCodes.Ldobj, type);
7986 #if GMCS_SOURCE
7987                         } else if (type.IsGenericParameter) {
7988                                 ig.Emit (OpCodes.Ldelem, type);
7989 #endif
7990                         } else if (type.IsPointer)
7991                                 ig.Emit (OpCodes.Ldelem_I);
7992                         else
7993                                 ig.Emit (OpCodes.Ldelem_Ref);
7994                 }
7995
7996                 protected override void Error_NegativeArrayIndex (Location loc)
7997                 {
7998                         Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7999                 }
8000
8001                 /// <summary>
8002                 ///    Returns the right opcode to store an object of Type `t'
8003                 ///    from an array of T.  
8004                 /// </summary>
8005                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8006                 {
8007                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
8008                         has_type_arg = false; is_stobj = false;
8009                         t = TypeManager.TypeToCoreType (t);
8010                         if (TypeManager.IsEnumType (t))
8011                                 t = TypeManager.GetEnumUnderlyingType (t);
8012                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8013                             t == TypeManager.bool_type)
8014                                 return OpCodes.Stelem_I1;
8015                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8016                                  t == TypeManager.char_type)
8017                                 return OpCodes.Stelem_I2;
8018                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8019                                 return OpCodes.Stelem_I4;
8020                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8021                                 return OpCodes.Stelem_I8;
8022                         else if (t == TypeManager.float_type)
8023                                 return OpCodes.Stelem_R4;
8024                         else if (t == TypeManager.double_type)
8025                                 return OpCodes.Stelem_R8;
8026                         else if (t == TypeManager.intptr_type) {
8027                                 has_type_arg = true;
8028                                 is_stobj = true;
8029                                 return OpCodes.Stobj;
8030                         } else if (t.IsValueType) {
8031                                 has_type_arg = true;
8032                                 is_stobj = true;
8033                                 return OpCodes.Stobj;
8034 #if GMCS_SOURCE
8035                         } else if (t.IsGenericParameter) {
8036                                 has_type_arg = true;
8037                                 return OpCodes.Stelem;
8038 #endif
8039
8040                         } else if (t.IsPointer)
8041                                 return OpCodes.Stelem_I;
8042                         else
8043                                 return OpCodes.Stelem_Ref;
8044                 }
8045
8046                 MethodInfo FetchGetMethod ()
8047                 {
8048                         ModuleBuilder mb = CodeGen.Module.Builder;
8049                         int arg_count = ea.Arguments.Count;
8050                         Type [] args = new Type [arg_count];
8051                         MethodInfo get;
8052                         
8053                         for (int i = 0; i < arg_count; i++){
8054                                 //args [i++] = a.Type;
8055                                 args [i] = TypeManager.int32_type;
8056                         }
8057                         
8058                         get = mb.GetArrayMethod (
8059                                 ea.Expr.Type, "Get",
8060                                 CallingConventions.HasThis |
8061                                 CallingConventions.Standard,
8062                                 type, args);
8063                         return get;
8064                 }
8065                                 
8066
8067                 MethodInfo FetchAddressMethod ()
8068                 {
8069                         ModuleBuilder mb = CodeGen.Module.Builder;
8070                         int arg_count = ea.Arguments.Count;
8071                         Type [] args = new Type [arg_count];
8072                         MethodInfo address;
8073                         Type ret_type;
8074                         
8075                         ret_type = TypeManager.GetReferenceType (type);
8076                         
8077                         for (int i = 0; i < arg_count; i++){
8078                                 //args [i++] = a.Type;
8079                                 args [i] = TypeManager.int32_type;
8080                         }
8081                         
8082                         address = mb.GetArrayMethod (
8083                                 ea.Expr.Type, "Address",
8084                                 CallingConventions.HasThis |
8085                                 CallingConventions.Standard,
8086                                 ret_type, args);
8087
8088                         return address;
8089                 }
8090
8091                 //
8092                 // Load the array arguments into the stack.
8093                 //
8094                 void LoadArrayAndArguments (EmitContext ec)
8095                 {
8096                         ea.Expr.Emit (ec);
8097
8098                         for (int i = 0; i < ea.Arguments.Count; ++i) {
8099                                 ((Argument)ea.Arguments [i]).Emit (ec);
8100                         }
8101                 }
8102
8103                 public void Emit (EmitContext ec, bool leave_copy)
8104                 {
8105                         int rank = ea.Expr.Type.GetArrayRank ();
8106                         ILGenerator ig = ec.ig;
8107
8108                         if (prepared) {
8109                                 LoadFromPtr (ig, this.type);
8110                         } else {
8111                                 LoadArrayAndArguments (ec);
8112                                 EmitLoadOpcode (ig, type, rank);
8113                         }       
8114
8115                         if (leave_copy) {
8116                                 ig.Emit (OpCodes.Dup);
8117                                 temp = new LocalTemporary (this.type);
8118                                 temp.Store (ec);
8119                         }
8120                 }
8121                 
8122                 public override void Emit (EmitContext ec)
8123                 {
8124                         Emit (ec, false);
8125                 }
8126
8127                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8128                 {
8129                         int rank = ea.Expr.Type.GetArrayRank ();
8130                         ILGenerator ig = ec.ig;
8131                         Type t = source.Type;
8132                         prepared = prepare_for_load;
8133
8134                         if (prepared) {
8135                                 AddressOf (ec, AddressOp.LoadStore);
8136                                 ec.ig.Emit (OpCodes.Dup);
8137                         } else {
8138                                 LoadArrayAndArguments (ec);
8139                         }
8140
8141                         if (rank == 1) {
8142                                 bool is_stobj, has_type_arg;
8143                                 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8144
8145                                 if (!prepared) {
8146                                         //
8147                                         // The stobj opcode used by value types will need
8148                                         // an address on the stack, not really an array/array
8149                                         // pair
8150                                         //
8151                                         if (is_stobj)
8152                                                 ig.Emit (OpCodes.Ldelema, t);
8153                                 }
8154                                 
8155                                 source.Emit (ec);
8156                                 if (leave_copy) {
8157                                         ec.ig.Emit (OpCodes.Dup);
8158                                         temp = new LocalTemporary (this.type);
8159                                         temp.Store (ec);
8160                                 }
8161                                 
8162                                 if (prepared)
8163                                         StoreFromPtr (ig, t);
8164                                 else if (is_stobj)
8165                                         ig.Emit (OpCodes.Stobj, t);
8166                                 else if (has_type_arg)
8167                                         ig.Emit (op, t);
8168                                 else
8169                                         ig.Emit (op);
8170                         } else {
8171                                 source.Emit (ec);
8172                                 if (leave_copy) {
8173                                         ec.ig.Emit (OpCodes.Dup);
8174                                         temp = new LocalTemporary (this.type);
8175                                         temp.Store (ec);
8176                                 }
8177
8178                                 if (prepared) {
8179                                         StoreFromPtr (ig, t);
8180                                 } else {
8181                                         int arg_count = ea.Arguments.Count;
8182                                         Type [] args = new Type [arg_count + 1];
8183                                         for (int i = 0; i < arg_count; i++) {
8184                                                 //args [i++] = a.Type;
8185                                                 args [i] = TypeManager.int32_type;
8186                                         }
8187                                         args [arg_count] = type;
8188
8189                                         MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8190                                                 ea.Expr.Type, "Set",
8191                                                 CallingConventions.HasThis |
8192                                                 CallingConventions.Standard,
8193                                                 TypeManager.void_type, args);
8194
8195                                         ig.Emit (OpCodes.Call, set);
8196                                 }
8197                         }
8198                         
8199                         if (temp != null) {
8200                                 temp.Emit (ec);
8201                                 temp.Release (ec);
8202                         }
8203                 }
8204
8205                 public void AddressOf (EmitContext ec, AddressOp mode)
8206                 {
8207                         int rank = ea.Expr.Type.GetArrayRank ();
8208                         ILGenerator ig = ec.ig;
8209
8210                         LoadArrayAndArguments (ec);
8211
8212                         if (rank == 1){
8213                                 ig.Emit (OpCodes.Ldelema, type);
8214                         } else {
8215                                 MethodInfo address = FetchAddressMethod ();
8216                                 ig.Emit (OpCodes.Call, address);
8217                         }
8218                 }
8219
8220                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8221                 {
8222                         type = storey.MutateType (type);
8223                         ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8224                 }
8225         }
8226
8227         /// <summary>
8228         ///   Expressions that represent an indexer call.
8229         /// </summary>
8230         public class IndexerAccess : Expression, IAssignMethod
8231         {
8232                 class IndexerMethodGroupExpr : MethodGroupExpr
8233                 {
8234                         public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8235                                 : base (null, loc)
8236                         {
8237                                 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8238                         }
8239
8240                         public override string Name {
8241                                 get {
8242                                         return "this";
8243                                 }
8244                         }
8245
8246                         protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8247                         {
8248                                 //
8249                                 // Here is the trick, decrease number of arguments by 1 when only
8250                                 // available property method is setter. This makes overload resolution
8251                                 // work correctly for indexers.
8252                                 //
8253                                 
8254                                 if (method.Name [0] == 'g')
8255                                         return parameters.Count;
8256
8257                                 return parameters.Count - 1;
8258                         }
8259                 }
8260
8261                 class Indexers
8262                 {
8263                         // Contains either property getter or setter
8264                         public ArrayList Methods;
8265                         public ArrayList Properties;
8266
8267                         Indexers ()
8268                         {
8269                         }
8270
8271                         void Append (Type caller_type, MemberInfo [] mi)
8272                         {
8273                                 if (mi == null)
8274                                         return;
8275
8276                                 foreach (PropertyInfo property in mi) {
8277                                         MethodInfo accessor = property.GetGetMethod (true);
8278                                         if (accessor == null)
8279                                                 accessor = property.GetSetMethod (true);
8280
8281                                         if (Methods == null) {
8282                                                 Methods = new ArrayList ();
8283                                                 Properties = new ArrayList ();
8284                                         }
8285
8286                                         Methods.Add (accessor);
8287                                         Properties.Add (property);
8288                                 }
8289                         }
8290
8291                         static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8292                         {
8293                                 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8294
8295                                 return TypeManager.MemberLookup (
8296                                         caller_type, caller_type, lookup_type, MemberTypes.Property,
8297                                         BindingFlags.Public | BindingFlags.Instance |
8298                                         BindingFlags.DeclaredOnly, p_name, null);
8299                         }
8300                         
8301                         public static Indexers GetIndexersForType (Type caller_type, Type lookup_type) 
8302                         {
8303                                 Indexers ix = new Indexers ();
8304
8305         #if GMCS_SOURCE
8306                                 if (lookup_type.IsGenericParameter) {
8307                                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8308                                         if (gc == null)
8309                                                 return ix;
8310
8311                                         if (gc.HasClassConstraint)
8312                                                 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8313
8314                                         Type[] ifaces = gc.InterfaceConstraints;
8315                                         foreach (Type itype in ifaces)
8316                                                 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8317
8318                                         return ix;
8319                                 }
8320         #endif
8321
8322                                 Type copy = lookup_type;
8323                                 while (copy != TypeManager.object_type && copy != null){
8324                                         ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8325                                         copy = copy.BaseType;
8326                                 }
8327
8328                                 if (lookup_type.IsInterface) {
8329                                         Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8330                                         if (ifaces != null) {
8331                                                 foreach (Type itype in ifaces)
8332                                                         ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8333                                         }
8334                                 }
8335
8336                                 return ix;
8337                         }
8338                 }
8339
8340                 enum AccessorType
8341                 {
8342                         Get,
8343                         Set
8344                 }
8345
8346                 //
8347                 // Points to our "data" repository
8348                 //
8349                 MethodInfo get, set;
8350                 bool is_base_indexer;
8351                 bool prepared;
8352                 LocalTemporary temp;
8353                 LocalTemporary prepared_value;
8354                 Expression set_expr;
8355
8356                 protected Type indexer_type;
8357                 protected Type current_type;
8358                 protected Expression instance_expr;
8359                 protected ArrayList arguments;
8360                 
8361                 public IndexerAccess (ElementAccess ea, Location loc)
8362                         : this (ea.Expr, false, loc)
8363                 {
8364                         this.arguments = ea.Arguments;
8365                 }
8366
8367                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8368                                          Location loc)
8369                 {
8370                         this.instance_expr = instance_expr;
8371                         this.is_base_indexer = is_base_indexer;
8372                         this.eclass = ExprClass.Value;
8373                         this.loc = loc;
8374                 }
8375
8376                 static string GetAccessorName (AccessorType at)
8377                 {
8378                         if (at == AccessorType.Set)
8379                                 return "set";
8380
8381                         if (at == AccessorType.Get)
8382                                 return "get";
8383
8384                         throw new NotImplementedException (at.ToString ());
8385                 }
8386
8387                 public override Expression CreateExpressionTree (EmitContext ec)
8388                 {
8389                         ArrayList args = new ArrayList (arguments.Count + 2);
8390                         args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8391                         args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8392                         foreach (Argument a in arguments)
8393                                 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8394
8395                         return CreateExpressionFactoryCall ("Call", args);
8396                 }
8397
8398                 protected virtual bool CommonResolve (EmitContext ec)
8399                 {
8400                         indexer_type = instance_expr.Type;
8401                         current_type = ec.ContainerType;
8402
8403                         return true;
8404                 }
8405
8406                 public override Expression DoResolve (EmitContext ec)
8407                 {
8408                         return ResolveAccessor (ec, AccessorType.Get);
8409                 }
8410
8411                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8412                 {
8413                         if (right_side == EmptyExpression.OutAccess) {
8414                                 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8415                                               GetSignatureForError ());
8416                                 return null;
8417                         }
8418
8419                         // if the indexer returns a value type, and we try to set a field in it
8420                         if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8421                                 Error_CannotModifyIntermediateExpressionValue (ec);
8422                         }
8423
8424                         Expression e = ResolveAccessor (ec, AccessorType.Set);
8425                         if (e == null)
8426                                 return null;
8427
8428                         set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8429                         return e;
8430                 }
8431
8432                 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8433                 {
8434                         if (!CommonResolve (ec))
8435                                 return null;
8436
8437                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8438                         if (ilist.Methods == null) {
8439                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8440                                                   TypeManager.CSharpName (indexer_type));
8441                                 return null;
8442                         }
8443
8444                         MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8445                         mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8446                         if (mg == null)
8447                                 return null;
8448
8449                         MethodInfo mi = (MethodInfo) mg;
8450                         PropertyInfo pi = null;
8451                         for (int i = 0; i < ilist.Methods.Count; ++i) {
8452                                 if (ilist.Methods [i] == mi) {
8453                                         pi = (PropertyInfo) ilist.Properties [i];
8454                                         break;
8455                                 }
8456                         }
8457
8458                         type = TypeManager.TypeToCoreType (pi.PropertyType);
8459                         if (type.IsPointer && !ec.InUnsafe)
8460                                 UnsafeError (loc);
8461
8462                         MethodInfo accessor;
8463                         if (accessorType == AccessorType.Get) {
8464                                 accessor = get = pi.GetGetMethod (true);
8465                         } else {
8466                                 accessor = set = pi.GetSetMethod (true);
8467                                 if (accessor == null && pi.GetGetMethod (true) != null) {
8468                                         Report.SymbolRelatedToPreviousError (pi);
8469                                         Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8470                                                 TypeManager.GetFullNameSignature (pi));
8471                                         return null;
8472                                 }
8473                         }
8474
8475                         if (accessor == null) {
8476                                 Report.SymbolRelatedToPreviousError (pi);
8477                                 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8478                                         TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8479                                 return null;
8480                         }
8481
8482                         //
8483                         // Only base will allow this invocation to happen.
8484                         //
8485                         if (accessor.IsAbstract && this is BaseIndexerAccess) {
8486                                 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8487                         }
8488
8489                         bool must_do_cs1540_check;
8490                         if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8491                                 if (set == null)
8492                                         set = pi.GetSetMethod (true);
8493                                 else
8494                                         get = pi.GetGetMethod (true);
8495
8496                                 if (set != null && get != null &&
8497                                         (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8498                                         Report.SymbolRelatedToPreviousError (accessor);
8499                                         Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8500                                                 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8501                                 } else {
8502                                         Report.SymbolRelatedToPreviousError (pi);
8503                                         ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8504                                 }
8505                         }
8506
8507                         instance_expr.CheckMarshalByRefAccess (ec);
8508                         eclass = ExprClass.IndexerAccess;
8509                         return this;
8510                 }
8511                 
8512                 public void Emit (EmitContext ec, bool leave_copy)
8513                 {
8514                         if (prepared) {
8515                                 prepared_value.Emit (ec);
8516                         } else {
8517                                 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8518                                         arguments, loc, false, false);
8519                         }
8520
8521                         if (leave_copy) {
8522                                 ec.ig.Emit (OpCodes.Dup);
8523                                 temp = new LocalTemporary (Type);
8524                                 temp.Store (ec);
8525                         }
8526                 }
8527                 
8528                 //
8529                 // source is ignored, because we already have a copy of it from the
8530                 // LValue resolution and we have already constructed a pre-cached
8531                 // version of the arguments (ea.set_arguments);
8532                 //
8533                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8534                 {
8535                         prepared = prepare_for_load;
8536                         Expression value = set_expr;
8537
8538                         if (prepared) {
8539                                 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8540                                         arguments, loc, true, false);
8541
8542                                 prepared_value = new LocalTemporary (type);
8543                                 prepared_value.Store (ec);
8544                                 source.Emit (ec);
8545                                 prepared_value.Release (ec);
8546
8547                                 if (leave_copy) {
8548                                         ec.ig.Emit (OpCodes.Dup);
8549                                         temp = new LocalTemporary (Type);
8550                                         temp.Store (ec);
8551                                 }
8552                         } else if (leave_copy) {
8553                                 temp = new LocalTemporary (Type);
8554                                 source.Emit (ec);
8555                                 temp.Store (ec);
8556                                 value = temp;
8557                         }
8558                         
8559                         arguments.Add (new Argument (value, Argument.AType.Expression));
8560                         Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8561                         
8562                         if (temp != null) {
8563                                 temp.Emit (ec);
8564                                 temp.Release (ec);
8565                         }
8566                 }
8567                 
8568                 public override void Emit (EmitContext ec)
8569                 {
8570                         Emit (ec, false);
8571                 }
8572
8573                 public override string GetSignatureForError ()
8574                 {
8575                         return TypeManager.CSharpSignature (get != null ? get : set, false);
8576                 }
8577
8578                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8579                 {
8580                         if (get != null)
8581                                 get = storey.MutateGenericMethod (get);
8582                         if (set != null)
8583                                 set = storey.MutateGenericMethod (set);
8584
8585                         instance_expr.MutateHoistedGenericType (storey);
8586                         foreach (Argument a in arguments)
8587                                 a.Expr.MutateHoistedGenericType (storey);
8588
8589                         type = storey.MutateType (type);
8590                 }
8591
8592                 protected override void CloneTo (CloneContext clonectx, Expression t)
8593                 {
8594                         IndexerAccess target = (IndexerAccess) t;
8595
8596                         if (arguments != null){
8597                                 target.arguments = new ArrayList ();
8598                                 foreach (Argument a in arguments)
8599                                         target.arguments.Add (a.Clone (clonectx));
8600                         }
8601                         if (instance_expr != null)
8602                                 target.instance_expr = instance_expr.Clone (clonectx);
8603                 }
8604         }
8605
8606         /// <summary>
8607         ///   The base operator for method names
8608         /// </summary>
8609         public class BaseAccess : Expression {
8610                 public readonly string Identifier;
8611                 TypeArguments args;
8612
8613                 public BaseAccess (string member, Location l)
8614                 {
8615                         this.Identifier = member;
8616                         loc = l;
8617                 }
8618
8619                 public BaseAccess (string member, TypeArguments args, Location l)
8620                         : this (member, l)
8621                 {
8622                         this.args = args;
8623                 }
8624
8625                 public override Expression CreateExpressionTree (EmitContext ec)
8626                 {
8627                         throw new NotSupportedException ("ET");
8628                 }
8629
8630                 public override Expression DoResolve (EmitContext ec)
8631                 {
8632                         Expression c = CommonResolve (ec);
8633
8634                         if (c == null)
8635                                 return null;
8636
8637                         //
8638                         // MethodGroups use this opportunity to flag an error on lacking ()
8639                         //
8640                         if (!(c is MethodGroupExpr))
8641                                 return c.Resolve (ec);
8642                         return c;
8643                 }
8644
8645                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8646                 {
8647                         Expression c = CommonResolve (ec);
8648
8649                         if (c == null)
8650                                 return null;
8651
8652                         //
8653                         // MethodGroups use this opportunity to flag an error on lacking ()
8654                         //
8655                         if (! (c is MethodGroupExpr))
8656                                 return c.DoResolveLValue (ec, right_side);
8657
8658                         return c;
8659                 }
8660
8661                 Expression CommonResolve (EmitContext ec)
8662                 {
8663                         Expression member_lookup;
8664                         Type current_type = ec.ContainerType;
8665                         Type base_type = current_type.BaseType;
8666
8667                         if (!This.IsThisAvailable (ec)) {
8668                                 if (ec.IsStatic) {
8669                                         Error (1511, "Keyword `base' is not available in a static method");
8670                                 } else {
8671                                         Error (1512, "Keyword `base' is not available in the current context");
8672                                 }
8673                                 return null;
8674                         }
8675                         
8676                         member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8677                                                       AllMemberTypes, AllBindingFlags, loc);
8678                         if (member_lookup == null) {
8679                                 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8680                                         null, AllMemberTypes, AllBindingFlags);
8681                                 return null;
8682                         }
8683
8684                         Expression left;
8685                         
8686                         if (ec.IsStatic)
8687                                 left = new TypeExpression (base_type, loc);
8688                         else
8689                                 left = ec.GetThis (loc);
8690
8691                         MemberExpr me = (MemberExpr) member_lookup;
8692                         me = me.ResolveMemberAccess (ec, left, loc, null);
8693                         if (me == null)
8694                                 return null;
8695
8696                         me.IsBase = true;
8697                         if (args != null) {
8698                                 args.Resolve (ec);
8699                                 me.SetTypeArguments (args);
8700                         }
8701
8702                         return me;
8703                 }
8704
8705                 public override void Emit (EmitContext ec)
8706                 {
8707                         throw new Exception ("Should never be called"); 
8708                 }
8709
8710                 protected override void CloneTo (CloneContext clonectx, Expression t)
8711                 {
8712                         BaseAccess target = (BaseAccess) t;
8713
8714                         if (args != null)
8715                                 target.args = args.Clone ();
8716                 }
8717         }
8718
8719         /// <summary>
8720         ///   The base indexer operator
8721         /// </summary>
8722         public class BaseIndexerAccess : IndexerAccess {
8723                 public BaseIndexerAccess (ArrayList args, Location loc)
8724                         : base (null, true, loc)
8725                 {
8726                         arguments = new ArrayList ();
8727                         foreach (Expression tmp in args)
8728                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8729                 }
8730
8731                 protected override bool CommonResolve (EmitContext ec)
8732                 {
8733                         instance_expr = ec.GetThis (loc);
8734
8735                         current_type = ec.ContainerType.BaseType;
8736                         indexer_type = current_type;
8737
8738                         foreach (Argument a in arguments){
8739                                 if (!a.Resolve (ec, loc))
8740                                         return false;
8741                         }
8742
8743                         return true;
8744                 }
8745
8746                 public override Expression CreateExpressionTree (EmitContext ec)
8747                 {
8748                         MemberExpr.Error_BaseAccessInExpressionTree (loc);
8749                         return base.CreateExpressionTree (ec);
8750                 }
8751         }
8752         
8753         /// <summary>
8754         ///   This class exists solely to pass the Type around and to be a dummy
8755         ///   that can be passed to the conversion functions (this is used by
8756         ///   foreach implementation to typecast the object return value from
8757         ///   get_Current into the proper type.  All code has been generated and
8758         ///   we only care about the side effect conversions to be performed
8759         ///
8760         ///   This is also now used as a placeholder where a no-action expression
8761         ///   is needed (the `New' class).
8762         /// </summary>
8763         public class EmptyExpression : Expression {
8764                 public static readonly Expression Null = new EmptyExpression ();
8765
8766                 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8767                 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8768                 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8769                 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8770
8771                 static EmptyExpression temp = new EmptyExpression ();
8772                 public static EmptyExpression Grab ()
8773                 {
8774                         EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8775                         temp = null;
8776                         return retval;
8777                 }
8778
8779                 public static void Release (EmptyExpression e)
8780                 {
8781                         temp = e;
8782                 }
8783
8784                 // TODO: should be protected
8785                 public EmptyExpression ()
8786                 {
8787                         type = TypeManager.object_type;
8788                         eclass = ExprClass.Value;
8789                         loc = Location.Null;
8790                 }
8791
8792                 public EmptyExpression (Type t)
8793                 {
8794                         type = t;
8795                         eclass = ExprClass.Value;
8796                         loc = Location.Null;
8797                 }
8798
8799                 public override Expression CreateExpressionTree (EmitContext ec)
8800                 {
8801                         throw new NotSupportedException ("ET");
8802                 }
8803                 
8804                 public override Expression DoResolve (EmitContext ec)
8805                 {
8806                         return this;
8807                 }
8808
8809                 public override void Emit (EmitContext ec)
8810                 {
8811                         // nothing, as we only exist to not do anything.
8812                 }
8813
8814                 public override void EmitSideEffect (EmitContext ec)
8815                 {
8816                 }
8817
8818                 //
8819                 // This is just because we might want to reuse this bad boy
8820                 // instead of creating gazillions of EmptyExpressions.
8821                 // (CanImplicitConversion uses it)
8822                 //
8823                 public void SetType (Type t)
8824                 {
8825                         type = t;
8826                 }
8827         }
8828         
8829         //
8830         // Empty statement expression
8831         //
8832         public sealed class EmptyExpressionStatement : ExpressionStatement
8833         {
8834                 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8835
8836                 private EmptyExpressionStatement ()
8837                 {
8838                         type = TypeManager.object_type;
8839                         eclass = ExprClass.Value;
8840                         loc = Location.Null;
8841                 }
8842
8843                 public override Expression CreateExpressionTree (EmitContext ec)
8844                 {
8845                         return null;
8846                 }
8847
8848                 public override void EmitStatement (EmitContext ec)
8849                 {
8850                         // Do nothing
8851                 }
8852
8853                 public override Expression DoResolve (EmitContext ec)
8854                 {
8855                         return this;
8856                 }
8857
8858                 public override void Emit (EmitContext ec)
8859                 {
8860                         // Do nothing
8861                 }
8862         }       
8863
8864         public class UserCast : Expression {
8865                 MethodInfo method;
8866                 Expression source;
8867                 
8868                 public UserCast (MethodInfo method, Expression source, Location l)
8869                 {
8870                         this.method = method;
8871                         this.source = source;
8872                         type = TypeManager.TypeToCoreType (method.ReturnType);
8873                         loc = l;
8874                 }
8875
8876                 public Expression Source {
8877                         get {
8878                                 return source;
8879                         }
8880                 }
8881
8882                 public override Expression CreateExpressionTree (EmitContext ec)
8883                 {
8884                         ArrayList args = new ArrayList (3);
8885                         args.Add (new Argument (source.CreateExpressionTree (ec)));
8886                         args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8887                         args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8888                         return CreateExpressionFactoryCall ("Convert", args);
8889                 }
8890                         
8891                 public override Expression DoResolve (EmitContext ec)
8892                 {
8893                         ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
8894                         if (oa != null)
8895                                 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
8896
8897                         eclass = ExprClass.Value;
8898                         return this;
8899                 }
8900
8901                 public override void Emit (EmitContext ec)
8902                 {
8903                         source.Emit (ec);
8904                         ec.ig.Emit (OpCodes.Call, method);
8905                 }
8906
8907                 public override string GetSignatureForError ()
8908                 {
8909                         return TypeManager.CSharpSignature (method);
8910                 }
8911
8912                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8913                 {
8914                         source.MutateHoistedGenericType (storey);
8915                         method = storey.MutateGenericMethod (method);
8916                 }
8917         }
8918
8919         // <summary>
8920         //   This class is used to "construct" the type during a typecast
8921         //   operation.  Since the Type.GetType class in .NET can parse
8922         //   the type specification, we just use this to construct the type
8923         //   one bit at a time.
8924         // </summary>
8925         public class ComposedCast : TypeExpr {
8926                 FullNamedExpression left;
8927                 string dim;
8928                 
8929                 public ComposedCast (FullNamedExpression left, string dim)
8930                         : this (left, dim, left.Location)
8931                 {
8932                 }
8933
8934                 public ComposedCast (FullNamedExpression left, string dim, Location l)
8935                 {
8936                         this.left = left;
8937                         this.dim = dim;
8938                         loc = l;
8939                 }
8940
8941                 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8942                 {
8943                         TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8944                         if (lexpr == null)
8945                                 return null;
8946
8947                         Type ltype = lexpr.Type;
8948 #if GMCS_SOURCE
8949                         if ((dim.Length > 0) && (dim [0] == '?')) {
8950                                 TypeExpr nullable = new Nullable.NullableType (left, loc);
8951                                 if (dim.Length > 1)
8952                                         nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8953                                 return nullable.ResolveAsTypeTerminal (ec, false);
8954                         }
8955 #endif
8956
8957                         if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8958                                 return null;
8959
8960                         if (dim.Length != 0 && dim [0] == '[') {
8961                                 if (TypeManager.IsSpecialType (ltype)) {
8962                                         Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8963                                         return null;
8964                                 }
8965
8966                                 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
8967                                         Report.SymbolRelatedToPreviousError (ltype);
8968                                         Report.Error (719, loc, "Array elements cannot be of static type `{0}'", 
8969                                                 TypeManager.CSharpName (ltype));
8970                                 }
8971                         }
8972
8973                         if (dim != "")
8974                                 type = TypeManager.GetConstructedType (ltype, dim);
8975                         else
8976                                 type = ltype;
8977
8978                         if (type == null)
8979                                 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8980
8981                         if (type.IsPointer && !ec.IsInUnsafeScope){
8982                                 UnsafeError (loc);
8983                         }
8984
8985                         eclass = ExprClass.Type;
8986                         return this;
8987                 }
8988
8989                 public override string GetSignatureForError ()
8990                 {
8991                         return left.GetSignatureForError () + dim;
8992                 }
8993
8994                 protected override void CloneTo (CloneContext clonectx, Expression t)
8995                 {
8996                         ComposedCast target = (ComposedCast) t;
8997
8998                         target.left = (FullNamedExpression)left.Clone (clonectx);
8999                 }
9000                 
9001                 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
9002                 {
9003                         return ResolveAsBaseTerminal (ec, silent);
9004                 }               
9005         }
9006
9007         public class FixedBufferPtr : Expression {
9008                 Expression array;
9009
9010                 public FixedBufferPtr (Expression array, Type array_type, Location l)
9011                 {
9012                         this.array = array;
9013                         this.loc = l;
9014
9015                         type = TypeManager.GetPointerType (array_type);
9016                         eclass = ExprClass.Value;
9017                 }
9018
9019                 public override Expression CreateExpressionTree (EmitContext ec)
9020                 {
9021                         Error_PointerInsideExpressionTree ();
9022                         return null;
9023                 }
9024
9025                 public override void Emit(EmitContext ec)
9026                 {
9027                         array.Emit (ec);
9028                 }
9029
9030                 public override Expression DoResolve (EmitContext ec)
9031                 {
9032                         //
9033                         // We are born fully resolved
9034                         //
9035                         return this;
9036                 }
9037         }
9038
9039
9040         //
9041         // This class is used to represent the address of an array, used
9042         // only by the Fixed statement, this generates "&a [0]" construct
9043         // for fixed (char *pa = a)
9044         //
9045         public class ArrayPtr : FixedBufferPtr {
9046                 Type array_type;
9047                 
9048                 public ArrayPtr (Expression array, Type array_type, Location l):
9049                         base (array, array_type, l)
9050                 {
9051                         this.array_type = array_type;
9052                 }
9053
9054                 public override void Emit (EmitContext ec)
9055                 {
9056                         base.Emit (ec);
9057                         
9058                         ILGenerator ig = ec.ig;
9059                         IntLiteral.EmitInt (ig, 0);
9060                         ig.Emit (OpCodes.Ldelema, array_type);
9061                 }
9062         }
9063
9064         //
9065         // Encapsulates a conversion rules required for array indexes
9066         //
9067         public class ArrayIndexCast : TypeCast
9068         {
9069                 public ArrayIndexCast (Expression expr)
9070                         : base (expr, expr.Type)
9071                 {
9072                 }
9073
9074                 public override Expression CreateExpressionTree (EmitContext ec)
9075                 {
9076                         ArrayList args = new ArrayList (2);
9077                         args.Add (new Argument (child.CreateExpressionTree (ec)));
9078                         args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9079                         return CreateExpressionFactoryCall ("ConvertChecked", args);
9080                 }
9081
9082                 public override void Emit (EmitContext ec)
9083                 {
9084                         child.Emit (ec);
9085                                 
9086                         if (type == TypeManager.int32_type)
9087                                 return;
9088
9089                         if (type == TypeManager.uint32_type)
9090                                 ec.ig.Emit (OpCodes.Conv_U);
9091                         else if (type == TypeManager.int64_type)
9092                                 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9093                         else if (type == TypeManager.uint64_type)
9094                                 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9095                         else
9096                                 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9097                 }
9098         }
9099
9100         //
9101         // Implements the `stackalloc' keyword
9102         //
9103         public class StackAlloc : Expression {
9104                 Type otype;
9105                 Expression t;
9106                 Expression count;
9107                 
9108                 public StackAlloc (Expression type, Expression count, Location l)
9109                 {
9110                         t = type;
9111                         this.count = count;
9112                         loc = l;
9113                 }
9114
9115                 public override Expression CreateExpressionTree (EmitContext ec)
9116                 {
9117                         throw new NotSupportedException ("ET");
9118                 }
9119
9120                 public override Expression DoResolve (EmitContext ec)
9121                 {
9122                         count = count.Resolve (ec);
9123                         if (count == null)
9124                                 return null;
9125                         
9126                         if (count.Type != TypeManager.uint32_type){
9127                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9128                                 if (count == null)
9129                                         return null;
9130                         }
9131
9132                         Constant c = count as Constant;
9133                         if (c != null && c.IsNegative) {
9134                                 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9135                                 return null;
9136                         }
9137
9138                         if (ec.InCatch || ec.InFinally) {
9139                                 Error (255, "Cannot use stackalloc in finally or catch");
9140                                 return null;
9141                         }
9142
9143                         TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9144                         if (texpr == null)
9145                                 return null;
9146
9147                         otype = texpr.Type;
9148
9149                         if (!TypeManager.VerifyUnManaged (otype, loc))
9150                                 return null;
9151
9152                         type = TypeManager.GetPointerType (otype);
9153                         eclass = ExprClass.Value;
9154
9155                         return this;
9156                 }
9157
9158                 public override void Emit (EmitContext ec)
9159                 {
9160                         int size = GetTypeSize (otype);
9161                         ILGenerator ig = ec.ig;
9162
9163                         count.Emit (ec);
9164
9165                         if (size == 0)
9166                                 ig.Emit (OpCodes.Sizeof, otype);
9167                         else
9168                                 IntConstant.EmitInt (ig, size);
9169
9170                         ig.Emit (OpCodes.Mul_Ovf_Un);
9171                         ig.Emit (OpCodes.Localloc);
9172                 }
9173
9174                 protected override void CloneTo (CloneContext clonectx, Expression t)
9175                 {
9176                         StackAlloc target = (StackAlloc) t;
9177                         target.count = count.Clone (clonectx);
9178                         target.t = t.Clone (clonectx);
9179                 }
9180         }
9181
9182         //
9183         // An object initializer expression
9184         //
9185         public class ElementInitializer : Assign
9186         {
9187                 public readonly string Name;
9188
9189                 public ElementInitializer (string name, Expression initializer, Location loc)
9190                         : base (null, initializer, loc)
9191                 {
9192                         this.Name = name;
9193                 }
9194                 
9195                 protected override void CloneTo (CloneContext clonectx, Expression t)
9196                 {
9197                         ElementInitializer target = (ElementInitializer) t;
9198                         target.source = source.Clone (clonectx);
9199                 }
9200
9201                 public override Expression CreateExpressionTree (EmitContext ec)
9202                 {
9203                         ArrayList args = new ArrayList (2);
9204                         FieldExpr fe = target as FieldExpr;
9205                         if (fe != null)
9206                                 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9207                         else
9208                                 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9209
9210                         args.Add (new Argument (source.CreateExpressionTree (ec)));
9211                         return CreateExpressionFactoryCall (
9212                                 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9213                                 args);
9214                 }
9215
9216                 public override Expression DoResolve (EmitContext ec)
9217                 {
9218                         if (source == null)
9219                                 return EmptyExpressionStatement.Instance;
9220                         
9221                         MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9222                                 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9223
9224                         if (me == null)
9225                                 return null;
9226
9227                         target = me;
9228                         me.InstanceExpression = ec.CurrentInitializerVariable;
9229
9230                         if (source is CollectionOrObjectInitializers) {
9231                                 Expression previous = ec.CurrentInitializerVariable;
9232                                 ec.CurrentInitializerVariable = target;
9233                                 source = source.Resolve (ec);
9234                                 ec.CurrentInitializerVariable = previous;
9235                                 if (source == null)
9236                                         return null;
9237                                         
9238                                 eclass = source.eclass;
9239                                 type = source.Type;
9240                                 return this;
9241                         }
9242
9243                         Expression expr = base.DoResolve (ec);
9244                         if (expr == null)
9245                                 return null;
9246
9247                         //
9248                         // Ignore field initializers with default value
9249                         //
9250                         Constant c = source as Constant;
9251                         if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9252                                 return EmptyExpressionStatement.Instance;
9253
9254                         return expr;
9255                 }
9256
9257                 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
9258                 {
9259                         MemberInfo member = members [0];
9260                         if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9261                                 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9262                                         "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9263                         else
9264                                 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9265                                         TypeManager.GetFullNameSignature (member));
9266
9267                         return null;
9268                 }
9269                 
9270                 public override void EmitStatement (EmitContext ec)
9271                 {
9272                         if (source is CollectionOrObjectInitializers)
9273                                 source.Emit (ec);
9274                         else
9275                                 base.EmitStatement (ec);
9276                 }
9277         }
9278         
9279         //
9280         // A collection initializer expression
9281         //
9282         public class CollectionElementInitializer : Invocation
9283         {
9284                 public class ElementInitializerArgument : Argument
9285                 {
9286                         public ElementInitializerArgument (Expression e)
9287                                 : base (e)
9288                         {
9289                         }
9290                 }
9291
9292                 sealed class AddMemberAccess : MemberAccess
9293                 {
9294                         public AddMemberAccess (Expression expr, Location loc)
9295                                 : base (expr, "Add", loc)
9296                         {
9297                         }
9298
9299                         protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
9300                         {
9301                                 if (TypeManager.HasElementType (type))
9302                                         return;
9303
9304                                 base.Error_TypeDoesNotContainDefinition (type, name);
9305                         }
9306                 }
9307
9308                 public CollectionElementInitializer (Expression argument)
9309                         : base (null, new ArrayList (1), true)
9310                 {
9311                         Arguments.Add (argument);
9312                         this.loc = argument.Location;
9313                 }
9314
9315                 public CollectionElementInitializer (ArrayList arguments, Location loc)
9316                         : base (null, arguments, true)
9317                 {
9318                         this.loc = loc;
9319                 }
9320
9321                 public override Expression CreateExpressionTree (EmitContext ec)
9322                 {
9323                         ArrayList args = new ArrayList (2);
9324                         args.Add (new Argument (mg.CreateExpressionTree (ec)));
9325
9326                         ArrayList expr_initializers = new ArrayList (Arguments.Count);
9327                         foreach (Argument a in Arguments)
9328                                 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9329
9330                         args.Add (new Argument (new ArrayCreation (
9331                                 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9332                         return CreateExpressionFactoryCall ("ElementInit", args);
9333                 }
9334
9335                 protected override void CloneTo (CloneContext clonectx, Expression t)
9336                 {
9337                         CollectionElementInitializer target = (CollectionElementInitializer) t;
9338
9339                         target.Arguments = new ArrayList (Arguments.Count);
9340                         foreach (Expression e in Arguments)
9341                                 target.Arguments.Add (e.Clone (clonectx));
9342                 }
9343
9344                 public override Expression DoResolve (EmitContext ec)
9345                 {
9346                         if (eclass != ExprClass.Invalid)
9347                                 return this;
9348
9349                         // TODO: We could call a constructor which takes element count argument,
9350                         // for known types like List<T>, Dictionary<T, U>
9351                         
9352                         for (int i = 0; i < Arguments.Count; ++i) {
9353                                 Expression expr = Arguments [i] as Expression;
9354                                 if (expr == null)
9355                                         return null;
9356
9357                                 expr = expr.Resolve (ec);
9358                                 if (expr == null)
9359                                         return null;
9360
9361                                 Arguments [i] = new ElementInitializerArgument (expr);
9362                         }
9363
9364                         base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9365
9366                         return base.DoResolve (ec);
9367                 }
9368         }
9369         
9370         //
9371         // A block of object or collection initializers
9372         //
9373         public class CollectionOrObjectInitializers : ExpressionStatement
9374         {
9375                 ArrayList initializers;
9376                 
9377                 public static readonly CollectionOrObjectInitializers Empty = 
9378                         new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9379
9380                 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9381                 {
9382                         this.initializers = initializers;
9383                         this.loc = loc;
9384                 }
9385                 
9386                 public bool IsEmpty {
9387                         get {
9388                                 return initializers.Count == 0;
9389                         }
9390                 }
9391
9392                 public bool IsCollectionInitializer {
9393                         get {
9394                                 return type == typeof (CollectionOrObjectInitializers);
9395                         }
9396                 }
9397
9398                 protected override void CloneTo (CloneContext clonectx, Expression target)
9399                 {
9400                         CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9401
9402                         t.initializers = new ArrayList (initializers.Count);
9403                         foreach (Expression e in initializers)
9404                                 t.initializers.Add (e.Clone (clonectx));
9405                 }
9406
9407                 public override Expression CreateExpressionTree (EmitContext ec)
9408                 {
9409                         ArrayList expr_initializers = new ArrayList (initializers.Count);
9410                         foreach (Expression e in initializers) {
9411                                 Expression expr = e.CreateExpressionTree (ec);
9412                                 if (expr != null)
9413                                         expr_initializers.Add (expr);
9414                         }
9415
9416                         return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9417                 }
9418                 
9419                 public override Expression DoResolve (EmitContext ec)
9420                 {
9421                         if (eclass != ExprClass.Invalid)
9422                                 return this;
9423
9424                         bool is_collection_initialization = false;
9425                         ArrayList element_names = null;
9426                         for (int i = 0; i < initializers.Count; ++i) {
9427                                 Expression initializer = (Expression) initializers [i];
9428                                 ElementInitializer element_initializer = initializer as ElementInitializer;
9429
9430                                 if (i == 0) {
9431                                         if (element_initializer != null) {
9432                                                 element_names = new ArrayList (initializers.Count);
9433                                                 element_names.Add (element_initializer.Name);
9434                                         } else {
9435                                                 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9436                                                         TypeManager.ienumerable_type)) {
9437                                                         Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9438                                                                 "object initializer because type `{1}' does not implement `{2}' interface",
9439                                                                 ec.CurrentInitializerVariable.GetSignatureForError (),
9440                                                                 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9441                                                                 TypeManager.CSharpName (TypeManager.ienumerable_type));
9442                                                         return null;
9443                                                 }
9444                                                 is_collection_initialization = true;
9445                                         }
9446                                 } else {
9447                                         if (is_collection_initialization != (element_initializer == null)) {
9448                                                 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9449                                                         is_collection_initialization ? "collection initializer" : "object initializer");
9450                                                 continue;
9451                                         }
9452
9453                                         if (!is_collection_initialization) {
9454                                                 if (element_names.Contains (element_initializer.Name)) {
9455                                                         Report.Error (1912, element_initializer.Location,
9456                                                                 "An object initializer includes more than one member `{0}' initialization",
9457                                                                 element_initializer.Name);
9458                                                 } else {
9459                                                         element_names.Add (element_initializer.Name);
9460                                                 }
9461                                         }
9462                                 }
9463
9464                                 Expression e = initializer.Resolve (ec);
9465                                 if (e == EmptyExpressionStatement.Instance)
9466                                         initializers.RemoveAt (i--);
9467                                 else
9468                                         initializers [i] = e;
9469                         }
9470
9471                         if (is_collection_initialization) {
9472                                 if (TypeManager.HasElementType (ec.CurrentInitializerVariable.Type)) {
9473                                         Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9474                                                 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type));
9475                                 }
9476
9477                                 type = typeof (CollectionOrObjectInitializers);
9478                         } else {
9479                                 type = typeof (ElementInitializer);
9480                         }
9481
9482                         eclass = ExprClass.Variable;
9483                         return this;
9484                 }
9485
9486                 public override void Emit (EmitContext ec)
9487                 {
9488                         EmitStatement (ec);
9489                 }
9490
9491                 public override void EmitStatement (EmitContext ec)
9492                 {
9493                         foreach (ExpressionStatement e in initializers)
9494                                 e.EmitStatement (ec);
9495                 }
9496
9497                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9498                 {
9499                         foreach (Expression e in initializers)
9500                                 e.MutateHoistedGenericType (storey);
9501                 }
9502         }
9503         
9504         //
9505         // New expression with element/object initializers
9506         //
9507         public class NewInitialize : New
9508         {
9509                 //
9510                 // This class serves as a proxy for variable initializer target instances.
9511                 // A real variable is assigned later when we resolve left side of an
9512                 // assignment
9513                 //
9514                 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9515                 {
9516                         NewInitialize new_instance;
9517
9518                         public InitializerTargetExpression (NewInitialize newInstance)
9519                         {
9520                                 this.type = newInstance.type;
9521                                 this.loc = newInstance.loc;
9522                                 this.eclass = newInstance.eclass;
9523                                 this.new_instance = newInstance;
9524                         }
9525
9526                         public override Expression CreateExpressionTree (EmitContext ec)
9527                         {
9528                                 // Should not be reached
9529                                 throw new NotSupportedException ("ET");
9530                         }
9531
9532                         public override Expression DoResolve (EmitContext ec)
9533                         {
9534                                 return this;
9535                         }
9536
9537                         public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9538                         {
9539                                 return this;
9540                         }
9541
9542                         public override void Emit (EmitContext ec)
9543                         {
9544                                 new_instance.value_target.Emit (ec);
9545                         }
9546
9547                         #region IMemoryLocation Members
9548
9549                         public void AddressOf (EmitContext ec, AddressOp mode)
9550                         {
9551                                 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
9552                         }
9553
9554                         #endregion
9555                 }
9556
9557                 CollectionOrObjectInitializers initializers;
9558
9559                 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9560                         : base (requested_type, arguments, l)
9561                 {
9562                         this.initializers = initializers;
9563                 }
9564
9565                 protected override void CloneTo (CloneContext clonectx, Expression t)
9566                 {
9567                         base.CloneTo (clonectx, t);
9568
9569                         NewInitialize target = (NewInitialize) t;
9570                         target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9571                 }
9572
9573                 public override Expression CreateExpressionTree (EmitContext ec)
9574                 {
9575                         ArrayList args = new ArrayList (2);
9576                         args.Add (new Argument (base.CreateExpressionTree (ec)));
9577                         if (!initializers.IsEmpty)
9578                                 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9579
9580                         return CreateExpressionFactoryCall (
9581                                 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9582                                 args);
9583                 }
9584
9585                 public override Expression DoResolve (EmitContext ec)
9586                 {
9587                         if (eclass != ExprClass.Invalid)
9588                                 return this;
9589                         
9590                         Expression e = base.DoResolve (ec);
9591                         if (type == null)
9592                                 return null;
9593
9594                         // Empty initializer can be optimized to simple new
9595                         if (initializers.IsEmpty) {
9596                                 initializers.Resolve (ec);
9597                                 return ReducedExpression.Create (e, this).Resolve (ec);
9598                         }
9599
9600                         Expression previous = ec.CurrentInitializerVariable;
9601                         ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9602                         initializers.Resolve (ec);
9603                         ec.CurrentInitializerVariable = previous;
9604                         return e;
9605                 }
9606
9607                 public override void Emit (EmitContext ec)
9608                 {
9609                         base.Emit (ec);
9610
9611                         //
9612                         // If target is non-hoisted variable, let's use it
9613                         //
9614                         VariableReference variable = value_target as VariableReference;
9615                         if (variable != null && variable.HoistedVariable == null) {
9616                                 if (variable.IsRef)
9617                                         StoreFromPtr (ec.ig, type);
9618                                 else
9619                                         variable.EmitAssign (ec, EmptyExpression.Null, false, false);
9620                         } else {
9621                                 variable = null;
9622                                 if (value_target == null || value_target_set)
9623                                         value_target = new LocalTemporary (type);
9624
9625                                 ((LocalTemporary) value_target).Store (ec);
9626                         }
9627
9628                         initializers.Emit (ec);
9629
9630                         if (variable == null) {
9631                                 value_target.Emit (ec);
9632                                 value_target = null;
9633                         }
9634                 }
9635
9636                 public override void EmitStatement (EmitContext ec)
9637                 {
9638                         if (initializers.IsEmpty) {
9639                                 base.EmitStatement (ec);
9640                                 return;
9641                         }
9642
9643                         base.Emit (ec);
9644
9645                         if (value_target == null) {
9646                                 LocalTemporary variable = new LocalTemporary (type);
9647                                 variable.Store (ec);
9648                                 value_target = variable;
9649                         }
9650
9651                         initializers.EmitStatement (ec);
9652                 }
9653
9654                 public override bool HasInitializer {
9655                         get {
9656                                 return !initializers.IsEmpty;
9657                         }
9658                 }
9659
9660                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9661                 {
9662                         base.MutateHoistedGenericType (storey);
9663                         initializers.MutateHoistedGenericType (storey);
9664                 }
9665         }
9666
9667         public class AnonymousTypeDeclaration : Expression
9668         {
9669                 ArrayList parameters;
9670                 readonly TypeContainer parent;
9671                 static readonly ArrayList EmptyParameters = new ArrayList (0);
9672
9673                 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9674                 {
9675                         this.parameters = parameters;
9676                         this.parent = parent;
9677                         this.loc = loc;
9678                 }
9679
9680                 protected override void CloneTo (CloneContext clonectx, Expression target)
9681                 {
9682                         if (parameters == null)
9683                                 return;
9684
9685                         AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9686                         t.parameters = new ArrayList (parameters.Count);
9687                         foreach (AnonymousTypeParameter atp in parameters)
9688                                 t.parameters.Add (atp.Clone (clonectx));
9689                 }
9690
9691                 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9692                 {
9693                         AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9694                         if (type != null)
9695                                 return type;
9696
9697                         type = AnonymousTypeClass.Create (parent, parameters, loc);
9698                         if (type == null)
9699                                 return null;
9700
9701                         type.DefineType ();
9702                         type.Define ();
9703                         type.EmitType ();
9704                         if (Report.Errors == 0)
9705                                 type.CloseType ();
9706
9707                         RootContext.ToplevelTypes.AddAnonymousType (type);
9708                         return type;
9709                 }
9710
9711                 public override Expression CreateExpressionTree (EmitContext ec)
9712                 {
9713                         throw new NotSupportedException ("ET");
9714                 }
9715
9716                 public override Expression DoResolve (EmitContext ec)
9717                 {
9718                         AnonymousTypeClass anonymous_type;
9719
9720                         if (!ec.IsAnonymousMethodAllowed) {
9721                                 Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9722                                 return null;
9723                         }
9724
9725                         if (parameters == null) {
9726                                 anonymous_type = CreateAnonymousType (EmptyParameters);
9727                                 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9728                                         null, loc).Resolve (ec);
9729                         }
9730
9731                         bool error = false;
9732                         ArrayList arguments = new ArrayList (parameters.Count);
9733                         TypeExpression [] t_args = new TypeExpression [parameters.Count];
9734                         for (int i = 0; i < parameters.Count; ++i) {
9735                                 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9736                                 if (e == null) {
9737                                         error = true;
9738                                         continue;
9739                                 }
9740
9741                                 arguments.Add (new Argument (e));
9742                                 t_args [i] = new TypeExpression (e.Type, e.Location);
9743                         }
9744
9745                         if (error)
9746                                 return null;
9747
9748                         anonymous_type = CreateAnonymousType (parameters);
9749                         if (anonymous_type == null)
9750                                 return null;
9751
9752                         ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9753                                 new TypeArguments (loc, t_args), loc);
9754
9755                         return new New (te, arguments, loc).Resolve (ec);
9756                 }
9757
9758                 public override void Emit (EmitContext ec)
9759                 {
9760                         throw new InternalErrorException ("Should not be reached");
9761                 }
9762         }
9763
9764         public class AnonymousTypeParameter : Expression
9765         {
9766                 public readonly string Name;
9767                 Expression initializer;
9768
9769                 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9770                 {
9771                         this.Name = name;
9772                         this.loc = loc;
9773                         this.initializer = initializer;
9774                 }
9775                 
9776                 public AnonymousTypeParameter (Parameter parameter)
9777                 {
9778                         this.Name = parameter.Name;
9779                         this.loc = parameter.Location;
9780                         this.initializer = new SimpleName (Name, loc);
9781                 }               
9782
9783                 protected override void CloneTo (CloneContext clonectx, Expression target)
9784                 {
9785                         AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9786                         t.initializer = initializer.Clone (clonectx);
9787                 }
9788
9789                 public override Expression CreateExpressionTree (EmitContext ec)
9790                 {
9791                         throw new NotSupportedException ("ET");
9792                 }
9793
9794                 public override bool Equals (object o)
9795                 {
9796                         AnonymousTypeParameter other = o as AnonymousTypeParameter;
9797                         return other != null && Name == other.Name;
9798                 }
9799
9800                 public override int GetHashCode ()
9801                 {
9802                         return Name.GetHashCode ();
9803                 }
9804
9805                 public override Expression DoResolve (EmitContext ec)
9806                 {
9807                         Expression e = initializer.Resolve (ec);
9808                         if (e == null)
9809                                 return null;
9810
9811                         if (e.eclass == ExprClass.MethodGroup) {
9812                                 Error_InvalidInitializer (e.ExprClassName);
9813                                 return null;
9814                         }
9815
9816                         type = e.Type;
9817                         if (type == TypeManager.void_type || type == TypeManager.null_type ||
9818                                 type == TypeManager.anonymous_method_type || type.IsPointer) {
9819                                 Error_InvalidInitializer (e.GetSignatureForError ());
9820                                 return null;
9821                         }
9822
9823                         return e;
9824                 }
9825
9826                 protected virtual void Error_InvalidInitializer (string initializer)
9827                 {
9828                         Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9829                                 Name, initializer);
9830                 }
9831
9832                 public override void Emit (EmitContext ec)
9833                 {
9834                         throw new InternalErrorException ("Should not be reached");
9835                 }
9836         }
9837 }