Merge pull request #1290 from directhex/master
[mono.git] / mcs / mcs / ecore.cs
1 //
2 // ecore.cs: Core of the Expression representation for the intermediate 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 // Copyright 2011-2012 Xamarin Inc.
11 //
12 //
13
14 using System;
15 using System.Collections.Generic;
16 using System.Text;
17 using SLE = System.Linq.Expressions;
18 using System.Linq;
19
20 #if STATIC
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
23 #else
24 using System.Reflection;
25 using System.Reflection.Emit;
26 #endif
27
28 namespace Mono.CSharp {
29
30         /// <remarks>
31         ///   The ExprClass class contains the is used to pass the 
32         ///   classification of an expression (value, variable, namespace,
33         ///   type, method group, property access, event access, indexer access,
34         ///   nothing).
35         /// </remarks>
36         public enum ExprClass : byte {
37                 Unresolved      = 0,
38                 
39                 Value,
40                 Variable,
41                 Namespace,
42                 Type,
43                 TypeParameter,
44                 MethodGroup,
45                 PropertyAccess,
46                 EventAccess,
47                 IndexerAccess,
48                 Nothing, 
49         }
50
51         /// <remarks>
52         ///   This is used to tell Resolve in which types of expressions we're
53         ///   interested.
54         /// </remarks>
55         [Flags]
56         public enum ResolveFlags {
57                 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
58                 VariableOrValue         = 1,
59
60                 // Returns a type expression.
61                 Type                    = 1 << 1,
62
63                 // Returns a method group.
64                 MethodGroup             = 1 << 2,
65
66                 TypeParameter   = 1 << 3,
67
68                 // Mask of all the expression class flags.
69                 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
70         }
71
72         //
73         // This is just as a hint to AddressOf of what will be done with the
74         // address.
75         [Flags]
76         public enum AddressOp {
77                 Store = 1,
78                 Load  = 2,
79                 LoadStore = 3
80         };
81         
82         /// <summary>
83         ///   This interface is implemented by variables
84         /// </summary>
85         public interface IMemoryLocation {
86                 /// <summary>
87                 ///   The AddressOf method should generate code that loads
88                 ///   the address of the object and leaves it on the stack.
89                 ///
90                 ///   The `mode' argument is used to notify the expression
91                 ///   of whether this will be used to read from the address or
92                 ///   write to the address.
93                 ///
94                 ///   This is just a hint that can be used to provide good error
95                 ///   reporting, and should have no other side effects. 
96                 /// </summary>
97                 void AddressOf (EmitContext ec, AddressOp mode);
98         }
99
100         //
101         // An expressions resolved as a direct variable reference
102         //
103         public interface IVariableReference : IFixedExpression
104         {
105                 bool IsHoisted { get; }
106                 string Name { get; }
107                 VariableInfo VariableInfo { get; }
108
109                 void SetHasAddressTaken ();
110         }
111
112         //
113         // Implemented by an expression which could be or is always
114         // fixed
115         //
116         public interface IFixedExpression
117         {
118                 bool IsFixed { get; }
119         }
120
121         public interface IExpressionCleanup
122         {
123                 void EmitCleanup (EmitContext ec);
124         }
125
126         /// <remarks>
127         ///   Base class for expressions
128         /// </remarks>
129         public abstract class Expression {
130                 public ExprClass eclass;
131                 protected TypeSpec type;
132                 protected Location loc;
133                 
134                 public TypeSpec Type {
135                         get { return type; }
136                         set { type = value; }
137                 }
138
139                 public virtual bool IsSideEffectFree {
140                         get {
141                                 return false;
142                         }
143                 }
144
145                 public Location Location {
146                         get { return loc; }
147                 }
148
149                 public virtual bool IsNull {
150                         get {
151                                 return false;
152                         }
153                 }
154
155                 //
156                 // Used to workaround parser limitation where we cannot get
157                 // start of statement expression location
158                 //
159                 public virtual Location StartLocation {
160                         get {
161                                 return loc;
162                         }
163                 }
164
165                 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
166                 {
167                         //
168                         // Return method-group expression when the expression can be used as
169                         // lambda replacement. A good example is array sorting where instead of
170                         // code like
171                         //
172                         //  Array.Sort (s, (a, b) => String.Compare (a, b));
173                         //
174                         // we can use method group directly
175                         //
176                         //  Array.Sort (s, String.Compare);
177                         //
178                         // Correct overload will be used because we do the reduction after
179                         // best candidate was found.
180                         //
181                         return null;
182                 }
183
184                 //
185                 // Returns true when the expression during Emit phase breaks stack
186                 // by using await expression
187                 //
188                 public virtual bool ContainsEmitWithAwait ()
189                 {
190                         return false;
191                 }
192
193                 /// <summary>
194                 ///   Performs semantic analysis on the Expression
195                 /// </summary>
196                 ///
197                 /// <remarks>
198                 ///   The Resolve method is invoked to perform the semantic analysis
199                 ///   on the node.
200                 ///
201                 ///   The return value is an expression (it can be the
202                 ///   same expression in some cases) or a new
203                 ///   expression that better represents this node.
204                 ///   
205                 ///   For example, optimizations of Unary (LiteralInt)
206                 ///   would return a new LiteralInt with a negated
207                 ///   value.
208                 ///   
209                 ///   If there is an error during semantic analysis,
210                 ///   then an error should be reported (using Report)
211                 ///   and a null value should be returned.
212                 ///   
213                 ///   There are two side effects expected from calling
214                 ///   Resolve(): the the field variable "eclass" should
215                 ///   be set to any value of the enumeration
216                 ///   `ExprClass' and the type variable should be set
217                 ///   to a valid type (this is the type of the
218                 ///   expression).
219                 /// </remarks>
220                 protected abstract Expression DoResolve (ResolveContext rc);
221
222                 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
223                 {
224                         return null;
225                 }
226
227                 //
228                 // This is used if the expression should be resolved as a type or namespace name.
229                 // the default implementation fails.   
230                 //
231                 public virtual TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
232                 {
233                         var rc = mc as ResolveContext ?? new ResolveContext (mc);
234                         Expression e = Resolve (rc);
235                         if (e != null)
236                                 e.Error_UnexpectedKind (rc, ResolveFlags.Type, loc);
237
238                         return null;
239                 }
240
241                 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
242                 {
243                         rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
244                 }
245
246                 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
247                 {
248                         rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
249                 }
250
251                 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
252                 {
253                         rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254                                 name, type.GetSignatureForError ());
255                 }
256
257                 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
258                 {
259                         report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
260                 }
261                 
262                 public void Error_InvalidExpressionStatement (BlockContext bc)
263                 {
264                         Error_InvalidExpressionStatement (bc.Report, loc);
265                 }
266
267                 public void Error_InvalidExpressionStatement (Report report)
268                 {
269                         Error_InvalidExpressionStatement (report, loc);
270                 }
271
272                 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
273                 {
274                         Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
275                 }
276
277                 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
278                 {
279                         Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
280                 }
281
282                 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
283                 {
284                         // The error was already reported as CS1660
285                         if (type == InternalType.AnonymousMethod)
286                                 return;
287
288                         if (type == InternalType.ErrorType || target == InternalType.ErrorType)
289                                 return;
290
291                         string from_type = type.GetSignatureForError ();
292                         string to_type = target.GetSignatureForError ();
293                         if (from_type == to_type) {
294                                 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
295                                 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
296                         }
297
298                         if (expl) {
299                                 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
300                                         from_type, to_type);
301                                 return;
302                         }
303
304                         ec.Report.DisableReporting ();
305                         bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
306                         ec.Report.EnableReporting ();
307
308                         if (expl_exists) {
309                                 ec.Report.Error (266, loc,
310                                         "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
311                                         from_type, to_type);
312                         } else {
313                                 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
314                                         from_type, to_type);
315                         }
316                 }
317
318                 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
319                 {
320                         // Better message for possible generic expressions
321                         if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
322                                 var report = context.Module.Compiler.Report;
323                                 report.SymbolRelatedToPreviousError (member);
324                                 if (member is TypeSpec)
325                                         member = ((TypeSpec) member).GetDefinition ();
326                                 else
327                                         member = ((MethodSpec) member).GetGenericMethodDefinition ();
328
329                                 string name = member.Kind == MemberKind.Method ? "method" : "type";
330                                 if (member.IsGeneric) {
331                                         report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
332                                                 name, member.GetSignatureForError (), member.Arity.ToString ());
333                                 } else {
334                                         report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
335                                                 name, member.GetSignatureForError ());
336                                 }
337                         } else {
338                                 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
339                         }
340                 }
341
342                 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
343                 {
344                         context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
345                                 exprType, name);
346                 }
347
348                 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
349                 {
350                         Error_TypeDoesNotContainDefinition (ec, loc, type, name);
351                 }
352
353                 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
354                 {
355                         ec.Report.SymbolRelatedToPreviousError (type);
356                         ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357                                 type.GetSignatureForError (), name);
358                 }
359
360                 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
361                 {
362                         if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
363                                 // Already reported as CS1612
364                         } else if (rhs == EmptyExpression.OutAccess) {
365                                 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
366                         } else {
367                                 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
368                         }
369                 }
370
371                 protected void Error_VoidPointerOperation (ResolveContext rc)
372                 {
373                         rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
374                 }
375
376                 public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
377                 {
378                         rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
379                 }
380
381                 public ResolveFlags ExprClassToResolveFlags {
382                         get {
383                                 switch (eclass) {
384                                 case ExprClass.Type:
385                                 case ExprClass.Namespace:
386                                         return ResolveFlags.Type;
387                                         
388                                 case ExprClass.MethodGroup:
389                                         return ResolveFlags.MethodGroup;
390                                         
391                                 case ExprClass.TypeParameter:
392                                         return ResolveFlags.TypeParameter;
393                                         
394                                 case ExprClass.Value:
395                                 case ExprClass.Variable:
396                                 case ExprClass.PropertyAccess:
397                                 case ExprClass.EventAccess:
398                                 case ExprClass.IndexerAccess:
399                                         return ResolveFlags.VariableOrValue;
400                                         
401                                 default:
402                                         throw new InternalErrorException (loc.ToString () + " " +  GetType () + " ExprClass is Invalid after resolve");
403                                 }
404                         }
405                 }
406
407                 //
408                 // Implements identical simple name and type-name resolution
409                 //
410                 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
411                 {
412                         var t = left.Type;
413                         if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
414                                 return left;
415
416                         // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
417                         // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
418
419                         if (left is MemberExpr || left is VariableReference) {
420                                 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
421                                 if (identical_type != null && identical_type.Type == left.Type)
422                                         return identical_type;
423                         }
424
425                         return left;
426                 }
427
428                 public virtual string GetSignatureForError ()
429                 {
430                         return type.GetDefinition ().GetSignatureForError ();
431                 }
432
433                 public static bool IsNeverNull (Expression expr)
434                 {
435                         if (expr is This || expr is New || expr is ArrayCreation || expr is DelegateCreation || expr is ConditionalMemberAccess)
436                                 return true;
437
438                         var c = expr as Constant;
439                         if (c != null)
440                                 return !c.IsNull;
441
442                         var tc = expr as TypeCast;
443                         if (tc != null)
444                                 return IsNeverNull (tc.Child);
445
446                         return false;
447                 }
448
449                 protected static bool IsNullPropagatingValid (TypeSpec type)
450                 {
451                         switch (type.Kind) {
452                         case MemberKind.Struct:
453                                 return type.IsNullableType;
454                         case MemberKind.Enum:
455                         case MemberKind.Void:
456                         case MemberKind.PointerType:
457                                 return false;
458                         case MemberKind.InternalCompilerType:
459                                 return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
460                         default:
461                                 return true;
462                         }
463                 }
464
465                 public virtual bool HasConditionalAccess ()
466                 {
467                         return false;
468                 }
469
470                 protected static TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
471                 {
472                         return TypeSpec.IsValueType (type) && !type.IsNullableType ?
473                                 Nullable.NullableInfo.MakeType (rc.Module, type) :
474                                 type;
475                 }
476                
477                 /// <summary>
478                 ///   Resolves an expression and performs semantic analysis on it.
479                 /// </summary>
480                 ///
481                 /// <remarks>
482                 ///   Currently Resolve wraps DoResolve to perform sanity
483                 ///   checking and assertion checking on what we expect from Resolve.
484                 /// </remarks>
485                 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
486                 {
487                         if (eclass != ExprClass.Unresolved) {
488                                 if ((flags & ExprClassToResolveFlags) == 0) {
489                                         Error_UnexpectedKind (ec, flags, loc);
490                                         return null;
491                                 }
492
493                                 return this;
494                         }
495                         
496                         Expression e;
497                         try {
498                                 e = DoResolve (ec);
499
500                                 if (e == null)
501                                         return null;
502
503                                 if ((flags & e.ExprClassToResolveFlags) == 0) {
504                                         e.Error_UnexpectedKind (ec, flags, loc);
505                                         return null;
506                                 }
507
508                                 if (e.type == null)
509                                         throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
510
511                                 return e;
512                         } catch (Exception ex) {
513                                 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
514                                         ec.Report.Printer is NullReportPrinter)
515                                         throw;
516
517                                 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
518                                 return ErrorExpression.Instance;        // TODO: Add location
519                         }
520                 }
521
522                 /// <summary>
523                 ///   Resolves an expression and performs semantic analysis on it.
524                 /// </summary>
525                 public Expression Resolve (ResolveContext rc)
526                 {
527                         return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
528                 }
529
530                 /// <summary>
531                 ///   Resolves an expression for LValue assignment
532                 /// </summary>
533                 ///
534                 /// <remarks>
535                 ///   Currently ResolveLValue wraps DoResolveLValue to perform sanity
536                 ///   checking and assertion checking on what we expect from Resolve
537                 /// </remarks>
538                 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
539                 {
540                         int errors = ec.Report.Errors;
541                         bool out_access = right_side == EmptyExpression.OutAccess;
542
543                         Expression e = DoResolveLValue (ec, right_side);
544
545                         if (e != null && out_access && !(e is IMemoryLocation)) {
546                                 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
547                                 //        Enabling this 'throw' will "only" result in deleting useless code elsewhere,
548
549                                 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
550                                 //                                e.GetType () + " " + e.GetSignatureForError ());
551                                 e = null;
552                         }
553
554                         if (e == null) {
555                                 if (errors == ec.Report.Errors) {
556                                         Error_ValueAssignment (ec, right_side);
557                                 }
558                                 return null;
559                         }
560
561                         if (e.eclass == ExprClass.Unresolved)
562                                 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
563
564                         if ((e.type == null) && !(e is GenericTypeExpr))
565                                 throw new Exception ("Expression " + e + " did not set its type after Resolve");
566
567                         return e;
568                 }
569
570                 public Constant ResolveLabelConstant (ResolveContext rc)
571                 {
572                         var expr = Resolve (rc);
573                         if (expr == null)
574                                 return null;
575
576                         Constant c = expr as Constant;
577                         if (c == null) {
578                                 if (expr.type != InternalType.ErrorType)
579                                         rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
580
581                                 return null;
582                         }
583
584                         return c;
585                 }
586
587                 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
588                 {
589                         if (Attribute.IsValidArgumentType (parameterType)) {
590                                 rc.Module.Compiler.Report.Error (182, loc,
591                                         "An attribute argument must be a constant expression, typeof expression or array creation expression");
592                         } else {
593                                 rc.Module.Compiler.Report.Error (181, loc,
594                                         "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
595                                         targetType.GetSignatureForError ());
596                         }
597                 }
598
599                 /// <summary>
600                 ///   Emits the code for the expression
601                 /// </summary>
602                 ///
603                 /// <remarks>
604                 ///   The Emit method is invoked to generate the code
605                 ///   for the expression.  
606                 /// </remarks>
607                 public abstract void Emit (EmitContext ec);
608
609
610                 // Emit code to branch to @target if this expression is equivalent to @on_true.
611                 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
612                 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
613                 // including the use of conditional branches.  Note also that a branch MUST be emitted
614                 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
615                 {
616                         Emit (ec);
617                         ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
618                 }
619
620                 // Emit this expression for its side effects, not for its value.
621                 // The default implementation is to emit the value, and then throw it away.
622                 // Subclasses can provide more efficient implementations, but those MUST be equivalent
623                 public virtual void EmitSideEffect (EmitContext ec)
624                 {
625                         Emit (ec);
626                         ec.Emit (OpCodes.Pop);
627                 }
628
629                 //
630                 // Emits the expression into temporary field variable. The method
631                 // should be used for await expressions only
632                 //
633                 public virtual Expression EmitToField (EmitContext ec)
634                 {
635                         //
636                         // This is the await prepare Emit method. When emitting code like
637                         // a + b we emit code like
638                         //
639                         // a.Emit ()
640                         // b.Emit ()
641                         // Opcodes.Add
642                         //
643                         // For await a + await b we have to interfere the flow to keep the
644                         // stack clean because await yields from the expression. The emit
645                         // then changes to
646                         //
647                         // a = a.EmitToField () // a is changed to temporary field access
648                         // b = b.EmitToField ()
649                         // a.Emit ()
650                         // b.Emit ()
651                         // Opcodes.Add
652                         //
653                         //
654                         // The idea is to emit expression and leave the stack empty with
655                         // result value still available.
656                         //
657                         // Expressions should override this default implementation when
658                         // optimized version can be provided (e.g. FieldExpr)
659                         //
660                         //
661                         // We can optimize for side-effect free expressions, they can be
662                         // emitted out of order
663                         //
664                         if (IsSideEffectFree)
665                                 return this;
666
667                         bool needs_temporary = ContainsEmitWithAwait ();
668                         if (!needs_temporary)
669                                 ec.EmitThis ();
670
671                         // Emit original code
672                         var field = EmitToFieldSource (ec);
673                         if (field == null) {
674                                 //
675                                 // Store the result to temporary field when we
676                                 // cannot load `this' directly
677                                 //
678                                 field = ec.GetTemporaryField (type);
679                                 if (needs_temporary) {
680                                         //
681                                         // Create temporary local (we cannot load `this' before Emit)
682                                         //
683                                         var temp = ec.GetTemporaryLocal (type);
684                                         ec.Emit (OpCodes.Stloc, temp);
685
686                                         ec.EmitThis ();
687                                         ec.Emit (OpCodes.Ldloc, temp);
688                                         field.EmitAssignFromStack (ec);
689
690                                         ec.FreeTemporaryLocal (temp, type);
691                                 } else {
692                                         field.EmitAssignFromStack (ec);
693                                 }
694                         }
695
696                         return field;
697                 }
698
699                 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
700                 {
701                         //
702                         // Default implementation calls Emit method
703                         //
704                         Emit (ec);
705                         return null;
706                 }
707
708                 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
709                 {
710                         if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
711                                 bool contains_await = false;
712
713                                 for (int i = 1; i < expressions.Count; ++i) {
714                                         if (expressions[i].ContainsEmitWithAwait ()) {
715                                                 contains_await = true;
716                                                 break;
717                                         }
718                                 }
719
720                                 if (contains_await) {
721                                         for (int i = 0; i < expressions.Count; ++i) {
722                                                 expressions[i] = expressions[i].EmitToField (ec);
723                                         }
724                                 }
725                         }
726
727                         for (int i = 0; i < expressions.Count; ++i) {
728                                 expressions[i].Emit (ec);
729                         }
730                 }
731
732                 /// <summary>
733                 ///   Protected constructor.  Only derivate types should
734                 ///   be able to be created
735                 /// </summary>
736
737                 protected Expression ()
738                 {
739                 }
740
741                 /// <summary>
742                 ///   Returns a fully formed expression after a MemberLookup
743                 /// </summary>
744                 /// 
745                 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
746                 {
747                         if (spec is EventSpec)
748                                 return new EventExpr ((EventSpec) spec, loc);
749                         if (spec is ConstSpec)
750                                 return new ConstantExpr ((ConstSpec) spec, loc);
751                         if (spec is FieldSpec)
752                                 return new FieldExpr ((FieldSpec) spec, loc);
753                         if (spec is PropertySpec)
754                                 return new PropertyExpr ((PropertySpec) spec, loc);
755                         if (spec is TypeSpec)
756                                 return new TypeExpression (((TypeSpec) spec), loc);
757
758                         return null;
759                 }
760
761                 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
762                 {
763                         var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
764                         if (ctors == null) {
765                                 switch (type.Kind) {
766                                 case MemberKind.Struct:
767                                         // Every struct has implicit default constructor if not provided by user
768                                         if (args == null)
769                                                 return null;
770
771                                         rc.Report.SymbolRelatedToPreviousError (type);
772                                         // Report meaningful error for struct as they always have default ctor in C# context
773                                         OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
774                                         break;
775                                 case MemberKind.MissingType:
776                                 case MemberKind.InternalCompilerType:
777 // LAMESPEC: dynamic is not really object
778 //                                      if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
779 //                                              goto default;
780                                         break;
781                                 default:
782                                         rc.Report.SymbolRelatedToPreviousError (type);
783                                         rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
784                                                 type.GetSignatureForError ());
785                                         break;
786                                 }
787
788                                 return null;
789                         }
790
791                         if (args == null && type.IsStruct) {
792                                 bool includes_empty = false;
793                                 foreach (MethodSpec ctor in ctors) {
794                                         if (ctor.Parameters.IsEmpty) {
795                                                 includes_empty = true;
796                                         }
797                                 }
798
799                                 if (!includes_empty)
800                                         return null;
801                         }
802
803                         var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
804                         if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
805                                 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
806                         }
807
808                         return r.ResolveMember<MethodSpec> (rc, ref args);
809                 }
810
811                 [Flags]
812                 public enum MemberLookupRestrictions
813                 {
814                         None = 0,
815                         InvocableOnly = 1,
816                         ExactArity = 1 << 2,
817                         ReadAccess = 1 << 3,
818                         EmptyArguments = 1 << 4,
819                         IgnoreArity = 1 << 5,
820                         IgnoreAmbiguity = 1 << 6
821                 }
822
823                 //
824                 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
825                 // `qualifier_type' or null to lookup members in the current class.
826                 //
827                 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
828                 {
829                         var members = MemberCache.FindMembers (queried_type, name, false);
830                         if (members == null)
831                                 return null;
832
833                         MemberSpec non_method = null;
834                         MemberSpec ambig_non_method = null;
835                         do {
836                                 for (int i = 0; i < members.Count; ++i) {
837                                         var member = members[i];
838
839                                         // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
840                                         if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
841                                                 continue;
842
843                                         if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
844                                                 continue;
845
846                                         if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
847                                                 continue;
848
849                                         if (!errorMode) {
850                                                 if (!member.IsAccessible (rc))
851                                                         continue;
852
853                                                 //
854                                                 // With runtime binder we can have a situation where queried type is inaccessible
855                                                 // because it came via dynamic object, the check about inconsisted accessibility
856                                                 // had no effect as the type was unknown during compilation
857                                                 //
858                                                 // class A {
859                                                 //              private class N { }
860                                                 //
861                                                 //              public dynamic Foo ()
862                                                 //              {
863                                                 //                      return new N ();
864                                                 //              }
865                                                 //      }
866                                                 //
867                                                 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
868                                                         continue;
869                                         }
870
871                                         if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
872                                                 if (member is MethodSpec) {
873                                                         //
874                                                         // Interface members that are hidden by class members are removed from the set. This
875                                                         // step only has an effect if T is a type parameter and T has both an effective base 
876                                                         // class other than object and a non-empty effective interface set
877                                                         //
878                                                         var tps = queried_type as TypeParameterSpec;
879                                                         if (tps != null && tps.HasTypeConstraint)
880                                                                 members = RemoveHiddenTypeParameterMethods (members);
881
882                                                         return new MethodGroupExpr (members, queried_type, loc);
883                                                 }
884
885                                                 if (!Invocation.IsMemberInvocable (member))
886                                                         continue;
887                                         }
888
889                                         if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
890                                                 non_method = member;
891                                         } else if (!errorMode && !member.IsNotCSharpCompatible) {
892                                                 //
893                                                 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
894                                                 // T has both an effective base class other than object and a non-empty effective interface set.
895                                                 //
896                                                 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
897                                                 //
898                                                 var tps = queried_type as TypeParameterSpec;
899                                                 if (tps != null && tps.HasTypeConstraint) {
900                                                         if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
901                                                                 continue;
902
903                                                         if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
904                                                                 non_method = member;
905                                                                 continue;
906                                                         }
907                                                 }
908
909                                                 ambig_non_method = member;
910                                         }
911                                 }
912
913                                 if (non_method != null) {
914                                         if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
915                                                 var report = rc.Module.Compiler.Report;
916                                                 report.SymbolRelatedToPreviousError (non_method);
917                                                 report.SymbolRelatedToPreviousError (ambig_non_method);
918                                                 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
919                                                         non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
920                                         }
921
922                                         if (non_method is MethodSpec)
923                                                 return new MethodGroupExpr (members, queried_type, loc);
924
925                                         return ExprClassFromMemberInfo (non_method, loc);
926                                 }
927
928                                 if (members[0].DeclaringType.BaseType == null)
929                                         members = null;
930                                 else
931                                         members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
932
933                         } while (members != null);
934
935                         return null;
936                 }
937
938                 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
939                 {
940                         if (members.Count < 2)
941                                 return members;
942
943                         //
944                         // If M is a method, then all non-method members declared in an interface declaration
945                         // are removed from the set, and all methods with the same signature as M declared in
946                         // an interface declaration are removed from the set
947                         //
948
949                         bool copied = false;
950                         for (int i = 0; i < members.Count; ++i) {
951                                 var method = members[i] as MethodSpec;
952                                 if (method == null) {
953                                         if (!copied) {
954                                                 copied = true;
955                                                 members = new List<MemberSpec> (members);
956                                         } 
957                                         
958                                         members.RemoveAt (i--);
959                                         continue;
960                                 }
961
962                                 if (!method.DeclaringType.IsInterface)
963                                         continue;
964
965                                 for (int ii = 0; ii < members.Count; ++ii) {
966                                         var candidate = members[ii] as MethodSpec;
967                                         if (candidate == null || !candidate.DeclaringType.IsClass)
968                                                 continue;
969
970                                         if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
971                                                 continue;
972
973                                         if (!copied) {
974                                                 copied = true;
975                                                 members = new List<MemberSpec> (members);
976                                         }
977
978                                         members.RemoveAt (i--);
979                                         break;
980                                 }
981                         }
982
983                         return members;
984                 }
985
986                 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
987                 {
988                         throw new NotImplementedException ();
989                 }
990
991                 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
992                 {
993                         if (t == InternalType.ErrorType)
994                                 return;
995
996                         rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
997                                 oper, t.GetSignatureForError ());
998                 }
999
1000                 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1001                 {
1002                         ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1003                 }
1004
1005                 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1006                 {
1007                         rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1008                 }
1009
1010                 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1011                 {
1012                 }
1013
1014                 //
1015                 // Special version of flow analysis for expressions which can return different
1016                 // on-true and on-false result. Used by &&, ||, ?: expressions
1017                 //
1018                 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1019                 {
1020                         FlowAnalysis (fc);
1021                         fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1022                 }
1023
1024                 /// <summary>
1025                 ///   Returns an expression that can be used to invoke operator true
1026                 ///   on the expression if it exists.
1027                 /// </summary>
1028                 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1029                 {
1030                         return GetOperatorTrueOrFalse (ec, e, true, loc);
1031                 }
1032
1033                 /// <summary>
1034                 ///   Returns an expression that can be used to invoke operator false
1035                 ///   on the expression if it exists.
1036                 /// </summary>
1037                 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1038                 {
1039                         return GetOperatorTrueOrFalse (ec, e, false, loc);
1040                 }
1041
1042                 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1043                 {
1044                         var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1045                         var methods = MemberCache.GetUserOperator (e.type, op, false);
1046                         if (methods == null)
1047                                 return null;
1048
1049                         Arguments arguments = new Arguments (1);
1050                         arguments.Add (new Argument (e));
1051
1052                         var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1053                         var oper = res.ResolveOperator (ec, ref arguments);
1054
1055                         if (oper == null)
1056                                 return null;
1057
1058                         return new UserOperatorCall (oper, arguments, null, loc);
1059                 }
1060                 
1061                 public virtual string ExprClassName
1062                 {
1063                         get {
1064                                 switch (eclass){
1065                                 case ExprClass.Unresolved:
1066                                         return "Unresolved";
1067                                 case ExprClass.Value:
1068                                         return "value";
1069                                 case ExprClass.Variable:
1070                                         return "variable";
1071                                 case ExprClass.Namespace:
1072                                         return "namespace";
1073                                 case ExprClass.Type:
1074                                         return "type";
1075                                 case ExprClass.MethodGroup:
1076                                         return "method group";
1077                                 case ExprClass.PropertyAccess:
1078                                         return "property access";
1079                                 case ExprClass.EventAccess:
1080                                         return "event access";
1081                                 case ExprClass.IndexerAccess:
1082                                         return "indexer access";
1083                                 case ExprClass.Nothing:
1084                                         return "null";
1085                                 case ExprClass.TypeParameter:
1086                                         return "type parameter";
1087                                 }
1088                                 throw new Exception ("Should not happen");
1089                         }
1090                 }
1091                 
1092                 /// <summary>
1093                 ///   Reports that we were expecting `expr' to be of class `expected'
1094                 /// </summary>
1095                 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1096                 {
1097                         var name = memberExpr.GetSignatureForError ();
1098
1099                         ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1100                 }
1101
1102                 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1103                 {
1104                         string [] valid = new string [4];
1105                         int count = 0;
1106
1107                         if ((flags & ResolveFlags.VariableOrValue) != 0) {
1108                                 valid [count++] = "variable";
1109                                 valid [count++] = "value";
1110                         }
1111
1112                         if ((flags & ResolveFlags.Type) != 0)
1113                                 valid [count++] = "type";
1114
1115                         if ((flags & ResolveFlags.MethodGroup) != 0)
1116                                 valid [count++] = "method group";
1117
1118                         if (count == 0)
1119                                 valid [count++] = "unknown";
1120
1121                         StringBuilder sb = new StringBuilder (valid [0]);
1122                         for (int i = 1; i < count - 1; i++) {
1123                                 sb.Append ("', `");
1124                                 sb.Append (valid [i]);
1125                         }
1126                         if (count > 1) {
1127                                 sb.Append ("' or `");
1128                                 sb.Append (valid [count - 1]);
1129                         }
1130
1131                         ec.Report.Error (119, loc, 
1132                                 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1133                 }
1134                 
1135                 public static void UnsafeError (ResolveContext ec, Location loc)
1136                 {
1137                         UnsafeError (ec.Report, loc);
1138                 }
1139
1140                 public static void UnsafeError (Report Report, Location loc)
1141                 {
1142                         Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1143                 }
1144
1145                 //
1146                 // Converts `source' to an int, uint, long or ulong.
1147                 //
1148                 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1149                 {
1150                         var btypes = ec.BuiltinTypes;
1151
1152                         if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1153                                 Arguments args = new Arguments (1);
1154                                 args.Add (new Argument (source));
1155                                 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1156                         }
1157
1158                         Expression converted;
1159                         
1160                         using (ec.Set (ResolveContext.Options.CheckedScope)) {
1161                                 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1162                                 if (converted == null)
1163                                         converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1164                                 if (converted == null)
1165                                         converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1166                                 if (converted == null)
1167                                         converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1168
1169                                 if (converted == null) {
1170                                         source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1171                                         return null;
1172                                 }
1173                         }
1174
1175                         if (pointerArray)
1176                                 return converted;
1177
1178                         //
1179                         // Only positive constants are allowed at compile time
1180                         //
1181                         Constant c = converted as Constant;
1182                         if (c != null && c.IsNegative)
1183                                 Error_NegativeArrayIndex (ec, source.loc);
1184
1185                         // No conversion needed to array index
1186                         if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1187                                 return converted;
1188
1189                         return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1190                 }
1191
1192                 //
1193                 // Derived classes implement this method by cloning the fields that
1194                 // could become altered during the Resolve stage
1195                 //
1196                 // Only expressions that are created for the parser need to implement
1197                 // this.
1198                 //
1199                 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1200                 {
1201                         throw new NotImplementedException (
1202                                 String.Format (
1203                                         "CloneTo not implemented for expression {0}", this.GetType ()));
1204                 }
1205
1206                 //
1207                 // Clones an expression created by the parser.
1208                 //
1209                 // We only support expressions created by the parser so far, not
1210                 // expressions that have been resolved (many more classes would need
1211                 // to implement CloneTo).
1212                 //
1213                 // This infrastructure is here merely for Lambda expressions which
1214                 // compile the same code using different type values for the same
1215                 // arguments to find the correct overload
1216                 //
1217                 public virtual Expression Clone (CloneContext clonectx)
1218                 {
1219                         Expression cloned = (Expression) MemberwiseClone ();
1220                         CloneTo (clonectx, cloned);
1221
1222                         return cloned;
1223                 }
1224
1225                 //
1226                 // Implementation of expression to expression tree conversion
1227                 //
1228                 public abstract Expression CreateExpressionTree (ResolveContext ec);
1229
1230                 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1231                 {
1232                         return CreateExpressionFactoryCall (ec, name, null, args, loc);
1233                 }
1234
1235                 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1236                 {
1237                         return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1238                 }
1239
1240                 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1241                 {
1242                         return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1243                 }
1244
1245                 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1246                 {
1247                         var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1248                         if (t == null)
1249                                 return null;
1250
1251                         return new TypeExpression (t, loc);
1252                 }
1253
1254                 //
1255                 // Implemented by all expressions which support conversion from
1256                 // compiler expression to invokable runtime expression. Used by
1257                 // dynamic C# binder.
1258                 //
1259                 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1260                 {
1261                         throw new NotImplementedException ("MakeExpression for " + GetType ());
1262                 }
1263                         
1264                 public virtual object Accept (StructuralVisitor visitor)
1265                 {
1266                         return visitor.Visit (this);
1267                 }
1268         }
1269
1270         /// <summary>
1271         ///   This is just a base class for expressions that can
1272         ///   appear on statements (invocations, object creation,
1273         ///   assignments, post/pre increment and decrement).  The idea
1274         ///   being that they would support an extra Emition interface that
1275         ///   does not leave a result on the stack.
1276         /// </summary>
1277         public abstract class ExpressionStatement : Expression
1278         {
1279                 public virtual void MarkReachable (Reachability rc)
1280                 {
1281                 }
1282
1283                 public ExpressionStatement ResolveStatement (BlockContext ec)
1284                 {
1285                         Expression e = Resolve (ec);
1286                         if (e == null)
1287                                 return null;
1288
1289                         ExpressionStatement es = e as ExpressionStatement;
1290                         if (es == null || e is AnonymousMethodBody)
1291                                 Error_InvalidExpressionStatement (ec);
1292
1293                         //
1294                         // This is quite expensive warning, try to limit the damage
1295                         //
1296                         if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1297                                 WarningAsyncWithoutWait (ec, e);
1298                         }
1299
1300                         return es;
1301                 }
1302
1303                 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1304                 {
1305                         if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1306                                 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1307                                         ProbingMode = true
1308                                 };
1309
1310                                 //
1311                                 // Need to do full resolve because GetAwaiter can be extension method
1312                                 // available only in this context
1313                                 //
1314                                 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1315                                 if (mg == null)
1316                                         return;
1317
1318                                 var arguments = new Arguments (0);
1319                                 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1320                                 if (mg == null)
1321                                         return;
1322
1323                                 //
1324                                 // Use same check rules as for real await
1325                                 //
1326                                 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1327                                 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1328                                         return;
1329
1330                                 bc.Report.Warning (4014, 1, e.Location,
1331                                         "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1332                                 return;
1333                         }
1334
1335                         var inv = e as Invocation;
1336                         if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1337                                 // The warning won't be reported for imported methods to maintain warning compatiblity with csc 
1338                                 bc.Report.Warning (4014, 1, e.Location,
1339                                         "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1340                                 return;
1341                         }
1342                 }
1343
1344                 /// <summary>
1345                 ///   Requests the expression to be emitted in a `statement'
1346                 ///   context.  This means that no new value is left on the
1347                 ///   stack after invoking this method (constrasted with
1348                 ///   Emit that will always leave a value on the stack).
1349                 /// </summary>
1350                 public abstract void EmitStatement (EmitContext ec);
1351
1352                 public override void EmitSideEffect (EmitContext ec)
1353                 {
1354                         EmitStatement (ec);
1355                 }
1356         }
1357
1358         /// <summary>
1359         ///   This kind of cast is used to encapsulate the child
1360         ///   whose type is child.Type into an expression that is
1361         ///   reported to return "return_type".  This is used to encapsulate
1362         ///   expressions which have compatible types, but need to be dealt
1363         ///   at higher levels with.
1364         ///
1365         ///   For example, a "byte" expression could be encapsulated in one
1366         ///   of these as an "unsigned int".  The type for the expression
1367         ///   would be "unsigned int".
1368         ///
1369         /// </summary>
1370         public abstract class TypeCast : Expression
1371         {
1372                 protected readonly Expression child;
1373
1374                 protected TypeCast (Expression child, TypeSpec return_type)
1375                 {
1376                         eclass = child.eclass;
1377                         loc = child.Location;
1378                         type = return_type;
1379                         this.child = child;
1380                 }
1381
1382                 public Expression Child {
1383                         get {
1384                                 return child;
1385                         }
1386                 }
1387
1388                 public override bool ContainsEmitWithAwait ()
1389                 {
1390                         return child.ContainsEmitWithAwait ();
1391                 }
1392
1393                 public override Expression CreateExpressionTree (ResolveContext ec)
1394                 {
1395                         Arguments args = new Arguments (2);
1396                         args.Add (new Argument (child.CreateExpressionTree (ec)));
1397                         args.Add (new Argument (new TypeOf (type, loc)));
1398
1399                         if (type.IsPointer || child.Type.IsPointer)
1400                                 Error_PointerInsideExpressionTree (ec);
1401
1402                         return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1403                 }
1404
1405                 protected override Expression DoResolve (ResolveContext ec)
1406                 {
1407                         // This should never be invoked, we are born in fully
1408                         // initialized state.
1409
1410                         return this;
1411                 }
1412
1413                 public override void Emit (EmitContext ec)
1414                 {
1415                         child.Emit (ec);
1416                 }
1417
1418                 public override void FlowAnalysis (FlowAnalysisContext fc)
1419                 {
1420                         child.FlowAnalysis (fc);
1421                 }
1422
1423                 public override SLE.Expression MakeExpression (BuilderContext ctx)
1424                 {
1425 #if STATIC
1426                         return base.MakeExpression (ctx);
1427 #else
1428                         return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1429                                 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1430                                 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1431 #endif
1432                 }
1433
1434                 protected override void CloneTo (CloneContext clonectx, Expression t)
1435                 {
1436                         // Nothing to clone
1437                 }
1438
1439                 public override bool IsNull {
1440                         get { return child.IsNull; }
1441                 }
1442         }
1443
1444         public class EmptyCast : TypeCast {
1445                 EmptyCast (Expression child, TypeSpec target_type)
1446                         : base (child, target_type)
1447                 {
1448                 }
1449
1450                 public static Expression Create (Expression child, TypeSpec type)
1451                 {
1452                         Constant c = child as Constant;
1453                         if (c != null) {
1454                                 var enum_constant = c as EnumConstant;
1455                                 if (enum_constant != null)
1456                                         c = enum_constant.Child;
1457
1458                                 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1459                                         if (c.Type == type)
1460                                                 return c;
1461
1462                                         var res = c.ConvertImplicitly (type);
1463                                         if (res != null)
1464                                                 return res;
1465                                 }
1466                         }
1467
1468                         EmptyCast e = child as EmptyCast;
1469                         if (e != null)
1470                                 return new EmptyCast (e.child, type);
1471
1472                         return new EmptyCast (child, type);
1473                 }
1474
1475                 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1476                 {
1477                         child.EmitBranchable (ec, label, on_true);
1478                 }
1479
1480                 public override void EmitSideEffect (EmitContext ec)
1481                 {
1482                         child.EmitSideEffect (ec);
1483                 }
1484         }
1485
1486         //
1487         // Used for predefined type user operator (no obsolete check, etc.)
1488         //
1489         public class OperatorCast : TypeCast
1490         {
1491                 readonly MethodSpec conversion_operator;
1492
1493                 public OperatorCast (Expression expr, TypeSpec target_type)
1494                         : this (expr, target_type, target_type, false)
1495                 {
1496                 }
1497                 
1498                 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1499                         : this (expr, target_type, target_type, find_explicit)
1500                 {
1501                 }
1502                 
1503                 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1504                         : base (expr, returnType)
1505                 {
1506                         var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1507                         var mi = MemberCache.GetUserOperator (declaringType, op, true);
1508
1509                         if (mi != null) {
1510                                 foreach (MethodSpec oper in mi) {
1511                                         if (oper.ReturnType != returnType)
1512                                                 continue;
1513
1514                                         if (oper.Parameters.Types[0] == expr.Type) {
1515                                                 conversion_operator = oper;
1516                                                 return;
1517                                         }
1518                                 }
1519                         }
1520
1521                         throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1522                                 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1523                 }
1524
1525                 public override void Emit (EmitContext ec)
1526                 {
1527                         child.Emit (ec);
1528                         ec.Emit (OpCodes.Call, conversion_operator);
1529                 }
1530         }
1531         
1532         //
1533         // Constant specialization of EmptyCast.
1534         // We need to special case this since an empty cast of
1535         // a constant is still a constant. 
1536         //
1537         public class EmptyConstantCast : Constant
1538         {
1539                 public readonly Constant child;
1540
1541                 public EmptyConstantCast (Constant child, TypeSpec type)
1542                         : base (child.Location)
1543                 {
1544                         if (child == null)
1545                                 throw new ArgumentNullException ("child");
1546
1547                         this.child = child;
1548                         this.eclass = child.eclass;
1549                         this.type = type;
1550                 }
1551
1552                 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1553                 {
1554                         if (child.Type == target_type)
1555                                 return child;
1556
1557                         // FIXME: check that 'type' can be converted to 'target_type' first
1558                         return child.ConvertExplicitly (in_checked_context, target_type);
1559                 }
1560
1561                 public override Expression CreateExpressionTree (ResolveContext ec)
1562                 {
1563                         Arguments args = Arguments.CreateForExpressionTree (ec, null,
1564                                 child.CreateExpressionTree (ec),
1565                                 new TypeOf (type, loc));
1566
1567                         if (type.IsPointer)
1568                                 Error_PointerInsideExpressionTree (ec);
1569
1570                         return CreateExpressionFactoryCall (ec, "Convert", args);
1571                 }
1572
1573                 public override bool IsDefaultValue {
1574                         get { return child.IsDefaultValue; }
1575                 }
1576
1577                 public override bool IsNegative {
1578                         get { return child.IsNegative; }
1579                 }
1580
1581                 public override bool IsNull {
1582                         get { return child.IsNull; }
1583                 }
1584                 
1585                 public override bool IsOneInteger {
1586                         get { return child.IsOneInteger; }
1587                 }
1588
1589                 public override bool IsSideEffectFree {
1590                         get {
1591                                 return child.IsSideEffectFree;
1592                         }
1593                 }
1594
1595                 public override bool IsZeroInteger {
1596                         get { return child.IsZeroInteger; }
1597                 }
1598
1599                 public override void Emit (EmitContext ec)
1600                 {
1601                         child.Emit (ec);                        
1602                 }
1603
1604                 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1605                 {
1606                         child.EmitBranchable (ec, label, on_true);
1607
1608                         // Only to make verifier happy
1609                         if (TypeManager.IsGenericParameter (type) && child.IsNull)
1610                                 ec.Emit (OpCodes.Unbox_Any, type);
1611                 }
1612
1613                 public override void EmitSideEffect (EmitContext ec)
1614                 {
1615                         child.EmitSideEffect (ec);
1616                 }
1617
1618                 public override object GetValue ()
1619                 {
1620                         return child.GetValue ();
1621                 }
1622
1623                 public override string GetValueAsLiteral ()
1624                 {
1625                         return child.GetValueAsLiteral ();
1626                 }
1627
1628                 public override long GetValueAsLong ()
1629                 {
1630                         return child.GetValueAsLong ();
1631                 }
1632
1633                 public override Constant ConvertImplicitly (TypeSpec target_type)
1634                 {
1635                         if (type == target_type)
1636                                 return this;
1637
1638                         // FIXME: Do we need to check user conversions?
1639                         if (!Convert.ImplicitStandardConversionExists (this, target_type))
1640                                 return null;
1641
1642                         return child.ConvertImplicitly (target_type);
1643                 }
1644         }
1645
1646         /// <summary>
1647         ///  This class is used to wrap literals which belong inside Enums
1648         /// </summary>
1649         public class EnumConstant : Constant
1650         {
1651                 public Constant Child;
1652
1653                 public EnumConstant (Constant child, TypeSpec enum_type)
1654                         : base (child.Location)
1655                 {
1656                         this.Child = child;
1657
1658                         this.eclass = ExprClass.Value;
1659                         this.type = enum_type;
1660                 }
1661
1662                 protected EnumConstant (Location loc)
1663                         : base (loc)
1664                 {
1665                 }
1666
1667                 public override void Emit (EmitContext ec)
1668                 {
1669                         Child.Emit (ec);
1670                 }
1671
1672                 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1673                 {
1674                         Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1675                 }
1676
1677                 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1678                 {
1679                         Child.EmitBranchable (ec, label, on_true);
1680                 }
1681
1682                 public override void EmitSideEffect (EmitContext ec)
1683                 {
1684                         Child.EmitSideEffect (ec);
1685                 }
1686
1687                 public override string GetSignatureForError()
1688                 {
1689                         return Type.GetSignatureForError ();
1690                 }
1691
1692                 public override object GetValue ()
1693                 {
1694                         return Child.GetValue ();
1695                 }
1696
1697 #if !STATIC
1698                 public override object GetTypedValue ()
1699                 {
1700                         //
1701                         // The method can be used in dynamic context only (on closed types)
1702                         //
1703                         // System.Enum.ToObject cannot be called on dynamic types
1704                         // EnumBuilder has to be used, but we cannot use EnumBuilder
1705                         // because it does not properly support generics
1706                         //
1707                         return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1708                 }
1709 #endif
1710
1711                 public override string GetValueAsLiteral ()
1712                 {
1713                         return Child.GetValueAsLiteral ();
1714                 }
1715
1716                 public override long GetValueAsLong ()
1717                 {
1718                         return Child.GetValueAsLong ();
1719                 }
1720
1721                 public EnumConstant Increment()
1722                 {
1723                         return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1724                 }
1725
1726                 public override bool IsDefaultValue {
1727                         get {
1728                                 return Child.IsDefaultValue;
1729                         }
1730                 }
1731
1732                 public override bool IsSideEffectFree {
1733                         get {
1734                                 return Child.IsSideEffectFree;
1735                         }
1736                 }
1737
1738                 public override bool IsZeroInteger {
1739                         get { return Child.IsZeroInteger; }
1740                 }
1741
1742                 public override bool IsNegative {
1743                         get {
1744                                 return Child.IsNegative;
1745                         }
1746                 }
1747
1748                 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1749                 {
1750                         if (Child.Type == target_type)
1751                                 return Child;
1752
1753                         return Child.ConvertExplicitly (in_checked_context, target_type);
1754                 }
1755
1756                 public override Constant ConvertImplicitly (TypeSpec type)
1757                 {
1758                         if (this.type == type) {
1759                                 return this;
1760                         }
1761
1762                         if (!Convert.ImplicitStandardConversionExists (this, type)){
1763                                 return null;
1764                         }
1765
1766                         return Child.ConvertImplicitly (type);
1767                 }
1768         }
1769
1770         /// <summary>
1771         ///   This kind of cast is used to encapsulate Value Types in objects.
1772         ///
1773         ///   The effect of it is to box the value type emitted by the previous
1774         ///   operation.
1775         /// </summary>
1776         public class BoxedCast : TypeCast {
1777
1778                 public BoxedCast (Expression expr, TypeSpec target_type)
1779                         : base (expr, target_type)
1780                 {
1781                         eclass = ExprClass.Value;
1782                 }
1783                 
1784                 protected override Expression DoResolve (ResolveContext ec)
1785                 {
1786                         // This should never be invoked, we are born in fully
1787                         // initialized state.
1788
1789                         return this;
1790                 }
1791
1792                 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1793                 {
1794                         // Only boxing to object type is supported
1795                         if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1796                                 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1797                                 return;
1798                         }
1799
1800                         enc.Encode (child.Type);
1801                         child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1802                 }
1803
1804                 public override void Emit (EmitContext ec)
1805                 {
1806                         base.Emit (ec);
1807                         
1808                         ec.Emit (OpCodes.Box, child.Type);
1809                 }
1810
1811                 public override void EmitSideEffect (EmitContext ec)
1812                 {
1813                         // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1814                         // so, we need to emit the box+pop instructions in most cases
1815                         if (child.Type.IsStruct &&
1816                             (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1817                                 child.EmitSideEffect (ec);
1818                         else
1819                                 base.EmitSideEffect (ec);
1820                 }
1821         }
1822
1823         public class UnboxCast : TypeCast {
1824                 public UnboxCast (Expression expr, TypeSpec return_type)
1825                         : base (expr, return_type)
1826                 {
1827                 }
1828
1829                 protected override Expression DoResolve (ResolveContext ec)
1830                 {
1831                         // This should never be invoked, we are born in fully
1832                         // initialized state.
1833
1834                         return this;
1835                 }
1836
1837                 public override void Emit (EmitContext ec)
1838                 {
1839                         base.Emit (ec);
1840
1841                         ec.Emit (OpCodes.Unbox_Any, type);
1842                 }
1843         }
1844         
1845         /// <summary>
1846         ///   This is used to perform explicit numeric conversions.
1847         ///
1848         ///   Explicit numeric conversions might trigger exceptions in a checked
1849         ///   context, so they should generate the conv.ovf opcodes instead of
1850         ///   conv opcodes.
1851         /// </summary>
1852         public class ConvCast : TypeCast {
1853                 public enum Mode : byte {
1854                         I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1855                         U1_I1, U1_CH,
1856                         I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1857                         U2_I1, U2_U1, U2_I2, U2_CH,
1858                         I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1859                         U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1860                         I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1861                         U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1862                         CH_I1, CH_U1, CH_I2,
1863                         R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1864                         R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1865                         I_I8,
1866                 }
1867
1868                 Mode mode;
1869                 
1870                 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1871                         : base (child, return_type)
1872                 {
1873                         mode = m;
1874                 }
1875
1876                 protected override Expression DoResolve (ResolveContext ec)
1877                 {
1878                         // This should never be invoked, we are born in fully
1879                         // initialized state.
1880
1881                         return this;
1882                 }
1883
1884                 public override string ToString ()
1885                 {
1886                         return String.Format ("ConvCast ({0}, {1})", mode, child);
1887                 }
1888                 
1889                 public override void Emit (EmitContext ec)
1890                 {
1891                         base.Emit (ec);
1892                         Emit (ec, mode);
1893                 }
1894
1895                 public static void Emit (EmitContext ec, Mode mode)
1896                 {
1897                         if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1898                                 switch (mode){
1899                                 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1900                                 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1901                                 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1902                                 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1903                                 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1904
1905                                 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1906                                 case Mode.U1_CH: /* nothing */ break;
1907
1908                                 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1909                                 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1910                                 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1911                                 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1912                                 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1913                                 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1914
1915                                 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1916                                 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1917                                 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1918                                 case Mode.U2_CH: /* nothing */ break;
1919
1920                                 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1921                                 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1922                                 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1923                                 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1924                                 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1925                                 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1926                                 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1927
1928                                 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1929                                 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1930                                 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1931                                 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1932                                 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1933                                 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1934
1935                                 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1936                                 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1937                                 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1938                                 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1939                                 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1940                                 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1941                                 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1942                                 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1943                                 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1944
1945                                 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1946                                 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1947                                 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1948                                 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1949                                 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1950                                 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1951                                 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1952                                 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1953                                 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1954
1955                                 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1956                                 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1957                                 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1958
1959                                 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1960                                 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1961                                 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1962                                 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1963                                 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1964                                 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1965                                 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1966                                 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1967                                 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1968
1969                                 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1970                                 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1971                                 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1972                                 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1973                                 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1974                                 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1975                                 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1976                                 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1977                                 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1978                                 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1979
1980                                 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1981                                 }
1982                         } else {
1983                                 switch (mode){
1984                                 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1985                                 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1986                                 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1987                                 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1988                                 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1989
1990                                 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1991                                 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1992
1993                                 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1994                                 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1995                                 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1996                                 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1997                                 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1998                                 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1999
2000                                 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2001                                 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2002                                 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2003                                 case Mode.U2_CH: /* nothing */ break;
2004
2005                                 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2006                                 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2007                                 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2008                                 case Mode.I4_U4: /* nothing */ break;
2009                                 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2010                                 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2011                                 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2012
2013                                 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2014                                 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2015                                 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2016                                 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2017                                 case Mode.U4_I4: /* nothing */ break;
2018                                 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2019
2020                                 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2021                                 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2022                                 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2023                                 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2024                                 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2025                                 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2026                                 case Mode.I8_U8: /* nothing */ break;
2027                                 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2028                                 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2029
2030                                 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2031                                 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2032                                 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2033                                 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2034                                 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2035                                 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2036                                 case Mode.U8_I8: /* nothing */ break;
2037                                 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2038                                 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2039
2040                                 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2041                                 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2042                                 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2043
2044                                 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2045                                 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2046                                 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2047                                 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2048                                 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2049                                 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2050                                 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2051                                 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2052                                 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2053
2054                                 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2055                                 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2056                                 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2057                                 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2058                                 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2059                                 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2060                                 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2061                                 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2062                                 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2063                                 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2064
2065                                 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2066                                 }
2067                         }
2068                 }
2069         }
2070         
2071         class OpcodeCast : TypeCast
2072         {
2073                 readonly OpCode op;
2074                 
2075                 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2076                         : base (child, return_type)
2077                 {
2078                         this.op = op;
2079                 }
2080
2081                 protected override Expression DoResolve (ResolveContext ec)
2082                 {
2083                         // This should never be invoked, we are born in fully
2084                         // initialized state.
2085
2086                         return this;
2087                 }
2088
2089                 public override void Emit (EmitContext ec)
2090                 {
2091                         base.Emit (ec);
2092                         ec.Emit (op);
2093                 }
2094
2095                 public TypeSpec UnderlyingType {
2096                         get { return child.Type; }
2097                 }
2098         }
2099
2100         //
2101         // Opcode casts expression with 2 opcodes but only
2102         // single expression tree node
2103         //
2104         class OpcodeCastDuplex : OpcodeCast
2105         {
2106                 readonly OpCode second;
2107
2108                 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2109                         : base (child, returnType, first)
2110                 {
2111                         this.second = second;
2112                 }
2113
2114                 public override void Emit (EmitContext ec)
2115                 {
2116                         base.Emit (ec);
2117                         ec.Emit (second);
2118                 }
2119         }
2120
2121         /// <summary>
2122         ///   This kind of cast is used to encapsulate a child and cast it
2123         ///   to the class requested
2124         /// </summary>
2125         public sealed class ClassCast : TypeCast {
2126                 readonly bool forced;
2127                 
2128                 public ClassCast (Expression child, TypeSpec return_type)
2129                         : base (child, return_type)
2130                 {
2131                 }
2132                 
2133                 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2134                         : base (child, return_type)
2135                 {
2136                         this.forced = forced;
2137                 }
2138
2139                 public override void Emit (EmitContext ec)
2140                 {
2141                         base.Emit (ec);
2142
2143                         bool gen = TypeManager.IsGenericParameter (child.Type);
2144                         if (gen)
2145                                 ec.Emit (OpCodes.Box, child.Type);
2146                         
2147                         if (type.IsGenericParameter) {
2148                                 ec.Emit (OpCodes.Unbox_Any, type);
2149                                 return;
2150                         }
2151                         
2152                         if (gen && !forced)
2153                                 return;
2154                         
2155                         ec.Emit (OpCodes.Castclass, type);
2156                 }
2157         }
2158
2159         //
2160         // Created during resolving pahse when an expression is wrapped or constantified
2161         // and original expression can be used later (e.g. for expression trees)
2162         //
2163         public class ReducedExpression : Expression
2164         {
2165                 public sealed class ReducedConstantExpression : EmptyConstantCast
2166                 {
2167                         readonly Expression orig_expr;
2168
2169                         public ReducedConstantExpression (Constant expr, Expression orig_expr)
2170                                 : base (expr, expr.Type)
2171                         {
2172                                 this.orig_expr = orig_expr;
2173                         }
2174
2175                         public Expression OriginalExpression {
2176                                 get {
2177                                         return orig_expr;
2178                                 }
2179                         }
2180
2181                         public override Constant ConvertImplicitly (TypeSpec target_type)
2182                         {
2183                                 Constant c = base.ConvertImplicitly (target_type);
2184                                 if (c != null)
2185                                         c = new ReducedConstantExpression (c, orig_expr);
2186
2187                                 return c;
2188                         }
2189
2190                         public override Expression CreateExpressionTree (ResolveContext ec)
2191                         {
2192                                 return orig_expr.CreateExpressionTree (ec);
2193                         }
2194
2195                         public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2196                         {
2197                                 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2198                                 if (c != null)
2199                                         c = new ReducedConstantExpression (c, orig_expr);
2200                                 return c;
2201                         }
2202
2203                         public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2204                         {
2205                                 //
2206                                 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2207                                 //
2208                                 if (orig_expr is Conditional)
2209                                         child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2210                                 else
2211                                         base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2212                         }
2213                 }
2214
2215                 sealed class ReducedExpressionStatement : ExpressionStatement
2216                 {
2217                         readonly Expression orig_expr;
2218                         readonly ExpressionStatement stm;
2219
2220                         public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2221                         {
2222                                 this.orig_expr = orig;
2223                                 this.stm = stm;
2224                                 this.eclass = stm.eclass;
2225                                 this.type = stm.Type;
2226
2227                                 this.loc = orig.Location;
2228                         }
2229
2230                         public override bool ContainsEmitWithAwait ()
2231                         {
2232                                 return stm.ContainsEmitWithAwait ();
2233                         }
2234
2235                         public override Expression CreateExpressionTree (ResolveContext ec)
2236                         {
2237                                 return orig_expr.CreateExpressionTree (ec);
2238                         }
2239
2240                         protected override Expression DoResolve (ResolveContext ec)
2241                         {
2242                                 return this;
2243                         }
2244
2245                         public override void Emit (EmitContext ec)
2246                         {
2247                                 stm.Emit (ec);
2248                         }
2249
2250                         public override void EmitStatement (EmitContext ec)
2251                         {
2252                                 stm.EmitStatement (ec);
2253                         }
2254
2255                         public override void FlowAnalysis (FlowAnalysisContext fc)
2256                         {
2257                                 stm.FlowAnalysis (fc);
2258                         }
2259                 }
2260
2261                 readonly Expression expr, orig_expr;
2262
2263                 private ReducedExpression (Expression expr, Expression orig_expr)
2264                 {
2265                         this.expr = expr;
2266                         this.eclass = expr.eclass;
2267                         this.type = expr.Type;
2268                         this.orig_expr = orig_expr;
2269                         this.loc = orig_expr.Location;
2270                 }
2271
2272                 #region Properties
2273
2274                 public override bool IsSideEffectFree {
2275                         get {
2276                                 return expr.IsSideEffectFree;
2277                         }
2278                 }
2279
2280                 public Expression OriginalExpression {
2281                         get {
2282                                 return orig_expr;
2283                         }
2284                 }
2285
2286                 #endregion
2287
2288                 public override bool ContainsEmitWithAwait ()
2289                 {
2290                         return expr.ContainsEmitWithAwait ();
2291                 }
2292
2293                 //
2294                 // Creates fully resolved expression switcher
2295                 //
2296                 public static Constant Create (Constant expr, Expression original_expr)
2297                 {
2298                         if (expr.eclass == ExprClass.Unresolved)
2299                                 throw new ArgumentException ("Unresolved expression");
2300
2301                         return new ReducedConstantExpression (expr, original_expr);
2302                 }
2303
2304                 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2305                 {
2306                         return new ReducedExpressionStatement (s, orig);
2307                 }
2308
2309                 public static Expression Create (Expression expr, Expression original_expr)
2310                 {
2311                         return Create (expr, original_expr, true);
2312                 }
2313
2314                 //
2315                 // Creates unresolved reduce expression. The original expression has to be
2316                 // already resolved. Created expression is constant based based on `expr'
2317                 // value unless canBeConstant is used
2318                 //
2319                 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2320                 {
2321                         if (canBeConstant) {
2322                                 Constant c = expr as Constant;
2323                                 if (c != null)
2324                                         return Create (c, original_expr);
2325                         }
2326
2327                         ExpressionStatement s = expr as ExpressionStatement;
2328                         if (s != null)
2329                                 return Create (s, original_expr);
2330
2331                         if (expr.eclass == ExprClass.Unresolved)
2332                                 throw new ArgumentException ("Unresolved expression");
2333
2334                         return new ReducedExpression (expr, original_expr);
2335                 }
2336
2337                 public override Expression CreateExpressionTree (ResolveContext ec)
2338                 {
2339                         return orig_expr.CreateExpressionTree (ec);
2340                 }
2341
2342                 protected override Expression DoResolve (ResolveContext ec)
2343                 {
2344                         return this;
2345                 }
2346
2347                 public override void Emit (EmitContext ec)
2348                 {
2349                         expr.Emit (ec);
2350                 }
2351
2352                 public override Expression EmitToField (EmitContext ec)
2353                 {
2354                         return expr.EmitToField(ec);
2355                 }
2356
2357                 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2358                 {
2359                         expr.EmitBranchable (ec, target, on_true);
2360                 }
2361
2362                 public override void FlowAnalysis (FlowAnalysisContext fc)
2363                 {
2364                         expr.FlowAnalysis (fc);
2365                 }
2366
2367                 public override SLE.Expression MakeExpression (BuilderContext ctx)
2368                 {
2369                         return orig_expr.MakeExpression (ctx);
2370                 }
2371         }
2372
2373         //
2374         // Standard composite pattern
2375         //
2376         public abstract class CompositeExpression : Expression
2377         {
2378                 protected Expression expr;
2379
2380                 protected CompositeExpression (Expression expr)
2381                 {
2382                         this.expr = expr;
2383                         this.loc = expr.Location;
2384                 }
2385
2386                 public override bool ContainsEmitWithAwait ()
2387                 {
2388                         return expr.ContainsEmitWithAwait ();
2389                 }
2390
2391                 public override Expression CreateExpressionTree (ResolveContext rc)
2392                 {
2393                         return expr.CreateExpressionTree (rc);
2394                 }
2395
2396                 public Expression Child {
2397                         get { return expr; }
2398                 }
2399
2400                 protected override Expression DoResolve (ResolveContext rc)
2401                 {
2402                         expr = expr.Resolve (rc);
2403                         if (expr == null)
2404                                 return null;
2405
2406                         type = expr.Type;
2407                         eclass = expr.eclass;
2408                         return this;
2409                 }
2410
2411                 public override void Emit (EmitContext ec)
2412                 {
2413                         expr.Emit (ec);
2414                 }
2415
2416                 public override bool IsNull {
2417                         get { return expr.IsNull; }
2418                 }
2419         }
2420
2421         //
2422         // Base of expressions used only to narrow resolve flow
2423         //
2424         public abstract class ShimExpression : Expression
2425         {
2426                 protected Expression expr;
2427
2428                 protected ShimExpression (Expression expr)
2429                 {
2430                         this.expr = expr;
2431                 }
2432
2433                 public Expression Expr {
2434                         get {
2435                                 return expr;
2436                         }
2437                 }
2438
2439                 protected override void CloneTo (CloneContext clonectx, Expression t)
2440                 {
2441                         if (expr == null)
2442                                 return;
2443
2444                         ShimExpression target = (ShimExpression) t;
2445                         target.expr = expr.Clone (clonectx);
2446                 }
2447
2448                 public override bool ContainsEmitWithAwait ()
2449                 {
2450                         return expr.ContainsEmitWithAwait ();
2451                 }
2452
2453                 public override Expression CreateExpressionTree (ResolveContext ec)
2454                 {
2455                         throw new NotSupportedException ("ET");
2456                 }
2457
2458                 public override void Emit (EmitContext ec)
2459                 {
2460                         throw new InternalErrorException ("Missing Resolve call");
2461                 }
2462         }
2463
2464         public class UnreachableExpression : Expression
2465         {
2466                 public UnreachableExpression (Expression expr)
2467                 {
2468                         this.loc = expr.Location;
2469                 }
2470
2471                 public override Expression CreateExpressionTree (ResolveContext ec)
2472                 {
2473                         // TODO: is it ok
2474                         throw new NotImplementedException ();
2475                 }
2476
2477                 protected override Expression DoResolve (ResolveContext rc)
2478                 {
2479                         throw new NotSupportedException ();
2480                 }
2481
2482                 public override void FlowAnalysis (FlowAnalysisContext fc)
2483                 {
2484                         fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2485                 }
2486
2487                 public override void Emit (EmitContext ec)
2488                 {
2489                 }
2490
2491                 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2492                 {
2493                 }
2494         }
2495
2496         //
2497         // Unresolved type name expressions
2498         //
2499         public abstract class ATypeNameExpression : FullNamedExpression
2500         {
2501                 string name;
2502                 protected TypeArguments targs;
2503
2504                 protected ATypeNameExpression (string name, Location l)
2505                 {
2506                         this.name = name;
2507                         loc = l;
2508                 }
2509
2510                 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2511                 {
2512                         this.name = name;
2513                         this.targs = targs;
2514                         loc = l;
2515                 }
2516
2517                 protected ATypeNameExpression (string name, int arity, Location l)
2518                         : this (name, new UnboundTypeArguments (arity), l)
2519                 {
2520                 }
2521
2522                 #region Properties
2523
2524                 protected int Arity {
2525                         get {
2526                                 return targs == null ? 0 : targs.Count;
2527                         }
2528                 }
2529
2530                 public bool HasTypeArguments {
2531                         get {
2532                                 return targs != null && !targs.IsEmpty;
2533                         }
2534                 }
2535
2536                 public string Name {
2537                         get {
2538                                 return name;
2539                         }
2540                         set {
2541                                 name = value;
2542                         }
2543                 }
2544
2545                 public TypeArguments TypeArguments {
2546                         get {
2547                                 return targs;
2548                         }
2549                 }
2550
2551                 #endregion
2552
2553                 public override bool Equals (object obj)
2554                 {
2555                         ATypeNameExpression atne = obj as ATypeNameExpression;
2556                         return atne != null && atne.Name == Name &&
2557                                 (targs == null || targs.Equals (atne.targs));
2558                 }
2559
2560                 protected void Error_OpenGenericTypeIsNotAllowed (IMemberContext mc)
2561                 {
2562                         mc.Module.Compiler.Report.Error (7003, Location, "Unbound generic name is not valid in this context");
2563                 }
2564
2565                 public override int GetHashCode ()
2566                 {
2567                         return Name.GetHashCode ();
2568                 }
2569
2570                 // TODO: Move it to MemberCore
2571                 public static string GetMemberType (MemberCore mc)
2572                 {
2573                         if (mc is Property)
2574                                 return "property";
2575                         if (mc is Indexer)
2576                                 return "indexer";
2577                         if (mc is FieldBase)
2578                                 return "field";
2579                         if (mc is MethodCore)
2580                                 return "method";
2581                         if (mc is EnumMember)
2582                                 return "enum";
2583                         if (mc is Event)
2584                                 return "event";
2585
2586                         return "type";
2587                 }
2588
2589                 public override string GetSignatureForError ()
2590                 {
2591                         if (targs != null) {
2592                                 return Name + "<" + targs.GetSignatureForError () + ">";
2593                         }
2594
2595                         return Name;
2596                 }
2597
2598                 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2599         }
2600         
2601         /// <summary>
2602         ///   SimpleName expressions are formed of a single word and only happen at the beginning 
2603         ///   of a dotted-name.
2604         /// </summary>
2605         public class SimpleName : ATypeNameExpression
2606         {
2607                 public SimpleName (string name, Location l)
2608                         : base (name, l)
2609                 {
2610                 }
2611
2612                 public SimpleName (string name, TypeArguments args, Location l)
2613                         : base (name, args, l)
2614                 {
2615                 }
2616
2617                 public SimpleName (string name, int arity, Location l)
2618                         : base (name, arity, l)
2619                 {
2620                 }
2621
2622                 public SimpleName GetMethodGroup ()
2623                 {
2624                         return new SimpleName (Name, targs, loc);
2625                 }
2626
2627                 protected override Expression DoResolve (ResolveContext rc)
2628                 {
2629                         return SimpleNameResolve (rc, null);
2630                 }
2631
2632                 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2633                 {
2634                         return SimpleNameResolve (ec, right_side);
2635                 }
2636
2637                 public void Error_NameDoesNotExist (ResolveContext rc)
2638                 {
2639                         rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2640                 }
2641
2642                 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2643                 {
2644                         if (ctx.CurrentType != null) {
2645                                 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2646                                 if (member != null) {
2647                                         Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2648                                         return;
2649                                 }
2650                         }
2651
2652                         var report = ctx.Module.Compiler.Report;
2653
2654                         var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2655                         if (retval != null) {
2656                                 report.SymbolRelatedToPreviousError (retval.Type);
2657                                 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2658                                 return;
2659                         }
2660
2661                         retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2662                         if (retval != null) {
2663                                 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2664                                 return;
2665                         }
2666
2667                         var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2668                         if (ns_candidates != null) {
2669                                 if (ctx is UsingAliasNamespace.AliasContext) {
2670                                         report.Error (246, loc,
2671                                                 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2672                                                 ns_candidates[0], Name);
2673                                 } else {
2674                                         string usings = string.Join ("' or `", ns_candidates.ToArray ());
2675                                         report.Error (246, loc,
2676                                                 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2677                                                 Name, usings);
2678                                 }
2679                         } else {
2680                                 report.Error (246, loc,
2681                                         "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2682                                         Name);
2683                         }
2684                 }
2685
2686                 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2687                 {
2688                         FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2689
2690                         if (fne != null) {
2691                                 if (fne.Type != null && Arity > 0) {
2692                                         if (HasTypeArguments) {
2693                                                 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2694                                                 if (ct.ResolveAsType (mc) == null)
2695                                                         return null;
2696
2697                                                 return ct;
2698                                         }
2699
2700                                         if (!allowUnboundTypeArguments)
2701                                                 Error_OpenGenericTypeIsNotAllowed (mc);
2702
2703                                         return new GenericOpenTypeExpr (fne.Type, loc);
2704                                 }
2705
2706                                 //
2707                                 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2708                                 //
2709                                 if (!(fne is NamespaceExpression))
2710                                         return fne;
2711                         }
2712
2713                         if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2714                                 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2715                                         mc.Module.Compiler.Report.Error (1980, Location,
2716                                                 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2717                                                 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2718                                 }
2719
2720                                 fne = new DynamicTypeExpr (loc);
2721                                 fne.ResolveAsType (mc);
2722                         }
2723
2724                         if (fne != null)
2725                                 return fne;
2726
2727                         Error_TypeOrNamespaceNotFound (mc);
2728                         return null;
2729                 }
2730
2731                 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2732                 {
2733                         return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2734                 }
2735
2736                 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2737                 {
2738                         int lookup_arity = Arity;
2739                         bool errorMode = false;
2740                         Expression e;
2741                         Block current_block = rc.CurrentBlock;
2742                         INamedBlockVariable variable = null;
2743                         bool variable_found = false;
2744
2745                         while (true) {
2746                                 //
2747                                 // Stage 1: binding to local variables or parameters
2748                                 //
2749                                 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2750                                 //
2751                                 if (current_block != null && lookup_arity == 0) {
2752                                         if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2753                                                 if (!variable.IsDeclared) {
2754                                                         // We found local name in accessible block but it's not
2755                                                         // initialized yet, maybe the user wanted to bind to something else
2756                                                         errorMode = true;
2757                                                         variable_found = true;
2758                                                 } else {
2759                                                         e = variable.CreateReferenceExpression (rc, loc);
2760                                                         if (e != null) {
2761                                                                 if (Arity > 0)
2762                                                                         Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2763
2764                                                                 return e;
2765                                                         }
2766                                                 }
2767                                         }
2768                                 }
2769
2770                                 //
2771                                 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2772                                 //
2773                                 TypeSpec member_type = rc.CurrentType;
2774                                 for (; member_type != null; member_type = member_type.DeclaringType) {
2775                                         e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2776                                         if (e == null)
2777                                                 continue;
2778
2779                                         var me = e as MemberExpr;
2780                                         if (me == null) {
2781                                                 // The name matches a type, defer to ResolveAsTypeStep
2782                                                 if (e is TypeExpr)
2783                                                         break;
2784
2785                                                 continue;
2786                                         }
2787
2788                                         if (errorMode) {
2789                                                 if (variable != null) {
2790                                                         if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2791                                                                 rc.Report.Error (844, loc,
2792                                                                         "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2793                                                                         Name, me.GetSignatureForError ());
2794                                                         } else {
2795                                                                 break;
2796                                                         }
2797                                                 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2798                                                         // Leave it to overload resolution to report correct error
2799                                                 } else {
2800                                                         // TODO: rc.Report.SymbolRelatedToPreviousError ()
2801                                                         ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2802                                                 }
2803                                         } else {
2804                                                 // LAMESPEC: again, ignores InvocableOnly
2805                                                 if (variable != null) {
2806                                                         rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2807                                                         rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2808                                                 }
2809
2810                                                 //
2811                                                 // MemberLookup does not check accessors availability, this is actually needed for properties only
2812                                                 //
2813                                                 var pe = me as PropertyExpr;
2814                                                 if (pe != null) {
2815
2816                                                         // Break as there is no other overload available anyway
2817                                                         if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2818                                                                 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2819                                                                         break;
2820
2821                                                                 pe.Getter = pe.PropertyInfo.Get;
2822                                                         } else {
2823                                                                 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2824                                                                         break;
2825
2826                                                                 pe.Setter = pe.PropertyInfo.Set;
2827                                                         }
2828                                                 }
2829                                         }
2830
2831                                         // TODO: It's used by EventExpr -> FieldExpr transformation only
2832                                         // TODO: Should go to MemberAccess
2833                                         me = me.ResolveMemberAccess (rc, null, null);
2834
2835                                         if (Arity > 0) {
2836                                                 targs.Resolve (rc);
2837                                                 me.SetTypeArguments (rc, targs);
2838                                         }
2839
2840                                         return me;
2841                                 }
2842
2843                                 //
2844                                 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2845                                 //
2846                                 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2847                                         if (IsPossibleTypeOrNamespace (rc)) {
2848                                                 if (variable != null) {
2849                                                         rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2850                                                         rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2851                                                 }
2852
2853                                                 return ResolveAsTypeOrNamespace (rc, false);
2854                                         }
2855                                 }
2856
2857                                 var mg = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2858                                 if (mg != null) {
2859                                         if (Arity > 0) {
2860                                                 targs.Resolve (rc);
2861                                                 mg.SetTypeArguments (rc, targs);
2862                                         }
2863                                         return mg;
2864                                 }
2865
2866                                 if (Name == "nameof")
2867                                         return new NameOf (this);
2868
2869                                 if (errorMode) {
2870                                         if (variable_found) {
2871                                                 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2872                                         } else {
2873                                                 if (Arity > 0) {
2874                                                         var tparams = rc.CurrentTypeParameters;
2875                                                         if (tparams != null) {
2876                                                                 if (tparams.Find (Name) != null) {
2877                                                                         Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2878                                                                         return null;
2879                                                                 }
2880                                                         }
2881
2882                                                         var ct = rc.CurrentType;
2883                                                         do {
2884                                                                 if (ct.MemberDefinition.TypeParametersCount > 0) {
2885                                                                         foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2886                                                                                 if (ctp.Name == Name) {
2887                                                                                         Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2888                                                                                         return null;
2889                                                                                 }
2890                                                                         }
2891                                                                 }
2892
2893                                                                 ct = ct.DeclaringType;
2894                                                         } while (ct != null);
2895                                                 }
2896
2897                                                 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2898                                                         e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2899                                                         if (e != null) {
2900                                                                 rc.Report.SymbolRelatedToPreviousError (e.Type);
2901                                                                 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2902                                                                 return e;
2903                                                         }
2904                                                 } else {
2905                                                         var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2906                                                         if (me != null) {
2907                                                                 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2908                                                                 return ErrorExpression.Instance;
2909                                                         }
2910                                                 }
2911
2912                                                 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2913                                                 if (e != null) {
2914                                                         if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2915                                                                 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2916                                                                 return e;
2917                                                         }
2918
2919                                                         if (e is TypeExpr) {
2920                                                                 // TypeExpression does not have correct location
2921                                                                 if (e is TypeExpression)
2922                                                                         e = new TypeExpression (e.Type, loc);
2923
2924                                                                 return e;
2925                                                         }
2926                                                 }
2927
2928                                                 Error_NameDoesNotExist (rc);
2929                                         }
2930
2931                                         return ErrorExpression.Instance;
2932                                 }
2933
2934                                 if (rc.Module.Evaluator != null) {
2935                                         var fi = rc.Module.Evaluator.LookupField (Name);
2936                                         if (fi != null)
2937                                                 return new FieldExpr (fi.Item1, loc);
2938                                 }
2939
2940                                 lookup_arity = 0;
2941                                 errorMode = true;
2942                         }
2943                 }
2944                 
2945                 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2946                 {
2947                         Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2948
2949                         if (e == null)
2950                                 return null;
2951
2952                         if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2953                                 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2954                                 return e;
2955                         }
2956
2957                         if (right_side != null) {
2958                                 e = e.ResolveLValue (ec, right_side);
2959                         } else {
2960                                 e = e.Resolve (ec);
2961                         }
2962
2963                         return e;
2964                 }
2965                 
2966                 public override object Accept (StructuralVisitor visitor)
2967                 {
2968                         return visitor.Visit (this);
2969                 }
2970         }
2971
2972         /// <summary>
2973         ///   Represents a namespace or a type.  The name of the class was inspired by
2974         ///   section 10.8.1 (Fully Qualified Names).
2975         /// </summary>
2976         public abstract class FullNamedExpression : Expression
2977         {
2978                 protected override void CloneTo (CloneContext clonectx, Expression target)
2979                 {
2980                         // Do nothing, most unresolved type expressions cannot be
2981                         // resolved to different type
2982                 }
2983
2984                 public override bool ContainsEmitWithAwait ()
2985                 {
2986                         return false;
2987                 }
2988
2989                 public override Expression CreateExpressionTree (ResolveContext ec)
2990                 {
2991                         throw new NotSupportedException ("ET");
2992                 }
2993
2994                 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
2995
2996                 //
2997                 // This is used to resolve the expression as a type, a null
2998                 // value will be returned if the expression is not a type
2999                 // reference
3000                 //
3001                 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3002                 {
3003                         FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3004
3005                         if (fne == null)
3006                                 return null;
3007
3008                         TypeExpr te = fne as TypeExpr;
3009                         if (te == null) {
3010                                 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3011                                 return null;
3012                         }
3013
3014                         te.loc = loc;
3015
3016                         type = te.Type;
3017
3018                         var dep = type.GetMissingDependencies ();
3019                         if (dep != null) {
3020                                 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3021                         }
3022
3023                         if (type.Kind == MemberKind.Void) {
3024                                 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3025                         }
3026
3027                         //
3028                         // Obsolete checks cannot be done when resolving base context as they
3029                         // require type dependencies to be set but we are in process of resolving them
3030                         //
3031                         if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
3032                                 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
3033                                 if (obsolete_attr != null && !mc.IsObsolete) {
3034                                         AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
3035                                 }
3036                         }
3037
3038                         return type;
3039                 }
3040
3041
3042                 public override void Emit (EmitContext ec)
3043                 {
3044                         throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3045                                 GetSignatureForError ());
3046                 }
3047         }
3048         
3049         /// <summary>
3050         ///   Expression that evaluates to a type
3051         /// </summary>
3052         public abstract class TypeExpr : FullNamedExpression
3053         {
3054                 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3055                 {
3056                         ResolveAsType (mc);
3057                         return this;
3058                 }
3059
3060                 protected sealed override Expression DoResolve (ResolveContext ec)
3061                 {
3062                         ResolveAsType (ec);
3063                         return this;
3064                 }
3065
3066                 public override bool Equals (object obj)
3067                 {
3068                         TypeExpr tobj = obj as TypeExpr;
3069                         if (tobj == null)
3070                                 return false;
3071
3072                         return Type == tobj.Type;
3073                 }
3074
3075                 public override int GetHashCode ()
3076                 {
3077                         return Type.GetHashCode ();
3078                 }
3079         }
3080
3081         /// <summary>
3082         ///   Fully resolved Expression that already evaluated to a type
3083         /// </summary>
3084         public class TypeExpression : TypeExpr
3085         {
3086                 public TypeExpression (TypeSpec t, Location l)
3087                 {
3088                         Type = t;
3089                         eclass = ExprClass.Type;
3090                         loc = l;
3091                 }
3092
3093                 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3094                 {
3095                         return type;
3096                 }
3097         }
3098
3099         public class NamespaceExpression : FullNamedExpression
3100         {
3101                 readonly Namespace ns;
3102
3103                 public NamespaceExpression (Namespace ns, Location loc)
3104                 {
3105                         this.ns = ns;
3106                         this.Type = InternalType.Namespace;
3107                         this.eclass = ExprClass.Namespace;
3108                         this.loc = loc;
3109                 }
3110
3111                 public Namespace Namespace {
3112                         get {
3113                                 return ns;
3114                         }
3115                 }
3116
3117                 protected override Expression DoResolve (ResolveContext rc)
3118                 {
3119                         throw new NotImplementedException ();
3120                 }
3121
3122                 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3123                 {
3124                         return this;
3125                 }
3126
3127                 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity)
3128                 {
3129                         var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3130                         if (retval != null) {
3131 //                              ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3132                                 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3133                                 return;
3134                         }
3135
3136                         retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3137                         if (retval != null) {
3138                                 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3139                                 return;
3140                         }
3141
3142                         Namespace ns;
3143                         if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3144                                 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3145                                 return;
3146                         }
3147
3148                         string assembly = null;
3149                         string possible_name = Namespace.GetSignatureForError () + "." + name;
3150
3151                         // Only assembly unique name should be added
3152                         switch (possible_name) {
3153                         case "System.Drawing":
3154                         case "System.Web.Services":
3155                         case "System.Web":
3156                         case "System.Data":
3157                         case "System.Configuration":
3158                         case "System.Data.Services":
3159                         case "System.DirectoryServices":
3160                         case "System.Json":
3161                         case "System.Net.Http":
3162                         case "System.Numerics":
3163                         case "System.Runtime.Caching":
3164                         case "System.ServiceModel":
3165                         case "System.Transactions":
3166                         case "System.Web.Routing":
3167                         case "System.Xml.Linq":
3168                         case "System.Xml":
3169                                 assembly = possible_name;
3170                                 break;
3171
3172                         case "System.Linq":
3173                         case "System.Linq.Expressions":
3174                                 assembly = "System.Core";
3175                                 break;
3176
3177                         case "System.Windows.Forms":
3178                         case "System.Windows.Forms.Layout":
3179                                 assembly = "System.Windows.Forms";
3180                                 break;
3181                         }
3182
3183                         assembly = assembly == null ? "an" : "`" + assembly + "'";
3184
3185                         if (Namespace is GlobalRootNamespace) {
3186                                 ctx.Module.Compiler.Report.Error (400, loc,
3187                                         "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3188                                         name, assembly);
3189                         } else {
3190                                 ctx.Module.Compiler.Report.Error (234, loc,
3191                                         "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3192                                         name, GetSignatureForError (), assembly);
3193                         }
3194                 }
3195
3196                 public override string GetSignatureForError ()
3197                 {
3198                         return ns.GetSignatureForError ();
3199                 }
3200
3201                 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3202                 {
3203                         return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3204                 }
3205     }
3206
3207         /// <summary>
3208         ///   This class denotes an expression which evaluates to a member
3209         ///   of a struct or a class.
3210         /// </summary>
3211         public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3212         {
3213                 protected bool conditional_access_receiver;
3214
3215                 //
3216                 // An instance expression associated with this member, if it's a
3217                 // non-static member
3218                 //
3219                 public Expression InstanceExpression;
3220
3221                 /// <summary>
3222                 ///   The name of this member.
3223                 /// </summary>
3224                 public abstract string Name {
3225                         get;
3226                 }
3227
3228                 //
3229                 // When base.member is used
3230                 //
3231                 public bool IsBase {
3232                         get { return InstanceExpression is BaseThis; }
3233                 }
3234
3235                 /// <summary>
3236                 ///   Whether this is an instance member.
3237                 /// </summary>
3238                 public abstract bool IsInstance {
3239                         get;
3240                 }
3241
3242                 /// <summary>
3243                 ///   Whether this is a static member.
3244                 /// </summary>
3245                 public abstract bool IsStatic {
3246                         get;
3247                 }
3248
3249                 public abstract string KindName {
3250                         get;
3251                 }
3252
3253                 public bool ConditionalAccess { get; set; }
3254
3255                 protected abstract TypeSpec DeclaringType {
3256                         get;
3257                 }
3258
3259                 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3260                         get {
3261                                 return InstanceExpression.Type;
3262                         }
3263                 }
3264
3265                 //
3266                 // Converts best base candidate for virtual method starting from QueriedBaseType
3267                 //
3268                 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3269                 {
3270                         //
3271                         // Only when base.member is used and method is virtual
3272                         //
3273                         if (!IsBase)
3274                                 return method;
3275
3276                         //
3277                         // Overload resulution works on virtual or non-virtual members only (no overrides). That
3278                         // means for base.member access we have to find the closest match after we found best candidate
3279                         //
3280                         if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3281                                 //
3282                                 // The method could already be what we are looking for
3283                                 //
3284                                 TypeSpec[] targs = null;
3285                                 if (method.DeclaringType != InstanceExpression.Type) {
3286                                         //
3287                                         // Candidate can have inflated MVAR parameters and we need to find
3288                                         // base match for original definition not inflated parameter types
3289                                         //
3290                                         var parameters = method.Parameters;
3291                                         if (method.Arity > 0) {
3292                                                 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3293                                                 var inflated = method.DeclaringType as InflatedTypeSpec;
3294                                                 if (inflated != null) {
3295                                                         parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3296                                                 }
3297                                         }
3298
3299                                         var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3300                                         var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3301                                         if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3302                                                 if (base_override.IsGeneric)
3303                                                         targs = method.TypeArguments;
3304
3305                                                 method = base_override;
3306                                         }
3307                                 }
3308
3309                                 //
3310                                 // When base access is used inside anonymous method/iterator/etc we need to
3311                                 // get back to the context of original type. We do it by emiting proxy
3312                                 // method in original class and rewriting base call to this compiler
3313                                 // generated method call which does the actual base invocation. This may
3314                                 // introduce redundant storey but with `this' only but it's tricky to avoid
3315                                 // at this stage as we don't know what expressions follow base
3316                                 //
3317                                 if (rc.CurrentAnonymousMethod != null) {
3318                                         if (targs == null && method.IsGeneric) {
3319                                                 targs = method.TypeArguments;
3320                                                 method = method.GetGenericMethodDefinition ();
3321                                         }
3322
3323                                         if (method.Parameters.HasArglist)
3324                                                 throw new NotImplementedException ("__arglist base call proxy");
3325
3326                                         method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3327
3328                                         // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3329                                         // get/set member expressions second call would fail to proxy because left expression
3330                                         // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3331                                         // FIXME: The async check is another hack but will probably fail with mutators
3332                                         if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3333                                                 InstanceExpression = new This (loc).Resolve (rc);
3334                                 }
3335
3336                                 if (targs != null)
3337                                         method = method.MakeGenericMethod (rc, targs);
3338                         }
3339
3340                         //
3341                         // Only base will allow this invocation to happen.
3342                         //
3343                         if (method.IsAbstract) {
3344                                 rc.Report.SymbolRelatedToPreviousError (method);
3345                                 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3346                         }
3347
3348                         return method;
3349                 }
3350
3351                 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3352                 {
3353                         if (InstanceExpression == null)
3354                                 return;
3355
3356                         if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3357                                 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3358                                         Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3359                                 }
3360                         }
3361                 }
3362
3363                 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3364                 {
3365                         if (InstanceExpression == null)
3366                                 return true;
3367
3368                         return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3369                 }
3370
3371                 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3372                 {
3373                         var ct = rc.CurrentType;
3374                         if (ct == qualifier)
3375                                 return true;
3376
3377                         if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3378                                 return true;
3379
3380                         qualifier = qualifier.GetDefinition ();
3381                         if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3382                                 return false;
3383                         }
3384
3385                         return true;
3386                 }
3387
3388                 public override bool ContainsEmitWithAwait ()
3389                 {
3390                         return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3391                 }
3392
3393                 public override bool HasConditionalAccess ()
3394                 {
3395                         return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3396                 }
3397
3398                 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3399                 {
3400                         do {
3401                                 type = type.GetDefinition ();
3402
3403                                 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3404                                         return true;
3405
3406                                 type = type.DeclaringType;
3407                         } while (type != null);
3408
3409                         return false;
3410                 }
3411
3412                 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3413                 {
3414                         if (InstanceExpression != null) {
3415                                 InstanceExpression = InstanceExpression.Resolve (rc);
3416                                 CheckProtectedMemberAccess (rc, member);
3417                         }
3418
3419                         if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3420                                 UnsafeError (rc, loc);
3421                         }
3422
3423                         var dep = member.GetMissingDependencies ();
3424                         if (dep != null) {
3425                                 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3426                         }
3427
3428                         if (!rc.IsObsolete) {
3429                                 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3430                                 if (oa != null)
3431                                         AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3432                         }
3433
3434                         if (!(member is FieldSpec))
3435                                 member.MemberDefinition.SetIsUsed ();
3436                 }
3437
3438                 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3439                 {
3440                         rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3441                 }
3442
3443                 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3444                 {
3445                         rc.Report.SymbolRelatedToPreviousError (member);
3446                         rc.Report.Error (1540, loc,
3447                                 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3448                                 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3449                 }
3450
3451                 public override void FlowAnalysis (FlowAnalysisContext fc)
3452                 {
3453                         if (InstanceExpression != null) {
3454                                 InstanceExpression.FlowAnalysis (fc);
3455
3456                                 if (ConditionalAccess) {
3457                                         fc.BranchConditionalAccessDefiniteAssignment ();
3458                                 }
3459                         }
3460                 }
3461
3462                 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3463                 {
3464                         if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
3465                                 if (HasConditionalAccess ()) {
3466                                         conditional_access_receiver = true;
3467                                         rc.Set (ResolveContext.Options.ConditionalAccessReceiver);
3468                                 }
3469                         }
3470                 }
3471
3472                 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3473                 {
3474                         if (!ResolveInstanceExpressionCore (rc, rhs))
3475                                 return false;
3476
3477                         //
3478                         // Check intermediate value modification which won't have any effect
3479                         //
3480                         if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3481                                 var fexpr = InstanceExpression as FieldExpr;
3482                                 if (fexpr != null) {
3483                                         if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3484                                                 return true;
3485
3486                                         if (fexpr.IsStatic) {
3487                                                 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3488                                                         fexpr.GetSignatureForError ());
3489                                         } else {
3490                                                 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3491                                                         fexpr.GetSignatureForError ());
3492                                         }
3493
3494                                         return true;
3495                                 }
3496
3497                                 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3498                                         if (rc.CurrentInitializerVariable != null) {
3499                                                 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3500                                                         InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3501                                         } else {
3502                                                 rc.Report.Error (1612, loc,
3503                                                         "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3504                                                         InstanceExpression.GetSignatureForError ());
3505                                         }
3506
3507                                         return true;
3508                                 }
3509
3510                                 var lvr = InstanceExpression as LocalVariableReference;
3511                                 if (lvr != null) {
3512
3513                                         if (!lvr.local_info.IsReadonly)
3514                                                 return true;
3515
3516                                         rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3517                                                 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3518                                 }
3519                         }
3520
3521                         return true;
3522                 }
3523
3524                 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3525                 {
3526                         if (IsStatic) {
3527                                 if (InstanceExpression != null) {
3528                                         if (InstanceExpression is TypeExpr) {
3529                                                 var t = InstanceExpression.Type;
3530                                                 do {
3531                                                         ObsoleteAttribute oa = t.GetAttributeObsolete ();
3532                                                         if (oa != null && !rc.IsObsolete) {
3533                                                                 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3534                                                         }
3535
3536                                                         t = t.DeclaringType;
3537                                                 } while (t != null);
3538                                         } else {
3539                                                 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3540                                                 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3541                                                         rc.Report.Error (176, loc,
3542                                                                 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3543                                                                 GetSignatureForError ());
3544                                                 }
3545                                         }
3546
3547                                         InstanceExpression = null;
3548                                 }
3549
3550                                 return false;
3551                         }
3552
3553                         if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3554                                 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3555                                         if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3556                                                 rc.Report.Error (236, loc,
3557                                                         "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3558                                                         GetSignatureForError ());
3559                                         } else {
3560                                                 var fe = this as FieldExpr;
3561                                                 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3562                                                         if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3563                                                                 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3564                                                         } else  {
3565                                                                 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3566                                                                         fe.Name);
3567                                                         }
3568                                                 } else {
3569                                                         rc.Report.Error (120, loc,
3570                                                                 "An object reference is required to access non-static member `{0}'",
3571                                                                 GetSignatureForError ());
3572                                                 }
3573                                         }
3574
3575                                         InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3576                                         return false;
3577                                 }
3578
3579                                 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3580                                         rc.Report.Error (38, loc,
3581                                                 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3582                                                 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3583                                 }
3584
3585                                 InstanceExpression = new This (loc).Resolve (rc);
3586                                 return false;
3587                         }
3588
3589                         var me = InstanceExpression as MemberExpr;
3590                         if (me != null) {
3591                                 me.ResolveInstanceExpressionCore (rc, rhs);
3592
3593                                 var fe = me as FieldExpr;
3594                                 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3595                                         rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3596                                         rc.Report.Warning (1690, 1, loc,
3597                                                 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3598                                                 me.GetSignatureForError ());
3599                                 }
3600
3601                                 return true;
3602                         }
3603
3604                         //
3605                         // Additional checks for l-value member access
3606                         //
3607                         if (rhs != null) {
3608                                 if (InstanceExpression is UnboxCast) {
3609                                         rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3610                                 }
3611                         }
3612
3613                         return true;
3614                 }
3615
3616                 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3617                 {
3618                         if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3619                                 ec.Report.Warning (1720, 1, left.Location,
3620                                         "Expression will always cause a `{0}'", "System.NullReferenceException");
3621                         }
3622
3623                         InstanceExpression = left;
3624                         return this;
3625                 }
3626
3627                 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3628                 {
3629                         var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3630                         inst.Emit (ec, ConditionalAccess);
3631
3632                         if (prepare_for_load)
3633                                 ec.Emit (OpCodes.Dup);
3634                 }
3635
3636                 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3637         }
3638
3639         public class ExtensionMethodCandidates
3640         {
3641                 readonly NamespaceContainer container;
3642                 readonly IList<MethodSpec> methods;
3643                 readonly int index;
3644                 readonly IMemberContext context;
3645
3646                 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3647                 {
3648                         this.context = context;
3649                         this.methods = methods;
3650                         this.container = nsContainer;
3651                         this.index = lookupIndex;
3652                 }
3653
3654                 public NamespaceContainer Container {
3655                         get {
3656                                 return container;
3657                         }
3658                 }
3659
3660                 public IMemberContext Context {
3661                         get {
3662                                 return context;
3663                         }
3664                 }
3665
3666                 public int LookupIndex {
3667                         get {
3668                                 return index;
3669                         }
3670                 }
3671
3672                 public IList<MethodSpec> Methods {
3673                         get {
3674                                 return methods;
3675                         }
3676                 }
3677         }
3678
3679         // 
3680         // Represents a group of extension method candidates for whole namespace
3681         // 
3682         class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3683         {
3684                 ExtensionMethodCandidates candidates;
3685                 public Expression ExtensionExpression;
3686
3687                 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3688                         : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3689                 {
3690                         this.candidates = candidates;
3691                         this.ExtensionExpression = extensionExpr;
3692                 }
3693
3694                 public override bool IsStatic {
3695                         get { return true; }
3696                 }
3697
3698                 public override void FlowAnalysis (FlowAnalysisContext fc)
3699                 {
3700                         if (ConditionalAccess) {
3701                                 fc.BranchConditionalAccessDefiniteAssignment ();
3702                         }
3703                 }
3704
3705                 //
3706                 // For extension methodgroup we are not looking for base members but parent
3707                 // namespace extension methods
3708                 //
3709                 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3710                 {
3711                         // TODO: candidates are null only when doing error reporting, that's
3712                         // incorrect. We have to discover same extension methods in error mode
3713                         if (candidates == null)
3714                                 return null;
3715
3716                         int arity = type_arguments == null ? 0 : type_arguments.Count;
3717
3718                         candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3719                         if (candidates == null)
3720                                 return null;
3721
3722                         return candidates.Methods.Cast<MemberSpec> ().ToList ();
3723                 }
3724
3725                 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3726                 {
3727                         // We are already here
3728                         return null;
3729                 }
3730
3731                 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3732                 {
3733                         if (arguments == null)
3734                                 arguments = new Arguments (1);
3735
3736                         ExtensionExpression = ExtensionExpression.Resolve (ec);
3737                         if (ExtensionExpression == null)
3738                                 return null;
3739
3740                         var cand = candidates;
3741                         var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3742                         arguments.Insert (0, new Argument (ExtensionExpression, atype));
3743                         var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3744                         
3745                         // Restore candidates in case we are running in probing mode 
3746                         candidates = cand;
3747
3748                         // Store resolved argument and restore original arguments
3749                         if (res == null) {
3750                                 // Clean-up modified arguments for error reporting
3751                                 arguments.RemoveAt (0);
3752                                 return null;
3753                         }
3754
3755                         var me = ExtensionExpression as MemberExpr;
3756                         if (me != null) {
3757                                 me.ResolveInstanceExpression (ec, null);
3758                                 var fe = me as FieldExpr;
3759                                 if (fe != null)
3760                                         fe.Spec.MemberDefinition.SetIsUsed ();
3761                         }
3762
3763                         InstanceExpression = null;
3764                         return this;
3765                 }
3766
3767                 #region IErrorHandler Members
3768
3769                 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3770                 {
3771                         return false;
3772                 }
3773
3774                 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3775                 {
3776                         rc.Report.SymbolRelatedToPreviousError (best);
3777                         rc.Report.Error (1928, loc,
3778                                 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3779                                 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3780
3781                         if (index == 0) {
3782                                 rc.Report.Error (1929, loc,
3783                                         "Extension method instance type `{0}' cannot be converted to `{1}'",
3784                                         arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3785                         }
3786
3787                         return true;
3788                 }
3789
3790                 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3791                 {
3792                         return false;
3793                 }
3794
3795                 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3796                 {
3797                         return false;
3798                 }
3799
3800                 #endregion
3801         }
3802
3803         /// <summary>
3804         ///   MethodGroupExpr represents a group of method candidates which
3805         ///   can be resolved to the best method overload
3806         /// </summary>
3807         public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3808         {
3809                 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3810
3811                 protected IList<MemberSpec> Methods;
3812                 MethodSpec best_candidate;
3813                 TypeSpec best_candidate_return;
3814                 protected TypeArguments type_arguments;
3815
3816                 SimpleName simple_name;
3817                 protected TypeSpec queried_type;
3818
3819                 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3820                 {
3821                         Methods = mi;
3822                         this.loc = loc;
3823                         this.type = InternalType.MethodGroup;
3824
3825                         eclass = ExprClass.MethodGroup;
3826                         queried_type = type;
3827                 }
3828
3829                 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3830                         : this (new MemberSpec[] { m }, type, loc)
3831                 {
3832                 }
3833
3834                 #region Properties
3835
3836                 public MethodSpec BestCandidate {
3837                         get {
3838                                 return best_candidate;
3839                         }
3840                 }
3841
3842                 public TypeSpec BestCandidateReturnType {
3843                         get {
3844                                 return best_candidate_return;
3845                         }
3846                 }
3847
3848                 public IList<MemberSpec> Candidates {
3849                         get {
3850                                 return Methods;
3851                         }
3852                 }
3853
3854                 protected override TypeSpec DeclaringType {
3855                         get {
3856                                 return queried_type;
3857                         }
3858                 }
3859
3860                 public bool IsConditionallyExcluded {
3861                         get {
3862                                 return Methods == Excluded;
3863                         }
3864                 }
3865
3866                 public override bool IsInstance {
3867                         get {
3868                                 if (best_candidate != null)
3869                                         return !best_candidate.IsStatic;
3870
3871                                 return false;
3872                         }
3873                 }
3874
3875                 public override bool IsSideEffectFree {
3876                         get {
3877                                 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3878                         }
3879                 }
3880
3881                 public override bool IsStatic {
3882                         get {
3883                                 if (best_candidate != null)
3884                                         return best_candidate.IsStatic;
3885
3886                                 return false;
3887                         }
3888                 }
3889
3890                 public override string KindName {
3891                         get { return "method"; }
3892                 }
3893
3894                 public override string Name {
3895                         get {
3896                                 if (best_candidate != null)
3897                                         return best_candidate.Name;
3898
3899                                 // TODO: throw ?
3900                                 return Methods.First ().Name;
3901                         }
3902                 }
3903
3904                 #endregion
3905
3906                 //
3907                 // When best candidate is already know this factory can be used
3908                 // to avoid expensive overload resolution to be called
3909                 //
3910                 // NOTE: InstanceExpression has to be set manually
3911                 //
3912                 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3913                 {
3914                         return new MethodGroupExpr (best, queriedType, loc) {
3915                                 best_candidate = best,
3916                                 best_candidate_return = best.ReturnType
3917                         };
3918                 }
3919
3920                 public override string GetSignatureForError ()
3921                 {
3922                         if (best_candidate != null)
3923                                 return best_candidate.GetSignatureForError ();
3924
3925                         return Methods.First ().GetSignatureForError ();
3926                 }
3927
3928                 public override Expression CreateExpressionTree (ResolveContext ec)
3929                 {
3930                         if (best_candidate == null) {
3931                                 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3932                                 return null;
3933                         }
3934
3935                         if (IsConditionallyExcluded)
3936                                 ec.Report.Error (765, loc,
3937                                         "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3938
3939                         if (ConditionalAccess)
3940                                 Error_NullShortCircuitInsideExpressionTree (ec);
3941
3942                         return new TypeOfMethod (best_candidate, loc);
3943                 }
3944                 
3945                 protected override Expression DoResolve (ResolveContext ec)
3946                 {
3947                         this.eclass = ExprClass.MethodGroup;
3948
3949                         if (InstanceExpression != null) {
3950                                 InstanceExpression = InstanceExpression.Resolve (ec);
3951                                 if (InstanceExpression == null)
3952                                         return null;
3953                         }
3954
3955                         return this;
3956                 }
3957
3958                 public override void Emit (EmitContext ec)
3959                 {
3960                         throw new NotSupportedException ();
3961                 }
3962
3963                 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
3964                 {
3965                         var call = new CallEmitter ();
3966                         call.InstanceExpression = InstanceExpression;
3967                         call.ConditionalAccess = ConditionalAccess;
3968
3969                         if (statement)
3970                                 call.EmitStatement (ec, best_candidate, arguments, loc);
3971                         else
3972                                 call.Emit (ec, best_candidate, arguments, loc);
3973                 }
3974
3975                 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
3976                 {
3977                         ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
3978                                 Statement = statement
3979                         };
3980
3981                         EmitCall (ec, arguments, statement);
3982
3983                         ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
3984                 }
3985
3986                 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3987                 {
3988                         ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3989                                 Name, target.GetSignatureForError ());
3990                 }
3991
3992                 public static bool IsExtensionMethodArgument (Expression expr)
3993                 {
3994                         //
3995                         // LAMESPEC: No details about which expressions are not allowed
3996                         //
3997                         return !(expr is TypeExpr) && !(expr is BaseThis);
3998                 }
3999
4000                 /// <summary>
4001                 ///   Find the Applicable Function Members (7.4.2.1)
4002                 ///
4003                 ///   me: Method Group expression with the members to select.
4004                 ///       it might contain constructors or methods (or anything
4005                 ///       that maps to a method).
4006                 ///
4007                 ///   Arguments: ArrayList containing resolved Argument objects.
4008                 ///
4009                 ///   loc: The location if we want an error to be reported, or a Null
4010                 ///        location for "probing" purposes.
4011                 ///
4012                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4013                 ///            that is the best match of me on Arguments.
4014                 ///
4015                 /// </summary>
4016                 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4017                 {
4018                         // TODO: causes issues with probing mode, remove explicit Kind check
4019                         if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4020                                 return this;
4021
4022                         var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4023                         if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4024                                 r.BaseMembersProvider = this;
4025                                 r.InstanceQualifier = this;
4026                         }
4027
4028                         if (cerrors != null)
4029                                 r.CustomErrors = cerrors;
4030
4031                         // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4032                         best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4033                         if (best_candidate == null) {
4034                                 if (!r.BestCandidateIsDynamic)
4035                                         return null;
4036
4037                                 if (simple_name != null && ec.IsStatic)
4038                                         InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4039
4040                                 return this;
4041                         }
4042
4043                         // Overload resolver had to create a new method group, all checks bellow have already been executed
4044                         if (r.BestCandidateNewMethodGroup != null)
4045                                 return r.BestCandidateNewMethodGroup;
4046
4047                         if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4048                                 if (InstanceExpression != null) {
4049                                         if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4050                                                 InstanceExpression = null;
4051                                         } else {
4052                                                 if (simple_name != null && best_candidate.IsStatic) {
4053                                                         InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4054                                                 }
4055
4056                                                 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4057                                         }
4058                                 }
4059
4060                                 ResolveInstanceExpression (ec, null);
4061                         }
4062
4063                         var base_override = CandidateToBaseOverride (ec, best_candidate);
4064                         if (base_override == best_candidate) {
4065                                 best_candidate_return = r.BestCandidateReturnType;
4066                         } else {
4067                                 best_candidate = base_override;
4068                                 best_candidate_return = best_candidate.ReturnType;
4069                         }
4070
4071                         if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4072                                 ConstraintChecker cc = new ConstraintChecker (ec);
4073                                 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4074                         }
4075
4076                         //
4077                         // Additional check for possible imported base override method which
4078                         // could not be done during IsOverrideMethodBaseTypeAccessible
4079                         //
4080                         if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4081                                 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4082                                 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4083                                 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4084                         }
4085
4086                         // Speed up the check by not doing it on disallowed targets
4087                         if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4088                                 Methods = Excluded;
4089
4090                         return this;
4091                 }
4092
4093                 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4094                 {
4095                         var fe = left as FieldExpr;
4096                         if (fe != null) {
4097                                 //
4098                                 // Using method-group on struct fields makes the struct assigned. I am not sure
4099                                 // why but that's what .net does
4100                                 //
4101                                 fe.Spec.MemberDefinition.SetIsAssigned ();
4102                         }
4103
4104                         simple_name = original;
4105                         return base.ResolveMemberAccess (ec, left, original);
4106                 }
4107
4108                 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4109                 {
4110                         type_arguments = ta;
4111                 }
4112
4113                 #region IBaseMembersProvider Members
4114
4115                 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4116                 {
4117                         return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4118                 }
4119
4120                 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4121                 {
4122                         if (queried_type == member.DeclaringType)
4123                                 return null;
4124
4125                         return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4126                                 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4127                 }
4128
4129                 //
4130                 // Extension methods lookup after ordinary methods candidates failed to apply
4131                 //
4132                 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4133                 {
4134                         if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4135                                 return null;
4136
4137                         if (!IsExtensionMethodArgument (InstanceExpression))
4138                                 return null;
4139
4140                         int arity = type_arguments == null ? 0 : type_arguments.Count;
4141                         var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
4142                         if (methods == null)
4143                                 return null;
4144
4145                         var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4146                         emg.SetTypeArguments (rc, type_arguments);
4147                         return emg;
4148                 }
4149
4150                 #endregion
4151         }
4152
4153         struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4154         {
4155                 public ConstructorInstanceQualifier (TypeSpec type)
4156                         : this ()
4157                 {
4158                         InstanceType = type;
4159                 }
4160
4161                 public TypeSpec InstanceType { get; private set; }
4162
4163                 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4164                 {
4165                         return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4166                 }
4167         }
4168
4169         public struct OverloadResolver
4170         {
4171                 [Flags]
4172                 public enum Restrictions
4173                 {
4174                         None = 0,
4175                         DelegateInvoke = 1,
4176                         ProbingOnly     = 1 << 1,
4177                         CovariantDelegate = 1 << 2,
4178                         NoBaseMembers = 1 << 3,
4179                         BaseMembersIncluded = 1 << 4,
4180                         GetEnumeratorLookup = 1 << 5
4181                 }
4182
4183                 public interface IBaseMembersProvider
4184                 {
4185                         IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4186                         IParametersMember GetOverrideMemberParameters (MemberSpec member);
4187                         MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4188                 }
4189
4190                 public interface IErrorHandler
4191                 {
4192                         bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4193                         bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4194                         bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4195                         bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4196                 }
4197
4198                 public interface IInstanceQualifier
4199                 {
4200                         TypeSpec InstanceType { get; }
4201                         bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4202                 }
4203
4204                 sealed class NoBaseMembers : IBaseMembersProvider
4205                 {
4206                         public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4207
4208                         public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4209                         {
4210                                 return null;
4211                         }
4212
4213                         public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4214                         {
4215                                 return null;
4216                         }
4217
4218                         public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4219                         {
4220                                 return null;
4221                         }
4222                 }
4223
4224                 struct AmbiguousCandidate
4225                 {
4226                         public readonly MemberSpec Member;
4227                         public readonly bool Expanded;
4228                         public readonly AParametersCollection Parameters;
4229
4230                         public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4231                         {
4232                                 Member = member;
4233                                 Parameters = parameters;
4234                                 Expanded = expanded;
4235                         }
4236                 }
4237
4238                 Location loc;
4239                 IList<MemberSpec> members;
4240                 TypeArguments type_arguments;
4241                 IBaseMembersProvider base_provider;
4242                 IErrorHandler custom_errors;
4243                 IInstanceQualifier instance_qualifier;
4244                 Restrictions restrictions;
4245                 MethodGroupExpr best_candidate_extension_group;
4246                 TypeSpec best_candidate_return_type;
4247
4248                 SessionReportPrinter lambda_conv_msgs;
4249
4250                 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4251                         : this (members, null, restrictions, loc)
4252                 {
4253                 }
4254
4255                 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4256                         : this ()
4257                 {
4258                         if (members == null || members.Count == 0)
4259                                 throw new ArgumentException ("empty members set");
4260
4261                         this.members = members;
4262                         this.loc = loc;
4263                         type_arguments = targs;
4264                         this.restrictions = restrictions;
4265                         if (IsDelegateInvoke)
4266                                 this.restrictions |= Restrictions.NoBaseMembers;
4267
4268                         base_provider = NoBaseMembers.Instance;
4269                 }
4270
4271                 #region Properties
4272
4273                 public IBaseMembersProvider BaseMembersProvider {
4274                         get {
4275                                 return base_provider;
4276                         }
4277                         set {
4278                                 base_provider = value;
4279                         }
4280                 }
4281
4282                 public bool BestCandidateIsDynamic { get; set; }
4283
4284                 //
4285                 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4286                 //
4287                 public MethodGroupExpr BestCandidateNewMethodGroup {
4288                         get {
4289                                 return best_candidate_extension_group;
4290                         }
4291                 }
4292
4293                 //
4294                 // Return type can be different between best candidate and closest override
4295                 //
4296                 public TypeSpec BestCandidateReturnType {
4297                         get {
4298                                 return best_candidate_return_type;
4299                         }
4300                 }
4301
4302                 public IErrorHandler CustomErrors {
4303                         get {
4304                                 return custom_errors;
4305                         }
4306                         set {
4307                                 custom_errors = value;
4308                         }
4309                 }
4310
4311                 TypeSpec DelegateType {
4312                         get {
4313                                 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4314                                         throw new InternalErrorException ("Not running in delegate mode", loc);
4315
4316                                 return members [0].DeclaringType;
4317                         }
4318                 }
4319
4320                 public IInstanceQualifier InstanceQualifier {
4321                         get {
4322                                 return instance_qualifier;
4323                         }
4324                         set {
4325                                 instance_qualifier = value;
4326                         }
4327                 }
4328
4329                 bool IsProbingOnly {
4330                         get {
4331                                 return (restrictions & Restrictions.ProbingOnly) != 0;
4332                         }
4333                 }
4334
4335                 bool IsDelegateInvoke {
4336                         get {
4337                                 return (restrictions & Restrictions.DelegateInvoke) != 0;
4338                         }
4339                 }
4340
4341                 #endregion
4342
4343                 //
4344                 //  7.4.3.3  Better conversion from expression
4345                 //  Returns :   1    if a->p is better,
4346                 //              2    if a->q is better,
4347                 //              0 if neither is better
4348                 //
4349                 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4350                 {
4351                         TypeSpec argument_type = a.Type;
4352
4353                         //
4354                         // If argument is an anonymous function
4355                         //
4356                         if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4357                                 //
4358                                 // p and q are delegate types or expression tree types
4359                                 //
4360                                 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4361                                         if (q.MemberDefinition != p.MemberDefinition) {
4362                                                 return 0;
4363                                         }
4364
4365                                         //
4366                                         // Uwrap delegate from Expression<T>
4367                                         //
4368                                         q = TypeManager.GetTypeArguments (q)[0];
4369                                         p = TypeManager.GetTypeArguments (p)[0];
4370                                 }
4371
4372                                 var p_m = Delegate.GetInvokeMethod (p);
4373                                 var q_m = Delegate.GetInvokeMethod (q);
4374
4375                                 //
4376                                 // With identical parameter lists
4377                                 //
4378                                 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4379                                         return 0;
4380
4381                                 p = p_m.ReturnType;
4382                                 var orig_q = q;
4383                                 q = q_m.ReturnType;
4384
4385                                 //
4386                                 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4387                                 //
4388                                 if (p.Kind == MemberKind.Void) {
4389                                         return q.Kind != MemberKind.Void ? 2 : 0;
4390                                 }
4391
4392                                 //
4393                                 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4394                                 //
4395                                 if (q.Kind == MemberKind.Void) {
4396                                         return p.Kind != MemberKind.Void ? 1: 0;
4397                                 }
4398
4399                                 var am = (AnonymousMethodExpression) a.Expr;
4400
4401                                 //
4402                                 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4403                                 // better conversion is performed between underlying types Y1 and Y2
4404                                 //
4405                                 if (p.IsGenericTask || q.IsGenericTask) {
4406                                         if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4407                                                 q = q.TypeArguments[0];
4408                                                 p = p.TypeArguments[0];
4409                                         }
4410                                 }
4411
4412                                 if (q != p) {
4413                                         //
4414                                         // An inferred return type X exists for E in the context of that parameter list, and 
4415                                         // the conversion from X to Y1 is better than the conversion from X to Y2
4416                                         //
4417                                         argument_type = am.InferReturnType (ec, null, orig_q);
4418                                         if (argument_type == null) {
4419                                                 // TODO: Can this be hit?
4420                                                 return 1;
4421                                         }
4422
4423                                         if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4424                                                 argument_type = ec.BuiltinTypes.Object;
4425                                 }
4426                         }
4427
4428                         if (argument_type == p)
4429                                 return 1;
4430
4431                         if (argument_type == q)
4432                                 return 2;
4433
4434                         //
4435                         // The parameters are identicial and return type is not void, use better type conversion
4436                         // on return type to determine better one
4437                         //
4438                         return BetterTypeConversion (ec, p, q);
4439                 }
4440
4441                 //
4442                 // 7.4.3.4  Better conversion from type
4443                 //
4444                 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4445                 {
4446                         if (p == null || q == null)
4447                                 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4448
4449                         switch (p.BuiltinType) {
4450                         case BuiltinTypeSpec.Type.Int:
4451                                 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4452                                         return 1;
4453                                 break;
4454                         case BuiltinTypeSpec.Type.Long:
4455                                 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4456                                         return 1;
4457                                 break;
4458                         case BuiltinTypeSpec.Type.SByte:
4459                                 switch (q.BuiltinType) {
4460                                 case BuiltinTypeSpec.Type.Byte:
4461                                 case BuiltinTypeSpec.Type.UShort:
4462                                 case BuiltinTypeSpec.Type.UInt:
4463                                 case BuiltinTypeSpec.Type.ULong:
4464                                         return 1;
4465                                 }
4466                                 break;
4467                         case BuiltinTypeSpec.Type.Short:
4468                                 switch (q.BuiltinType) {
4469                                 case BuiltinTypeSpec.Type.UShort:
4470                                 case BuiltinTypeSpec.Type.UInt:
4471                                 case BuiltinTypeSpec.Type.ULong:
4472                                         return 1;
4473                                 }
4474                                 break;
4475                         case BuiltinTypeSpec.Type.Dynamic:
4476                                 // Dynamic is never better
4477                                 return 2;
4478                         }
4479
4480                         switch (q.BuiltinType) {
4481                         case BuiltinTypeSpec.Type.Int:
4482                                 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4483                                         return 2;
4484                                 break;
4485                         case BuiltinTypeSpec.Type.Long:
4486                                 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4487                                         return 2;
4488                                 break;
4489                         case BuiltinTypeSpec.Type.SByte:
4490                                 switch (p.BuiltinType) {
4491                                 case BuiltinTypeSpec.Type.Byte:
4492                                 case BuiltinTypeSpec.Type.UShort:
4493                                 case BuiltinTypeSpec.Type.UInt:
4494                                 case BuiltinTypeSpec.Type.ULong:
4495                                         return 2;
4496                                 }
4497                                 break;
4498                         case BuiltinTypeSpec.Type.Short:
4499                                 switch (p.BuiltinType) {
4500                                 case BuiltinTypeSpec.Type.UShort:
4501                                 case BuiltinTypeSpec.Type.UInt:
4502                                 case BuiltinTypeSpec.Type.ULong:
4503                                         return 2;
4504                                 }
4505                                 break;
4506                         case BuiltinTypeSpec.Type.Dynamic:
4507                                 // Dynamic is never better
4508                                 return 1;
4509                         }
4510
4511                         // FIXME: handle lifted operators
4512
4513                         // TODO: this is expensive
4514                         Expression p_tmp = new EmptyExpression (p);
4515                         Expression q_tmp = new EmptyExpression (q);
4516
4517                         bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4518                         bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4519
4520                         if (p_to_q && !q_to_p)
4521                                 return 1;
4522
4523                         if (q_to_p && !p_to_q)
4524                                 return 2;
4525
4526                         return 0;
4527                 }
4528
4529                 /// <summary>
4530                 ///   Determines "Better function" between candidate
4531                 ///   and the current best match
4532                 /// </summary>
4533                 /// <remarks>
4534                 ///    Returns a boolean indicating :
4535                 ///     false if candidate ain't better
4536                 ///     true  if candidate is better than the current best match
4537                 /// </remarks>
4538                 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4539                         MemberSpec best, AParametersCollection bparam, bool best_params)
4540                 {
4541                         AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4542                         AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4543
4544                         bool better_at_least_one = false;
4545                         bool are_equivalent = true;
4546                         int args_count = args == null ? 0 : args.Count;
4547                         int j = 0;
4548                         Argument a = null;
4549                         TypeSpec ct, bt;
4550                         for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4551                                 a = args[j];
4552
4553                                 // Default arguments are ignored for better decision
4554                                 if (a.IsDefaultArgument)
4555                                         break;
4556
4557                                 //
4558                                 // When comparing named argument the parameter type index has to be looked up
4559                                 // in original parameter set (override version for virtual members)
4560                                 //
4561                                 NamedArgument na = a as NamedArgument;
4562                                 if (na != null) {
4563                                         int idx = cparam.GetParameterIndexByName (na.Name);
4564                                         ct = candidate_pd.Types[idx];
4565                                         if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4566                                                 ct = TypeManager.GetElementType (ct);
4567
4568                                         idx = bparam.GetParameterIndexByName (na.Name);
4569                                         bt = best_pd.Types[idx];
4570                                         if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4571                                                 bt = TypeManager.GetElementType (bt);
4572                                 } else {
4573                                         ct = candidate_pd.Types[c_idx];
4574                                         bt = best_pd.Types[b_idx];
4575
4576                                         if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4577                                                 ct = TypeManager.GetElementType (ct);
4578                                                 --c_idx;
4579                                         }
4580
4581                                         if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4582                                                 bt = TypeManager.GetElementType (bt);
4583                                                 --b_idx;
4584                                         }
4585                                 }
4586
4587                                 if (TypeSpecComparer.IsEqual (ct, bt))
4588                                         continue;
4589
4590                                 are_equivalent = false;
4591                                 int result = BetterExpressionConversion (ec, a, ct, bt);
4592
4593                                 // for each argument, the conversion to 'ct' should be no worse than 
4594                                 // the conversion to 'bt'.
4595                                 if (result == 2)
4596                                         return false;
4597
4598                                 // for at least one argument, the conversion to 'ct' should be better than 
4599                                 // the conversion to 'bt'.
4600                                 if (result != 0)
4601                                         better_at_least_one = true;
4602                         }
4603
4604                         if (better_at_least_one)
4605                                 return true;
4606
4607                         //
4608                         // Tie-breaking rules are applied only for equivalent parameter types
4609                         //
4610                         if (!are_equivalent)
4611                                 return false;
4612
4613                         //
4614                         // If candidate is applicable in its normal form and best has a params array and is applicable
4615                         // only in its expanded form, then candidate is better
4616                         //
4617                         if (candidate_params != best_params)
4618                                 return !candidate_params;
4619
4620                         //
4621                         // We have not reached end of parameters list due to params or used default parameters
4622                         //
4623                         while (j < candidate_pd.Count && j < best_pd.Count) {
4624                                 var cand_param = candidate_pd.FixedParameters [j];
4625                                 var best_param = best_pd.FixedParameters [j];
4626
4627                                 if (candidate_pd.Count == best_pd.Count) {
4628                                         //
4629                                         // LAMESPEC:
4630                                         //
4631                                         // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4632                                         // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4633                                         //
4634                                         if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4635                                                 return cand_param.HasDefaultValue;
4636
4637                                         if (cand_param.HasDefaultValue) {
4638                                                 ++j;
4639                                                 continue;
4640                                         }
4641                                 } else {
4642                                         //
4643                                         // Neither is better when not all arguments are provided
4644                                         //
4645                                         // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4646                                         // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4647                                         // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4648                                         //
4649                                         if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
4650                                                 return false;
4651                                 }
4652
4653                                 break;
4654                         }
4655
4656                         if (candidate_pd.Count != best_pd.Count)
4657                                 return candidate_pd.Count < best_pd.Count;
4658
4659                         //
4660                         // One is a non-generic method and second is a generic method, then non-generic is better
4661                         //
4662                         if (best.IsGeneric != candidate.IsGeneric)
4663                                 return best.IsGeneric;
4664
4665                         //
4666                         // Both methods have the same number of parameters, and the parameters have equal types
4667                         // Pick the "more specific" signature using rules over original (non-inflated) types
4668                         //
4669                         var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4670                         var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4671
4672                         bool specific_at_least_once = false;
4673                         for (j = 0; j < args_count; ++j) {
4674                                 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4675                                 if (na != null) {
4676                                         ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4677                                         bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4678                                 } else {
4679                                         ct = candidate_def_pd.Types[j];
4680                                         bt = best_def_pd.Types[j];
4681                                 }
4682
4683                                 if (ct == bt)
4684                                         continue;
4685                                 TypeSpec specific = MoreSpecific (ct, bt);
4686                                 if (specific == bt)
4687                                         return false;
4688                                 if (specific == ct)
4689                                         specific_at_least_once = true;
4690                         }
4691
4692                         if (specific_at_least_once)
4693                                 return true;
4694
4695                         return false;
4696                 }
4697
4698                 static bool CheckInflatedArguments (MethodSpec ms)
4699                 {
4700                         if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4701                                 return true;
4702
4703                         // Setup constraint checker for probing only
4704                         ConstraintChecker cc = new ConstraintChecker (null);
4705
4706                         var mp = ms.Parameters.Types;
4707                         for (int i = 0; i < mp.Length; ++i) {
4708                                 var type = mp[i] as InflatedTypeSpec;
4709                                 if (type == null)
4710                                         continue;
4711
4712                                 var targs = type.TypeArguments;
4713                                 if (targs.Length == 0)
4714                                         continue;
4715
4716                                 // TODO: Checking inflated MVAR arguments should be enough
4717                                 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4718                                         return false;
4719                         }
4720
4721                         return true;
4722                 }
4723
4724                 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4725                 {
4726                         rc.Report.Error (1729, loc,
4727                                 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4728                                 type.GetSignatureForError (), argCount.ToString ());
4729                 }
4730
4731                 //
4732                 // Determines if the candidate method is applicable to the given set of arguments
4733                 // There could be two different set of parameters for same candidate where one
4734                 // is the closest override for default values and named arguments checks and second
4735                 // one being the virtual base for the parameter types and modifiers.
4736                 //
4737                 // A return value rates candidate method compatibility,
4738                 // -1 = fatal error
4739                 // 0 = the best, int.MaxValue = the worst
4740                 //
4741                 int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, IParametersMember pm, ref bool params_expanded_form, ref bool dynamicArgument, ref TypeSpec returnType, bool errorMode)
4742                 {
4743                         //
4744                         // Each step has allocated 10 values, it can overflow for
4745                         // more than 10 arguments but that's ok as it's used for
4746                         // better error reporting only
4747                         //
4748                         const int ArgumentCountMismatch         = 1000000000;
4749                         const int NamedArgumentsMismatch        = 100000000;
4750                         const int DefaultArgumentMismatch       = 10000000;
4751                         const int UnexpectedTypeArguments       = 1000000;
4752                         const int TypeArgumentsMismatch         = 100000;
4753                         const int InflatedTypesMismatch         = 10000;
4754
4755                         // Parameters of most-derived type used mainly for named and optional parameters
4756                         var pd = pm.Parameters;
4757
4758                         // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4759                         // params modifier instead of most-derived type
4760                         var cpd = ((IParametersMember) candidate).Parameters;
4761                         int param_count = pd.Count;
4762                         int optional_count = 0;
4763                         int score;
4764                         Arguments orig_args = arguments;
4765
4766                         if (arg_count != param_count) {
4767                                 //
4768                                 // No arguments expansion when doing exact match for delegates
4769                                 //
4770                                 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4771                                         for (int i = 0; i < pd.Count; ++i) {
4772                                                 if (pd.FixedParameters[i].HasDefaultValue) {
4773                                                         optional_count = pd.Count - i;
4774                                                         break;
4775                                                 }
4776                                         }
4777                                 }
4778
4779                                 if (optional_count != 0) {
4780                                         // Readjust expected number when params used
4781                                         if (cpd.HasParams) {
4782                                                 optional_count--;
4783                                                 if (arg_count < param_count)
4784                                                         param_count--;
4785                                         } else if (arg_count > param_count) {
4786                                                 int args_gap = System.Math.Abs (arg_count - param_count);
4787                                                 return ArgumentCountMismatch + args_gap;
4788                                         } else if (arg_count < param_count - optional_count) {
4789                                                 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4790                                                 return ArgumentCountMismatch + args_gap;
4791                                         }
4792                                 } else if (arg_count != param_count) {
4793                                         int args_gap = System.Math.Abs (arg_count - param_count);
4794                                         if (!cpd.HasParams)
4795                                                 return ArgumentCountMismatch + args_gap;
4796                                         if (arg_count < param_count - 1)
4797                                                 return ArgumentCountMismatch + args_gap;
4798                                 }
4799
4800                                 // Resize to fit optional arguments
4801                                 if (optional_count != 0) {
4802                                         if (arguments == null) {
4803                                                 arguments = new Arguments (optional_count);
4804                                         } else {
4805                                                 // Have to create a new container, so the next run can do same
4806                                                 var resized = new Arguments (param_count);
4807                                                 resized.AddRange (arguments);
4808                                                 arguments = resized;
4809                                         }
4810
4811                                         for (int i = arg_count; i < param_count; ++i)
4812                                                 arguments.Add (null);
4813                                 }
4814                         }
4815
4816                         if (arg_count > 0) {
4817                                 //
4818                                 // Shuffle named arguments to the right positions if there are any
4819                                 //
4820                                 if (arguments[arg_count - 1] is NamedArgument) {
4821                                         arg_count = arguments.Count;
4822
4823                                         for (int i = 0; i < arg_count; ++i) {
4824                                                 bool arg_moved = false;
4825                                                 while (true) {
4826                                                         NamedArgument na = arguments[i] as NamedArgument;
4827                                                         if (na == null)
4828                                                                 break;
4829
4830                                                         int index = pd.GetParameterIndexByName (na.Name);
4831
4832                                                         // Named parameter not found
4833                                                         if (index < 0)
4834                                                                 return NamedArgumentsMismatch - i;
4835
4836                                                         // already reordered
4837                                                         if (index == i)
4838                                                                 break;
4839
4840                                                         Argument temp;
4841                                                         if (index >= param_count) {
4842                                                                 // When using parameters which should not be available to the user
4843                                                                 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4844                                                                         break;
4845
4846                                                                 arguments.Add (null);
4847                                                                 ++arg_count;
4848                                                                 temp = null;
4849                                                         } else {
4850                                                                 if (index == arg_count)
4851                                                                         return NamedArgumentsMismatch - i - 1;
4852
4853                                                                 temp = arguments [index];
4854
4855                                                                 // The slot has been taken by positional argument
4856                                                                 if (temp != null && !(temp is NamedArgument))
4857                                                                         break;
4858                                                         }
4859
4860                                                         if (!arg_moved) {
4861                                                                 arguments = arguments.MarkOrderedArgument (na);
4862                                                                 arg_moved = true;
4863                                                         }
4864
4865                                                         if (arguments == orig_args) {
4866                                                                 arguments = new Arguments (orig_args.Count);
4867                                                                 arguments.AddRange (orig_args);
4868                                                         }
4869
4870                                                         arguments[index] = arguments[i];
4871                                                         arguments[i] = temp;
4872
4873                                                         if (temp == null)
4874                                                                 break;
4875                                                 }
4876                                         }
4877                                 } else {
4878                                         arg_count = arguments.Count;
4879                                 }
4880                         } else if (arguments != null) {
4881                                 arg_count = arguments.Count;
4882                         }
4883
4884                         //
4885                         // Don't do any expensive checks when the candidate cannot succeed
4886                         //
4887                         if (arg_count != param_count && !cpd.HasParams)
4888                                 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
4889
4890                         var dep = candidate.GetMissingDependencies ();
4891                         if (dep != null) {
4892                                 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4893                                 return -1;
4894                         }
4895
4896                         //
4897                         // 1. Handle generic method using type arguments when specified or type inference
4898                         //
4899                         TypeSpec[] ptypes;
4900                         var ms = candidate as MethodSpec;
4901                         if (ms != null && ms.IsGeneric) {
4902                                 if (type_arguments != null) {
4903                                         var g_args_count = ms.Arity;
4904                                         if (g_args_count != type_arguments.Count)
4905                                                 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
4906
4907                                         if (type_arguments.Arguments != null)
4908                                                 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4909                                 } else {
4910                                         //
4911                                         // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4912                                         // probing lambda methods keep all errors reported in separate set and once we are done and no best
4913                                         // candidate was found use the set to report more details about what was wrong with lambda body.
4914                                         // The general idea is to distinguish between code errors and errors caused by
4915                                         // trial-and-error type inference
4916                                         //
4917                                         if (lambda_conv_msgs == null) {
4918                                                 for (int i = 0; i < arg_count; i++) {
4919                                                         Argument a = arguments[i];
4920                                                         if (a == null)
4921                                                                 continue;
4922
4923                                                         var am = a.Expr as AnonymousMethodExpression;
4924                                                         if (am != null) {
4925                                                                 if (lambda_conv_msgs == null)
4926                                                                         lambda_conv_msgs = new SessionReportPrinter ();
4927
4928                                                                 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4929                                                         }
4930                                                 }
4931                                         }
4932
4933                                         var ti = new TypeInference (arguments);
4934                                         TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4935
4936                                         if (i_args == null)
4937                                                 return TypeArgumentsMismatch - ti.InferenceScore;
4938
4939                                         //
4940                                         // Clear any error messages when the result was success
4941                                         //
4942                                         if (lambda_conv_msgs != null)
4943                                                 lambda_conv_msgs.ClearSession ();
4944
4945                                         if (i_args.Length != 0) {
4946                                                 if (!errorMode) {
4947                                                         for (int i = 0; i < i_args.Length; ++i) {
4948                                                                 var ta = i_args [i];
4949                                                                 if (!ta.IsAccessible (ec))
4950                                                                         return TypeArgumentsMismatch - i;
4951                                                         }
4952                                                 }
4953
4954                                                 ms = ms.MakeGenericMethod (ec, i_args);
4955                                         }
4956                                 }
4957
4958                                 //
4959                                 // Type arguments constraints have to match for the method to be applicable
4960                                 //
4961                                 if (!CheckInflatedArguments (ms)) {
4962                                         candidate = ms;
4963                                         return InflatedTypesMismatch;
4964                                 }
4965
4966                                 //
4967                                 // We have a generic return type and at same time the method is override which
4968                                 // means we have to also inflate override return type in case the candidate is
4969                                 // best candidate and override return type is different to base return type.
4970                                 // 
4971                                 // virtual Foo<T, object> with override Foo<T, dynamic>
4972                                 //
4973                                 if (candidate != pm) {
4974                                         MethodSpec override_ms = (MethodSpec) pm;
4975                                         var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4976                                         returnType = inflator.Inflate (returnType);
4977                                 } else {
4978                                         returnType = ms.ReturnType;
4979                                 }
4980
4981                                 candidate = ms;
4982                                 pd = ms.Parameters;
4983                                 ptypes = pd.Types;
4984                         } else {
4985                                 if (type_arguments != null)
4986                                         return UnexpectedTypeArguments;
4987
4988                                 ptypes = cpd.Types;
4989                         }
4990
4991                         //
4992                         // 2. Each argument has to be implicitly convertible to method parameter
4993                         //
4994                         Parameter.Modifier p_mod = 0;
4995                         TypeSpec pt = null;
4996
4997                         for (int i = 0; i < arg_count; i++) {
4998                                 Argument a = arguments[i];
4999                                 if (a == null) {
5000                                         var fp = pd.FixedParameters[i];
5001                                         if (!fp.HasDefaultValue) {
5002                                                 arguments = orig_args;
5003                                                 return arg_count * 2 + 2;
5004                                         }
5005
5006                                         //
5007                                         // Get the default value expression, we can use the same expression
5008                                         // if the type matches
5009                                         //
5010                                         Expression e = fp.DefaultValue;
5011                                         if (e != null) {
5012                                                 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5013                                                 if (e == null) {
5014                                                         // Restore for possible error reporting
5015                                                         for (int ii = i; ii < arg_count; ++ii)
5016                                                                 arguments.RemoveAt (i);
5017
5018                                                         return (arg_count - i) * 2 + 1;
5019                                                 }
5020                                         }
5021
5022                                         if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5023                                                 //
5024                                                 // LAMESPEC: Attributes can be mixed together with build-in priority
5025                                                 //
5026                                                 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5027                                                         e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5028                                                 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5029                                                         e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5030                                                 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5031                                                         e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5032                                                 }
5033                                         }
5034
5035                                         arguments[i] = new Argument (e, Argument.AType.Default);
5036                                         continue;
5037                                 }
5038
5039                                 if (p_mod != Parameter.Modifier.PARAMS) {
5040                                         p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5041                                         pt = ptypes [i];
5042                                 } else if (!params_expanded_form) {
5043                                         params_expanded_form = true;
5044                                         pt = ((ElementTypeSpec) pt).Element;
5045                                         i -= 2;
5046                                         continue;
5047                                 }
5048
5049                                 score = 1;
5050                                 if (!params_expanded_form) {
5051                                         if (a.IsExtensionType) {
5052                                                 //
5053                                                 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
5054                                                 //
5055                                                 // LAMESPEC: or implicit type parameter conversion
5056                                                 //
5057                                                 var at = a.Type;
5058                                                 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
5059                                                         Convert.ImplicitReferenceConversionExists (at, pt, false) ||
5060                                                         Convert.ImplicitBoxingConversion (null, at, pt) != null) {
5061                                                         score = 0;
5062                                                         continue;
5063                                                 }
5064                                         } else {
5065                                                 score = IsArgumentCompatible (ec, a, p_mod, pt);
5066
5067                                                 if (score < 0)
5068                                                         dynamicArgument = true;
5069                                         }
5070                                 }
5071
5072                                 //
5073                                 // It can be applicable in expanded form (when not doing exact match like for delegates)
5074                                 //
5075                                 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5076                                         if (!params_expanded_form) {
5077                                                 pt = ((ElementTypeSpec) pt).Element;
5078                                         }
5079
5080                                         if (score > 0)
5081                                                 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5082
5083                                         if (score < 0) {
5084                                                 params_expanded_form = true;
5085                                                 dynamicArgument = true;
5086                                         } else if (score == 0 || arg_count > pd.Count) {
5087                                                 params_expanded_form = true;
5088                                         }
5089                                 }
5090
5091                                 if (score > 0) {
5092                                         if (params_expanded_form)
5093                                                 ++score;
5094                                         return (arg_count - i) * 2 + score;
5095                                 }
5096                         }
5097
5098                         //
5099                         // Restore original arguments for dynamic binder to keep the intention of original source code
5100                         //
5101                         if (dynamicArgument)
5102                                 arguments = orig_args;
5103
5104                         return 0;
5105                 }
5106
5107                 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5108                 {
5109                         if (e is Constant && e.Type == ptype)
5110                                 return e;
5111
5112                         //
5113                         // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5114                         //
5115                         if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5116                                 e = new MemberAccess (new MemberAccess (new MemberAccess (
5117                                         new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5118                         } else if (e is Constant) {
5119                                 //
5120                                 // Handles int to int? conversions, DefaultParameterValue check
5121                                 //
5122                                 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5123                                 if (e == null)
5124                                         return null;
5125                         } else {
5126                                 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5127                         }
5128
5129                         return e.Resolve (ec);
5130                 }
5131
5132                 //
5133                 // Tests argument compatibility with the parameter
5134                 // The possible return values are
5135                 // 0 - success
5136                 // 1 - modifier mismatch
5137                 // 2 - type mismatch
5138                 // -1 - dynamic binding required
5139                 //
5140                 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5141                 {
5142                         //
5143                         // Types have to be identical when ref or out modifer
5144                         // is used and argument is not of dynamic type
5145                         //
5146                         if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5147                                 if (argument.Type != parameter) {
5148                                         //
5149                                         // Do full equality check after quick path
5150                                         //
5151                                         if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
5152                                                 //
5153                                                 // Using dynamic for ref/out parameter can still succeed at runtime
5154                                                 //
5155                                                 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5156                                                         return -1;
5157
5158                                                 return 2;
5159                                         }
5160                                 }
5161
5162                                 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5163                                         //
5164                                         // Using dynamic for ref/out parameter can still succeed at runtime
5165                                         //
5166                                         if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5167                                                 return -1;
5168
5169                                         return 1;
5170                                 }
5171
5172                         } else {
5173                                 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5174                                         return -1;
5175
5176                                 //
5177                                 // Use implicit conversion in all modes to return same candidates when the expression
5178                                 // is used as argument or delegate conversion
5179                                 //
5180                                 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5181                                         return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5182                                 }
5183                         }
5184
5185                         return 0;
5186                 }
5187
5188                 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5189                 {
5190                         if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5191                                 return q;
5192                         if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5193                                 return p;
5194
5195                         var ac_p = p as ArrayContainer;
5196                         if (ac_p != null) {
5197                                 var ac_q = q as ArrayContainer;
5198                                 if (ac_q == null)
5199                                         return null;
5200
5201                                 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5202                                 if (specific == ac_p.Element)
5203                                         return p;
5204                                 if (specific == ac_q.Element)
5205                                         return q;
5206                         } else if (p.IsGeneric && q.IsGeneric) {
5207                                 var pargs = TypeManager.GetTypeArguments (p);
5208                                 var qargs = TypeManager.GetTypeArguments (q);
5209
5210                                 bool p_specific_at_least_once = false;
5211                                 bool q_specific_at_least_once = false;
5212
5213                                 for (int i = 0; i < pargs.Length; i++) {
5214                                         TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5215                                         if (specific == pargs[i])
5216                                                 p_specific_at_least_once = true;
5217                                         if (specific == qargs[i])
5218                                                 q_specific_at_least_once = true;
5219                                 }
5220
5221                                 if (p_specific_at_least_once && !q_specific_at_least_once)
5222                                         return p;
5223                                 if (!p_specific_at_least_once && q_specific_at_least_once)
5224                                         return q;
5225                         }
5226
5227                         return null;
5228                 }
5229
5230                 //
5231                 // Find the best method from candidate list
5232                 //
5233                 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5234                 {
5235                         List<AmbiguousCandidate> ambiguous_candidates = null;
5236
5237                         MemberSpec best_candidate;
5238                         Arguments best_candidate_args = null;
5239                         bool best_candidate_params = false;
5240                         bool best_candidate_dynamic = false;
5241                         int best_candidate_rate;
5242                         IParametersMember best_parameter_member = null;
5243
5244                         int args_count = args != null ? args.Count : 0;
5245
5246                         Arguments candidate_args = args;
5247                         bool error_mode = false;
5248                         MemberSpec invocable_member = null;
5249
5250                         while (true) {
5251                                 best_candidate = null;
5252                                 best_candidate_rate = int.MaxValue;
5253
5254                                 var type_members = members;
5255                                 do {
5256                                         for (int i = 0; i < type_members.Count; ++i) {
5257                                                 var member = type_members[i];
5258
5259                                                 //
5260                                                 // Methods in a base class are not candidates if any method in a derived
5261                                                 // class is applicable
5262                                                 //
5263                                                 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5264                                                         continue;
5265
5266                                                 if (!error_mode) {
5267                                                         if (!member.IsAccessible (rc))
5268                                                                 continue;
5269
5270                                                         if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5271                                                                 continue;
5272
5273                                                         if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5274                                                                 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5275                                                                 continue;
5276                                                         }
5277                                                 }
5278
5279                                                 IParametersMember pm = member as IParametersMember;
5280                                                 if (pm == null) {
5281                                                         //
5282                                                         // Will use it later to report ambiguity between best method and invocable member
5283                                                         //
5284                                                         if (Invocation.IsMemberInvocable (member))
5285                                                                 invocable_member = member;
5286
5287                                                         continue;
5288                                                 }
5289
5290                                                 //
5291                                                 // Overload resolution is looking for base member but using parameter names
5292                                                 // and default values from the closest member. That means to do expensive lookup
5293                                                 // for the closest override for virtual or abstract members
5294                                                 //
5295                                                 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5296                                                         var override_params = base_provider.GetOverrideMemberParameters (member);
5297                                                         if (override_params != null)
5298                                                                 pm = override_params;
5299                                                 }
5300
5301                                                 //
5302                                                 // Check if the member candidate is applicable
5303                                                 //
5304                                                 bool params_expanded_form = false;
5305                                                 bool dynamic_argument = false;
5306                                                 TypeSpec rt = pm.MemberType;
5307                                                 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5308
5309                                                 if (lambda_conv_msgs != null)
5310                                                         lambda_conv_msgs.EndSession ();
5311
5312                                                 //
5313                                                 // How does it score compare to others
5314                                                 //
5315                                                 if (candidate_rate < best_candidate_rate) {
5316
5317                                                         // Fatal error (missing dependency), cannot continue
5318                                                         if (candidate_rate < 0)
5319                                                                 return null;
5320
5321                                                         if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5322                                                                 // Only parameterless methods are considered
5323                                                         } else {
5324                                                                 best_candidate_rate = candidate_rate;
5325                                                                 best_candidate = member;
5326                                                                 best_candidate_args = candidate_args;
5327                                                                 best_candidate_params = params_expanded_form;
5328                                                                 best_candidate_dynamic = dynamic_argument;
5329                                                                 best_parameter_member = pm;
5330                                                                 best_candidate_return_type = rt;
5331                                                         }
5332                                                 } else if (candidate_rate == 0) {
5333                                                         //
5334                                                         // The member look is done per type for most operations but sometimes
5335                                                         // it's not possible like for binary operators overload because they
5336                                                         // are unioned between 2 sides
5337                                                         //
5338                                                         if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5339                                                                 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5340                                                                         continue;
5341                                                         }
5342
5343                                                         bool is_better;
5344                                                         if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5345                                                                 //
5346                                                                 // We pack all interface members into top level type which makes the overload resolution
5347                                                                 // more complicated for interfaces. We compensate it by removing methods with same
5348                                                                 // signature when building the cache hence this path should not really be hit often
5349                                                                 //
5350                                                                 // Example:
5351                                                                 // interface IA { void Foo (int arg); }
5352                                                                 // interface IB : IA { void Foo (params int[] args); }
5353                                                                 //
5354                                                                 // IB::Foo is the best overload when calling IB.Foo (1)
5355                                                                 //
5356                                                                 is_better = true;
5357                                                                 if (ambiguous_candidates != null) {
5358                                                                         foreach (var amb_cand in ambiguous_candidates) {
5359                                                                                 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5360                                                                                         continue;
5361                                                                                 }
5362
5363                                                                                 is_better = false;
5364                                                                                 break;
5365                                                                         }
5366
5367                                                                         if (is_better)
5368                                                                                 ambiguous_candidates = null;
5369                                                                 }
5370                                                         } else {
5371                                                                 // Is the new candidate better
5372                                                                 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5373                                                         }
5374
5375                                                         if (is_better) {
5376                                                                 best_candidate = member;
5377                                                                 best_candidate_args = candidate_args;
5378                                                                 best_candidate_params = params_expanded_form;
5379                                                                 best_candidate_dynamic = dynamic_argument;
5380                                                                 best_parameter_member = pm;
5381                                                                 best_candidate_return_type = rt;
5382                                                         } else {
5383                                                                 // It's not better but any other found later could be but we are not sure yet
5384                                                                 if (ambiguous_candidates == null)
5385                                                                         ambiguous_candidates = new List<AmbiguousCandidate> ();
5386
5387                                                                 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5388                                                         }
5389                                                 }
5390
5391                                                 // Restore expanded arguments
5392                                                 candidate_args = args;
5393                                         }
5394                                 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5395
5396                                 //
5397                                 // We've found exact match
5398                                 //
5399                                 if (best_candidate_rate == 0)
5400                                         break;
5401
5402                                 //
5403                                 // Try extension methods lookup when no ordinary method match was found and provider enables it
5404                                 //
5405                                 if (!error_mode) {
5406                                         var emg = base_provider.LookupExtensionMethod (rc);
5407                                         if (emg != null) {
5408                                                 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5409                                                 if (emg != null) {
5410                                                         best_candidate_extension_group = emg;
5411                                                         return (T) (MemberSpec) emg.BestCandidate;
5412                                                 }
5413                                         }
5414                                 }
5415
5416                                 // Don't run expensive error reporting mode for probing
5417                                 if (IsProbingOnly)
5418                                         return null;
5419
5420                                 if (error_mode)
5421                                         break;
5422
5423                                 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5424                                         break;
5425
5426                                 lambda_conv_msgs = null;
5427                                 error_mode = true;
5428                         }
5429
5430                         //
5431                         // No best member match found, report an error
5432                         //
5433                         if (best_candidate_rate != 0 || error_mode) {
5434                                 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5435                                 return null;
5436                         }
5437
5438                         if (best_candidate_dynamic) {
5439                                 if (args[0].IsExtensionType) {
5440                                         rc.Report.Error (1973, loc,
5441                                                 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' cannot be dynamically dispatched. Consider calling the method without the extension method syntax",
5442                                                 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5443                                 }
5444
5445                                 //
5446                                 // Check type constraints only when explicit type arguments are used
5447                                 //
5448                                 if (best_candidate.IsGeneric && type_arguments != null) {
5449                                         MethodSpec bc = best_candidate as MethodSpec;
5450                                         if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5451                                                 ConstraintChecker cc = new ConstraintChecker (rc);
5452                                                 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5453                                         }
5454                                 }
5455
5456                                 BestCandidateIsDynamic = true;
5457                                 return null;
5458                         }
5459
5460                         //
5461                         // These flags indicates we are running delegate probing conversion. No need to
5462                         // do more expensive checks
5463                         // 
5464                         if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5465                                 return (T) best_candidate;
5466
5467                         if (ambiguous_candidates != null) {
5468                                 //
5469                                 // Now check that there are no ambiguities i.e the selected method
5470                                 // should be better than all the others
5471                                 //
5472                                 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5473                                         var candidate = ambiguous_candidates [ix];
5474
5475                                         if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5476                                                 var ambiguous = candidate.Member;
5477                                                 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5478                                                         rc.Report.SymbolRelatedToPreviousError (best_candidate);
5479                                                         rc.Report.SymbolRelatedToPreviousError (ambiguous);
5480                                                         rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5481                                                                 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5482                                                 }
5483
5484                                                 return (T) best_candidate;
5485                                         }
5486                                 }
5487                         }
5488
5489                         if (invocable_member != null && !IsProbingOnly) {
5490                                 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5491                                 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5492                                 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5493                                         best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5494                         }
5495
5496                         //
5497                         // And now check if the arguments are all
5498                         // compatible, perform conversions if
5499                         // necessary etc. and return if everything is
5500                         // all right
5501                         //
5502                         if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5503                                 return null;
5504
5505                         if (best_candidate == null)
5506                                 return null;
5507
5508                         //
5509                         // Don't run possibly expensive checks in probing mode
5510                         //
5511                         if (!IsProbingOnly && !rc.IsInProbingMode) {
5512                                 //
5513                                 // Check ObsoleteAttribute on the best method
5514                                 //
5515                                 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5516                                 if (oa != null && !rc.IsObsolete)
5517                                         AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5518
5519                                 best_candidate.MemberDefinition.SetIsUsed ();
5520                         }
5521
5522                         args = best_candidate_args;
5523                         return (T) best_candidate;
5524                 }
5525
5526                 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5527                 {
5528                         return ResolveMember<MethodSpec> (rc, ref args);
5529                 }
5530
5531                 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5532                                                                                                         Argument a, AParametersCollection expected_par, TypeSpec paramType)
5533                 {
5534                         if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5535                                 return;
5536
5537                         if (a.Type == InternalType.ErrorType)
5538                                 return;
5539
5540                         if (a is CollectionElementInitializer.ElementInitializerArgument) {
5541                                 ec.Report.SymbolRelatedToPreviousError (method);
5542                                 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5543                                         ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5544                                                 TypeManager.CSharpSignature (method));
5545                                         return;
5546                                 }
5547                                 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5548                                           TypeManager.CSharpSignature (method));
5549                         } else if (IsDelegateInvoke) {
5550                                 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5551                                         DelegateType.GetSignatureForError ());
5552                         } else {
5553                                 ec.Report.SymbolRelatedToPreviousError (method);
5554                                 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5555                                         method.GetSignatureForError ());
5556                         }
5557
5558                         Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5559
5560                         string index = (idx + 1).ToString ();
5561                         if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5562                                 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5563                                         ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5564                                                 index, Parameter.GetModifierSignature (a.Modifier));
5565                                 else
5566                                         ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5567                                                 index, Parameter.GetModifierSignature (mod));
5568                         } else {
5569                                 string p1 = a.GetSignatureForError ();
5570                                 string p2 = paramType.GetSignatureForError ();
5571
5572                                 if (p1 == p2) {
5573                                         p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5574                                         p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5575                                 }
5576
5577                                 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5578                                         p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5579                                         p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5580                                 }
5581
5582                                 ec.Report.Error (1503, a.Expr.Location,
5583                                         "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5584                         }
5585                 }
5586
5587                 //
5588                 // We have failed to find exact match so we return error info about the closest match
5589                 //
5590                 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5591                 {
5592                         int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5593                         int arg_count = args == null ? 0 : args.Count;
5594
5595                         if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5596                                 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5597                                 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5598                                 return;
5599                         }
5600
5601                         if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5602                                 return;
5603                         }
5604
5605
5606                         if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5607                                 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5608                                 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5609                         }
5610
5611                         //
5612                         // For candidates which match on parameters count report more details about incorrect arguments
5613                         //
5614                         if (pm != null) {
5615                                 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5616                                         // Reject any inaccessible member
5617                                         if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5618                                                 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5619                                                 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5620                                                 return;
5621                                         }
5622
5623                                         var ms = best_candidate as MethodSpec;
5624                                         if (ms != null && ms.IsGeneric) {
5625                                                 bool constr_ok = true;
5626                                                 if (ms.TypeArguments != null)
5627                                                         constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5628
5629                                                 if (ta_count == 0 && ms.TypeArguments == null) {
5630                                                         if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5631                                                                 return;
5632
5633                                                         if (constr_ok) {
5634                                                                 rc.Report.Error (411, loc,
5635                                                                         "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5636                                                                         ms.GetGenericMethodDefinition ().GetSignatureForError ());
5637                                                         }
5638
5639                                                         return;
5640                                                 }
5641                                         }
5642
5643                                         VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5644                                         return;
5645                                 }
5646                         }
5647
5648                         //
5649                         // We failed to find any method with correct argument count, report best candidate
5650                         //
5651                         if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5652                                 return;
5653
5654                         if (best_candidate.Kind == MemberKind.Constructor) {
5655                                 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5656                                 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5657                         } else if (IsDelegateInvoke) {
5658                                 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5659                                 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5660                                         DelegateType.GetSignatureForError (), arg_count.ToString ());
5661                         } else {
5662                                 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5663                                 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5664                                 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5665                                         name, arg_count.ToString ());
5666                         }
5667                 }
5668
5669                 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5670                 {
5671                         var p = ((IParametersMember)best_candidate).Parameters;
5672                         if (!p.HasParams)
5673                                 return false;
5674
5675                         string name = null;
5676                         for (int i = p.Count - 1; i != 0; --i) {
5677                                 var fp = p.FixedParameters [i];
5678                                 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5679                                         continue;
5680
5681                                 name = fp.Name;
5682                                 break;
5683                         }
5684
5685                         if (args == null)
5686                                 return false;
5687
5688                         foreach (var arg in args) {
5689                                 var na = arg as NamedArgument;
5690                                 if (na == null)
5691                                         continue;
5692
5693                                 if (na.Name == name) {
5694                                         name = null;
5695                                         break;
5696                                 }
5697                         }
5698
5699                         if (name == null)
5700                                 return false;
5701
5702                         return args.Count + 1 == pm.Parameters.Count;
5703                 }
5704
5705                 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5706                 {
5707                         var pd = pm.Parameters;
5708                         var cpd = ((IParametersMember) member).Parameters;
5709                         var ptypes = cpd.Types;
5710
5711                         Parameter.Modifier p_mod = 0;
5712                         TypeSpec pt = null;
5713                         int a_idx = 0, a_pos = 0;
5714                         Argument a = null;
5715                         ArrayInitializer params_initializers = null;
5716                         bool has_unsafe_arg = pm.MemberType.IsPointer;
5717                         int arg_count = args == null ? 0 : args.Count;
5718
5719                         for (; a_idx < arg_count; a_idx++, ++a_pos) {
5720                                 a = args[a_idx];
5721                                 if (a == null)
5722                                         continue;
5723
5724                                 if (p_mod != Parameter.Modifier.PARAMS) {
5725                                         p_mod = cpd.FixedParameters [a_idx].ModFlags;
5726                                         pt = ptypes[a_idx];
5727                                         has_unsafe_arg |= pt.IsPointer;
5728
5729                                         if (p_mod == Parameter.Modifier.PARAMS) {
5730                                                 if (chose_params_expanded) {
5731                                                         params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5732                                                         pt = TypeManager.GetElementType (pt);
5733                                                 }
5734                                         }
5735                                 }
5736
5737                                 //
5738                                 // Types have to be identical when ref or out modifer is used 
5739                                 //
5740                                 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5741                                         if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5742                                                 break;
5743
5744                                         if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5745                                                 continue;
5746
5747                                         break;
5748                                 }
5749
5750                                 NamedArgument na = a as NamedArgument;
5751                                 if (na != null) {
5752                                         int name_index = pd.GetParameterIndexByName (na.Name);
5753                                         if (name_index < 0 || name_index >= pd.Count) {
5754                                                 if (IsDelegateInvoke) {
5755                                                         ec.Report.SymbolRelatedToPreviousError (DelegateType);
5756                                                         ec.Report.Error (1746, na.Location,
5757                                                                 "The delegate `{0}' does not contain a parameter named `{1}'",
5758                                                                 DelegateType.GetSignatureForError (), na.Name);
5759                                                 } else {
5760                                                         ec.Report.SymbolRelatedToPreviousError (member);
5761                                                         ec.Report.Error (1739, na.Location,
5762                                                                 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5763                                                                 TypeManager.CSharpSignature (member), na.Name);
5764                                                 }
5765                                         } else if (args[name_index] != a && args[name_index] != null) {
5766                                                 if (IsDelegateInvoke)
5767                                                         ec.Report.SymbolRelatedToPreviousError (DelegateType);
5768                                                 else
5769                                                         ec.Report.SymbolRelatedToPreviousError (member);
5770
5771                                                 ec.Report.Error (1744, na.Location,
5772                                                         "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5773                                                         na.Name);
5774                                         }
5775                                 }
5776                                 
5777                                 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5778                                         continue;
5779
5780                                 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5781                                         custom_errors.NoArgumentMatch (ec, member);
5782                                         return false;
5783                                 }
5784
5785                                 Expression conv;
5786                                 if (a.IsExtensionType) {
5787                                         if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5788                                                 conv = a.Expr;
5789                                         } else {
5790                                                 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5791                                                 if (conv == null)
5792                                                         conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5793                                         }
5794                                 } else {
5795                                         conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5796                                 }
5797
5798                                 if (conv == null)
5799                                         break;
5800
5801                                 //
5802                                 // Convert params arguments to an array initializer
5803                                 //
5804                                 if (params_initializers != null) {
5805                                         // we choose to use 'a.Expr' rather than 'conv' so that
5806                                         // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5807                                         params_initializers.Add (a.Expr);
5808                                         args.RemoveAt (a_idx--);
5809                                         --arg_count;
5810                                         a.Expr = conv;
5811                                         continue;
5812                                 }
5813
5814                                 // Update the argument with the implicit conversion
5815                                 a.Expr = conv;
5816                         }
5817
5818                         if (a_idx != arg_count) {
5819                                 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5820                                 return false;
5821                         }
5822
5823                         //
5824                         // Fill not provided arguments required by params modifier
5825                         //
5826                         if (params_initializers == null && arg_count + 1 == pd.Count) {
5827                                 if (args == null)
5828                                         args = new Arguments (1);
5829
5830                                 pt = ptypes[pd.Count - 1];
5831                                 pt = TypeManager.GetElementType (pt);
5832                                 has_unsafe_arg |= pt.IsPointer;
5833                                 params_initializers = new ArrayInitializer (0, loc);
5834                         }
5835
5836                         //
5837                         // Append an array argument with all params arguments
5838                         //
5839                         if (params_initializers != null) {
5840                                 args.Add (new Argument (
5841                                         new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5842                                 arg_count++;
5843                         }
5844
5845                         if (has_unsafe_arg && !ec.IsUnsafe) {
5846                                 Expression.UnsafeError (ec, loc);
5847                         }
5848
5849                         //
5850                         // We could infer inaccesible type arguments
5851                         //
5852                         if (type_arguments == null && member.IsGeneric) {
5853                                 var ms = (MethodSpec) member;
5854                                 foreach (var ta in ms.TypeArguments) {
5855                                         if (!ta.IsAccessible (ec)) {
5856                                                 ec.Report.SymbolRelatedToPreviousError (ta);
5857                                                 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5858                                                 break;
5859                                         }
5860                                 }
5861                         }
5862
5863                         return true;
5864                 }
5865         }
5866
5867         public class ConstantExpr : MemberExpr
5868         {
5869                 readonly ConstSpec constant;
5870
5871                 public ConstantExpr (ConstSpec constant, Location loc)
5872                 {
5873                         this.constant = constant;
5874                         this.loc = loc;
5875                 }
5876
5877                 public override string Name {
5878                         get { throw new NotImplementedException (); }
5879                 }
5880
5881                 public override string KindName {
5882                         get { return "constant"; }
5883                 }
5884
5885                 public override bool IsInstance {
5886                         get { return !IsStatic; }
5887                 }
5888
5889                 public override bool IsStatic {
5890                         get { return true; }
5891                 }
5892
5893                 protected override TypeSpec DeclaringType {
5894                         get { return constant.DeclaringType; }
5895                 }
5896
5897                 public override Expression CreateExpressionTree (ResolveContext ec)
5898                 {
5899                         throw new NotSupportedException ("ET");
5900                 }
5901
5902                 protected override Expression DoResolve (ResolveContext rc)
5903                 {
5904                         ResolveInstanceExpression (rc, null);
5905                         DoBestMemberChecks (rc, constant);
5906
5907                         var c = constant.GetConstant (rc);
5908
5909                         // Creates reference expression to the constant value
5910                         return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5911                 }
5912
5913                 public override void Emit (EmitContext ec)
5914                 {
5915                         throw new NotSupportedException ();
5916                 }
5917
5918                 public override string GetSignatureForError ()
5919                 {
5920                         return constant.GetSignatureForError ();
5921                 }
5922
5923                 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5924                 {
5925                         Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5926                 }
5927         }
5928
5929         //
5930         // Fully resolved expression that references a Field
5931         //
5932         public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5933         {
5934                 protected FieldSpec spec;
5935                 VariableInfo variable_info;
5936                 
5937                 LocalTemporary temp;
5938                 bool prepared;
5939                 
5940                 protected FieldExpr (Location l)
5941                 {
5942                         loc = l;
5943                 }
5944
5945                 public FieldExpr (FieldSpec spec, Location loc)
5946                 {
5947                         this.spec = spec;
5948                         this.loc = loc;
5949
5950                         type = spec.MemberType;
5951                 }
5952                 
5953                 public FieldExpr (FieldBase fi, Location l)
5954                         : this (fi.Spec, l)
5955                 {
5956                 }
5957
5958                 #region Properties
5959
5960                 public override string Name {
5961                         get {
5962                                 return spec.Name;
5963                         }
5964                 }
5965
5966                 public bool IsHoisted {
5967                         get {
5968                                 IVariableReference hv = InstanceExpression as IVariableReference;
5969                                 return hv != null && hv.IsHoisted;
5970                         }
5971                 }
5972
5973                 public override bool IsInstance {
5974                         get {
5975                                 return !spec.IsStatic;
5976                         }
5977                 }
5978
5979                 public override bool IsStatic {
5980                         get {
5981                                 return spec.IsStatic;
5982                         }
5983                 }
5984
5985                 public override string KindName {
5986                         get { return "field"; }
5987                 }
5988
5989                 public FieldSpec Spec {
5990                         get {
5991                                 return spec;
5992                         }
5993                 }
5994
5995                 protected override TypeSpec DeclaringType {
5996                         get {
5997                                 return spec.DeclaringType;
5998                         }
5999                 }
6000
6001                 public VariableInfo VariableInfo {
6002                         get {
6003                                 return variable_info;
6004                         }
6005                 }
6006
6007 #endregion
6008
6009                 public override string GetSignatureForError ()
6010                 {
6011                         return spec.GetSignatureForError ();
6012                 }
6013
6014                 public bool IsMarshalByRefAccess (ResolveContext rc)
6015                 {
6016                         // Checks possible ldflda of field access expression
6017                         return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6018                                 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6019                                 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6020                 }
6021
6022                 public void SetHasAddressTaken ()
6023                 {
6024                         IVariableReference vr = InstanceExpression as IVariableReference;
6025                         if (vr != null) {
6026                                 vr.SetHasAddressTaken ();
6027                         }
6028                 }
6029
6030                 protected override void CloneTo (CloneContext clonectx, Expression target)
6031                 {
6032                         var t = (FieldExpr) target;
6033
6034                         if (InstanceExpression != null)
6035                                 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6036                 }
6037
6038                 public override Expression CreateExpressionTree (ResolveContext ec)
6039                 {
6040                         if (ConditionalAccess) {
6041                                 Error_NullShortCircuitInsideExpressionTree (ec);
6042                         }
6043
6044                         return CreateExpressionTree (ec, true);
6045                 }
6046
6047                 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6048                 {
6049                         Arguments args;
6050                         Expression instance;
6051
6052                         if (InstanceExpression == null) {
6053                                 instance = new NullLiteral (loc);
6054                         } else if (convertInstance) {
6055                                 instance = InstanceExpression.CreateExpressionTree (ec);
6056                         } else {
6057                                 args = new Arguments (1);
6058                                 args.Add (new Argument (InstanceExpression));
6059                                 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6060                         }
6061
6062                         args = Arguments.CreateForExpressionTree (ec, null,
6063                                 instance,
6064                                 CreateTypeOfExpression ());
6065
6066                         return CreateExpressionFactoryCall (ec, "Field", args);
6067                 }
6068
6069                 public Expression CreateTypeOfExpression ()
6070                 {
6071                         return new TypeOfField (spec, loc);
6072                 }
6073
6074                 protected override Expression DoResolve (ResolveContext ec)
6075                 {
6076                         spec.MemberDefinition.SetIsUsed ();
6077
6078                         return DoResolve (ec, null);
6079                 }
6080
6081                 Expression DoResolve (ResolveContext ec, Expression rhs)
6082                 {
6083                         bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6084
6085                         if (rhs != this) {
6086                                 ResolveConditionalAccessReceiver (ec);
6087
6088                                 if (ResolveInstanceExpression (ec, rhs)) {
6089                                         // Resolve the field's instance expression while flow analysis is turned
6090                                         // off: when accessing a field "a.b", we must check whether the field
6091                                         // "a.b" is initialized, not whether the whole struct "a" is initialized.
6092
6093                                         if (lvalue_instance) {
6094                                                 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6095
6096                                                 Expression right_side =
6097                                                         out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6098
6099                                                 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6100                                         } else {
6101                                                 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6102                                         }
6103
6104                                         if (InstanceExpression == null)
6105                                                 return null;
6106                                 }
6107
6108                                 DoBestMemberChecks (ec, spec);
6109
6110                                 if (conditional_access_receiver)
6111                                         ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6112                         }
6113
6114                         var fb = spec as FixedFieldSpec;
6115                         IVariableReference var = InstanceExpression as IVariableReference;
6116
6117                         if (fb != null) {
6118                                 IFixedExpression fe = InstanceExpression as IFixedExpression;
6119                                 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6120                                         ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6121                                 }
6122
6123                                 if (InstanceExpression.eclass != ExprClass.Variable) {
6124                                         ec.Report.SymbolRelatedToPreviousError (spec);
6125                                         ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6126                                                 TypeManager.GetFullNameSignature (spec));
6127                                 } else if (var != null && var.IsHoisted) {
6128                                         AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6129                                 }
6130
6131                                 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6132                         }
6133
6134                         //
6135                         // Set flow-analysis variable info for struct member access. It will be check later
6136                         // for precise error reporting
6137                         //
6138                         if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6139                                 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6140                         }
6141
6142                         if (ConditionalAccess) {
6143                                 if (conditional_access_receiver)
6144                                         type = LiftMemberType (ec, type);
6145
6146                                 if (InstanceExpression.IsNull)
6147                                         return Constant.CreateConstantFromValue (type, null, loc);
6148                         }
6149
6150                         eclass = ExprClass.Variable;
6151                         return this;
6152                 }
6153
6154                 public void SetFieldAssigned (FlowAnalysisContext fc)
6155                 {
6156                         if (!IsInstance)
6157                                 return;
6158
6159                         bool lvalue_instance = spec.DeclaringType.IsStruct;
6160                         if (lvalue_instance) {
6161                                 var var = InstanceExpression as IVariableReference;
6162                                 if (var != null && var.VariableInfo != null) {
6163                                         fc.SetStructFieldAssigned (var.VariableInfo, Name);
6164                                 }
6165                         }
6166
6167                         var fe = InstanceExpression as FieldExpr;
6168                         if (fe != null) {
6169                                 Expression instance;
6170
6171                                 do {
6172                                         instance = fe.InstanceExpression;
6173                                         var fe_instance = instance as FieldExpr;
6174                                         if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6175                                                 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6176                                                         var var = InstanceExpression as IVariableReference;
6177                                                         if (var != null && var.VariableInfo == null) {
6178                                                                 var var_inst = instance as IVariableReference;
6179                                                                 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6180                                                                         fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6181                                                         }
6182                                                 }
6183
6184                                                 if (fe_instance != null) {
6185                                                         fe = fe_instance;
6186                                                         continue;
6187                                                 }
6188                                         }
6189
6190                                         break;
6191                                 } while (true);
6192
6193                                 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6194                                         instance.FlowAnalysis (fc);
6195                         } else {
6196                                 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6197                                         InstanceExpression.FlowAnalysis (fc);
6198                         }
6199                 }
6200
6201                 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6202                 {
6203                         // The return value is always null.  Returning a value simplifies calling code.
6204         
6205                         if (right_side == EmptyExpression.OutAccess) {
6206                                 if (IsStatic) {
6207                                         rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6208                                                 GetSignatureForError ());
6209                                 } else {
6210                                         rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6211                                                 GetSignatureForError ());
6212                                 }
6213
6214                                 return null;
6215                         }
6216
6217                         if (right_side == EmptyExpression.LValueMemberAccess) {
6218                                 // Already reported as CS1648/CS1650
6219                                 return null;
6220                         }
6221
6222                         if (right_side == EmptyExpression.LValueMemberOutAccess) {
6223                                 if (IsStatic) {
6224                                         rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6225                                                 GetSignatureForError ());
6226                                 } else {
6227                                         rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6228                                                 GetSignatureForError ());
6229                                 }
6230                                 return null;
6231                         }
6232
6233                         if (IsStatic) {
6234                                 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6235                                         GetSignatureForError ());
6236                         } else {
6237                                 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6238                                         GetSignatureForError ());
6239                         }
6240
6241                         return null;
6242                 }
6243
6244                 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6245                 {
6246                         if (ConditionalAccess)
6247                                 throw new NotSupportedException ("null propagating operator assignment");
6248
6249                         if (spec is FixedFieldSpec) {
6250                                 // It could be much better error message but we want to be error compatible
6251                                 Error_ValueAssignment (ec, right_side);
6252                         }
6253
6254                         Expression e = DoResolve (ec, right_side);
6255
6256                         if (e == null)
6257                                 return null;
6258
6259                         spec.MemberDefinition.SetIsAssigned ();
6260
6261                         if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6262                                         (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6263                                 ec.Report.Warning (420, 1, loc,
6264                                         "`{0}': A volatile field references will not be treated as volatile",
6265                                         spec.GetSignatureForError ());
6266                         }
6267
6268                         if (spec.IsReadOnly) {
6269                                 // InitOnly fields can only be assigned in constructors or initializers
6270                                 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6271                                         return Error_AssignToReadonly (ec, right_side);
6272
6273                                 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6274
6275                                         // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6276                                         if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6277                                                 return Error_AssignToReadonly (ec, right_side);
6278                                         // static InitOnly fields cannot be assigned-to in an instance constructor
6279                                         if (IsStatic && !ec.IsStatic)
6280                                                 return Error_AssignToReadonly (ec, right_side);
6281                                         // instance constructors can't modify InitOnly fields of other instances of the same type
6282                                         if (!IsStatic && !(InstanceExpression is This))
6283                                                 return Error_AssignToReadonly (ec, right_side);
6284                                 }
6285                         }
6286
6287                         if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6288                                 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6289                                 ec.Report.Warning (197, 1, loc,
6290                                                 "Passing `{0}' as ref or out or taking its address may cause a runtime exception because it is a field of a marshal-by-reference class",
6291                                                 GetSignatureForError ());
6292                         }
6293
6294                         eclass = ExprClass.Variable;
6295                         return this;
6296                 }
6297
6298                 public override void FlowAnalysis (FlowAnalysisContext fc)
6299                 {
6300                         var var = InstanceExpression as IVariableReference;
6301                         if (var != null) {
6302                                 var vi = var.VariableInfo;
6303                                 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6304                                         fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6305                                         return;
6306                                 }
6307
6308                                 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6309                                         return;
6310                         }
6311
6312                         base.FlowAnalysis (fc);
6313
6314                         if (conditional_access_receiver)
6315                                 fc.ConditionalAccessEnd ();
6316                 }
6317
6318                 public override int GetHashCode ()
6319                 {
6320                         return spec.GetHashCode ();
6321                 }
6322                 
6323                 public bool IsFixed {
6324                         get {
6325                                 //
6326                                 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6327                                 //
6328                                 IVariableReference variable = InstanceExpression as IVariableReference;
6329                                 if (variable != null)
6330                                         return InstanceExpression.Type.IsStruct && variable.IsFixed;
6331
6332                                 IFixedExpression fe = InstanceExpression as IFixedExpression;
6333                                 return fe != null && fe.IsFixed;
6334                         }
6335                 }
6336
6337                 public override bool Equals (object obj)
6338                 {
6339                         FieldExpr fe = obj as FieldExpr;
6340                         if (fe == null)
6341                                 return false;
6342
6343                         if (spec != fe.spec)
6344                                 return false;
6345
6346                         if (InstanceExpression == null || fe.InstanceExpression == null)
6347                                 return true;
6348
6349                         return InstanceExpression.Equals (fe.InstanceExpression);
6350                 }
6351                 
6352                 public void Emit (EmitContext ec, bool leave_copy)
6353                 {
6354                         bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6355
6356                         if (IsStatic){
6357                                 if (is_volatile)
6358                                         ec.Emit (OpCodes.Volatile);
6359
6360                                 ec.Emit (OpCodes.Ldsfld, spec);
6361                         } else {
6362                                 if (!prepared) {
6363                                         if (conditional_access_receiver)
6364                                                 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6365
6366                                         EmitInstance (ec, false);
6367                                 }
6368
6369                                 // Optimization for build-in types
6370                                 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6371                                         ec.EmitLoadFromPtr (type);
6372                                 } else {
6373                                         var ff = spec as FixedFieldSpec;
6374                                         if (ff != null) {
6375                                                 ec.Emit (OpCodes.Ldflda, spec);
6376                                                 ec.Emit (OpCodes.Ldflda, ff.Element);
6377                                         } else {
6378                                                 if (is_volatile)
6379                                                         ec.Emit (OpCodes.Volatile);
6380
6381                                                 ec.Emit (OpCodes.Ldfld, spec);
6382                                         }
6383                                 }
6384
6385                                 if (conditional_access_receiver) {
6386                                         ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6387                                 }
6388                         }
6389
6390                         if (leave_copy) {
6391                                 ec.Emit (OpCodes.Dup);
6392                                 if (!IsStatic) {
6393                                         temp = new LocalTemporary (this.Type);
6394                                         temp.Store (ec);
6395                                 }
6396                         }
6397                 }
6398
6399                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6400                 {
6401                         bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6402                         if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6403                                 prepared = true;
6404                         }
6405
6406                         if (IsInstance) {
6407                                 if (ConditionalAccess)
6408                                         throw new NotImplementedException ("null operator assignment");
6409
6410                                 if (has_await_source)
6411                                         source = source.EmitToField (ec);
6412
6413                                 EmitInstance (ec, prepared);
6414                         }
6415
6416                         source.Emit (ec);
6417
6418                         if (leave_copy || ec.NotifyEvaluatorOnStore) {
6419                                 ec.Emit (OpCodes.Dup);
6420                                 if (!IsStatic) {
6421                                         temp = new LocalTemporary (this.Type);
6422                                         temp.Store (ec);
6423                                 }
6424                         }
6425
6426                         if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6427                                 ec.Emit (OpCodes.Volatile);
6428                                         
6429                         spec.MemberDefinition.SetIsAssigned ();
6430
6431                         if (IsStatic)
6432                                 ec.Emit (OpCodes.Stsfld, spec);
6433                         else
6434                                 ec.Emit (OpCodes.Stfld, spec);
6435
6436                         if (ec.NotifyEvaluatorOnStore) {
6437                                 if (!IsStatic)
6438                                         throw new NotImplementedException ("instance field write");
6439
6440                                 if (leave_copy)
6441                                         ec.Emit (OpCodes.Dup);
6442
6443                                 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6444                         }
6445                         
6446                         if (temp != null) {
6447                                 temp.Emit (ec);
6448                                 temp.Release (ec);
6449                                 temp = null;
6450                         }
6451                 }
6452
6453                 //
6454                 // Emits store to field with prepared values on stack
6455                 //
6456                 public void EmitAssignFromStack (EmitContext ec)
6457                 {
6458                         if (IsStatic) {
6459                                 ec.Emit (OpCodes.Stsfld, spec);
6460                         } else {
6461                                 ec.Emit (OpCodes.Stfld, spec);
6462                         }
6463                 }
6464
6465                 public override void Emit (EmitContext ec)
6466                 {
6467                         Emit (ec, false);
6468                 }
6469
6470                 public override void EmitSideEffect (EmitContext ec)
6471                 {
6472                         bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6473
6474                         if (is_volatile) // || is_marshal_by_ref ())
6475                                 base.EmitSideEffect (ec);
6476                 }
6477
6478                 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6479                 {
6480                         if ((mode & AddressOp.Store) != 0)
6481                                 spec.MemberDefinition.SetIsAssigned ();
6482                         if ((mode & AddressOp.Load) != 0)
6483                                 spec.MemberDefinition.SetIsUsed ();
6484
6485                         //
6486                         // Handle initonly fields specially: make a copy and then
6487                         // get the address of the copy.
6488                         //
6489                         bool need_copy;
6490                         if (spec.IsReadOnly){
6491                                 need_copy = true;
6492                                 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6493                                         if (IsStatic){
6494                                                 if (ec.IsStatic)
6495                                                         need_copy = false;
6496                                         } else
6497                                                 need_copy = false;
6498                                 }
6499                         } else
6500                                 need_copy = false;
6501                         
6502                         if (need_copy) {
6503                                 Emit (ec);
6504                                 var temp = ec.GetTemporaryLocal (type);
6505                                 ec.Emit (OpCodes.Stloc, temp);
6506                                 ec.Emit (OpCodes.Ldloca, temp);
6507                                 return;
6508                         }
6509
6510
6511                         if (IsStatic){
6512                                 ec.Emit (OpCodes.Ldsflda, spec);
6513                         } else {
6514                                 if (!prepared)
6515                                         EmitInstance (ec, false);
6516                                 ec.Emit (OpCodes.Ldflda, spec);
6517                         }
6518                 }
6519
6520                 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6521                 {
6522                         return MakeExpression (ctx);
6523                 }
6524
6525                 public override SLE.Expression MakeExpression (BuilderContext ctx)
6526                 {
6527 #if STATIC
6528                         return base.MakeExpression (ctx);
6529 #else
6530                         return SLE.Expression.Field (
6531                                 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6532                                 spec.GetMetaInfo ());
6533 #endif
6534                 }
6535
6536                 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6537                 {
6538                         Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6539                 }
6540         }
6541
6542         
6543         //
6544         // Expression that evaluates to a Property.
6545         //
6546         // This is not an LValue because we need to re-write the expression. We
6547         // can not take data from the stack and store it.
6548         //
6549         sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6550         {
6551                 Arguments arguments;
6552
6553                 public PropertyExpr (PropertySpec spec, Location l)
6554                         : base (l)
6555                 {
6556                         best_candidate = spec;
6557                         type = spec.MemberType;
6558                 }
6559
6560                 #region Properties
6561
6562                 protected override Arguments Arguments {
6563                         get {
6564                                 return arguments;
6565                         }
6566                         set {
6567                                 arguments = value;
6568                         }
6569                 }
6570
6571                 protected override TypeSpec DeclaringType {
6572                         get {
6573                                 return best_candidate.DeclaringType;
6574                         }
6575                 }
6576
6577                 public override string Name {
6578                         get {
6579                                 return best_candidate.Name;
6580                         }
6581                 }
6582
6583                 public override bool IsInstance {
6584                         get {
6585                                 return !IsStatic;
6586                         }
6587                 }
6588
6589                 public override bool IsStatic {
6590                         get {
6591                                 return best_candidate.IsStatic;
6592                         }
6593                 }
6594
6595                 public override string KindName {
6596                         get { return "property"; }
6597                 }
6598
6599                 public PropertySpec PropertyInfo {
6600                         get {
6601                                 return best_candidate;
6602                         }
6603                 }
6604
6605                 #endregion
6606
6607                 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6608                 {
6609                         if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6610                                 return null;
6611
6612                         var args_count = arguments == null ? 0 : arguments.Count;
6613                         if (args_count != body.Parameters.Count && args_count == 0)
6614                                 return null;
6615
6616                         var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6617                         mg.InstanceExpression = InstanceExpression;
6618
6619                         return mg;
6620                 }
6621
6622                 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6623                 {
6624                         return new PropertyExpr (spec, loc) {
6625                                 Getter = spec.Get,
6626                                 Setter = spec.Set
6627                         };
6628                 }
6629
6630                 public override Expression CreateExpressionTree (ResolveContext ec)
6631                 {
6632                         if (ConditionalAccess) {
6633                                 Error_NullShortCircuitInsideExpressionTree (ec);
6634                         }
6635
6636                         Arguments args;
6637                         if (IsSingleDimensionalArrayLength ()) {
6638                                 args = new Arguments (1);
6639                                 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6640                                 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6641                         }
6642
6643                         args = new Arguments (2);
6644                         if (InstanceExpression == null)
6645                                 args.Add (new Argument (new NullLiteral (loc)));
6646                         else
6647                                 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6648                         args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6649                         return CreateExpressionFactoryCall (ec, "Property", args);
6650                 }
6651
6652                 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6653                 {
6654                         DoResolveLValue (rc, null);
6655                         return new TypeOfMethod (Setter, loc);
6656                 }
6657
6658                 public override string GetSignatureForError ()
6659                 {
6660                         return best_candidate.GetSignatureForError ();
6661                 }
6662
6663                 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6664                 {
6665 #if STATIC
6666                         return base.MakeExpression (ctx);
6667 #else
6668                         return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6669 #endif
6670                 }
6671
6672                 public override SLE.Expression MakeExpression (BuilderContext ctx)
6673                 {
6674 #if STATIC
6675                         return base.MakeExpression (ctx);
6676 #else
6677                         return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6678 #endif
6679                 }
6680
6681                 void Error_PropertyNotValid (ResolveContext ec)
6682                 {
6683                         ec.Report.SymbolRelatedToPreviousError (best_candidate);
6684                         ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6685                                 GetSignatureForError ());
6686                 }
6687
6688                 bool IsSingleDimensionalArrayLength ()
6689                 {
6690                         if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6691                                 return false;
6692
6693                         ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6694                         return ac != null && ac.Rank == 1;
6695                 }
6696
6697                 public override void Emit (EmitContext ec, bool leave_copy)
6698                 {
6699                         //
6700                         // Special case: length of single dimension array property is turned into ldlen
6701                         //
6702                         if (IsSingleDimensionalArrayLength ()) {
6703                                 if (conditional_access_receiver) {
6704                                         ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6705                                 }
6706
6707                                 EmitInstance (ec, false);
6708
6709                                 ec.Emit (OpCodes.Ldlen);
6710                                 ec.Emit (OpCodes.Conv_I4);
6711
6712                                 if (conditional_access_receiver) {
6713                                         ec.CloseConditionalAccess (type);
6714                                 }
6715
6716                                 return;
6717                         }
6718
6719                         base.Emit (ec, leave_copy);
6720                 }
6721
6722                 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6723                 {
6724                         Arguments args;
6725                         LocalTemporary await_source_arg = null;
6726
6727                         if (isCompound && !(source is DynamicExpressionStatement)) {
6728                                 emitting_compound_assignment = true;
6729                                 source.Emit (ec);
6730
6731                                 if (has_await_arguments) {
6732                                         await_source_arg = new LocalTemporary (Type);
6733                                         await_source_arg.Store (ec);
6734
6735                                         args = new Arguments (1);
6736                                         args.Add (new Argument (await_source_arg));
6737
6738                                         if (leave_copy) {
6739                                                 temp = await_source_arg;
6740                                         }
6741
6742                                         has_await_arguments = false;
6743                                 } else {
6744                                         args = null;
6745
6746                                         if (leave_copy) {
6747                                                 ec.Emit (OpCodes.Dup);
6748                                                 temp = new LocalTemporary (this.Type);
6749                                                 temp.Store (ec);
6750                                         }
6751                                 }
6752                         } else {
6753                                 args = arguments ?? new Arguments (1);
6754
6755                                 if (leave_copy) {
6756                                         source.Emit (ec);
6757                                         temp = new LocalTemporary (this.Type);
6758                                         temp.Store (ec);
6759                                         args.Add (new Argument (temp));
6760                                 } else {
6761                                         args.Add (new Argument (source));
6762                                 }
6763                         }
6764
6765                         emitting_compound_assignment = false;
6766
6767                         var call = new CallEmitter ();
6768                         call.InstanceExpression = InstanceExpression;
6769                         if (args == null)
6770                                 call.InstanceExpressionOnStack = true;
6771
6772                         if (ConditionalAccess) {
6773                                 call.ConditionalAccess = true;
6774                         }
6775
6776                         if (leave_copy)
6777                                 call.Emit (ec, Setter, args, loc);
6778                         else
6779                                 call.EmitStatement (ec, Setter, args, loc);
6780
6781                         if (temp != null) {
6782                                 temp.Emit (ec);
6783                                 temp.Release (ec);
6784                         }
6785
6786                         if (await_source_arg != null) {
6787                                 await_source_arg.Release (ec);
6788                         }
6789                 }
6790
6791                 public override void FlowAnalysis (FlowAnalysisContext fc)
6792                 {
6793                         base.FlowAnalysis (fc);
6794
6795                         if (conditional_access_receiver)
6796                                 fc.ConditionalAccessEnd ();
6797                 }
6798
6799                 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6800                 {
6801                         eclass = ExprClass.PropertyAccess;
6802
6803                         if (best_candidate.IsNotCSharpCompatible) {
6804                                 Error_PropertyNotValid (rc);
6805                         }
6806
6807                         ResolveInstanceExpression (rc, right_side);
6808
6809                         if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6810                                 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6811                                 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6812                                 if (p != null) {
6813                                         type = p.MemberType;
6814                                 }
6815                         }
6816
6817                         DoBestMemberChecks (rc, best_candidate);
6818
6819                         // Handling of com-imported properties with any number of default property parameters
6820                         if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6821                                 var p = best_candidate.Get.Parameters;
6822                                 arguments = new Arguments (p.Count);
6823                                 for (int i = 0; i < p.Count; ++i) {
6824                                         arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6825                                 }
6826                         } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6827                                 var p = best_candidate.Set.Parameters;
6828                                 arguments = new Arguments (p.Count - 1);
6829                                 for (int i = 0; i < p.Count - 1; ++i) {
6830                                         arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6831                                 }
6832                         }
6833
6834                         return this;
6835                 }
6836
6837                 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6838                 {
6839                         Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6840                 }
6841         }
6842
6843         abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6844         {
6845                 // getter and setter can be different for base calls
6846                 MethodSpec getter, setter;
6847                 protected T best_candidate;
6848
6849                 protected LocalTemporary temp;
6850                 protected bool emitting_compound_assignment;
6851                 protected bool has_await_arguments;
6852
6853                 protected PropertyOrIndexerExpr (Location l)
6854                 {
6855                         loc = l;
6856                 }
6857
6858                 #region Properties
6859
6860                 protected abstract Arguments Arguments { get; set; }
6861
6862                 public MethodSpec Getter {
6863                         get {
6864                                 return getter;
6865                         }
6866                         set {
6867                                 getter = value;
6868                         }
6869                 }
6870
6871                 public MethodSpec Setter {
6872                         get {
6873                                 return setter;
6874                         }
6875                         set {
6876                                 setter = value;
6877                         }
6878                 }
6879
6880                 #endregion
6881
6882                 protected override Expression DoResolve (ResolveContext ec)
6883                 {
6884                         if (eclass == ExprClass.Unresolved) {
6885                                 ResolveConditionalAccessReceiver (ec);
6886
6887                                 var expr = OverloadResolve (ec, null);
6888                                 if (expr == null)
6889                                         return null;
6890
6891                                 if (expr != this)
6892                                         return expr.Resolve (ec);
6893
6894                                 if (conditional_access_receiver) {
6895                                         type = LiftMemberType (ec, type);
6896                                         ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6897                                 }
6898                         }
6899
6900                         if (!ResolveGetter (ec))
6901                                 return null;
6902
6903                         return this;
6904                 }
6905
6906                 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6907                 {
6908                         if (ConditionalAccess)
6909                                 throw new NotSupportedException ("null propagating operator assignment");
6910
6911                         if (right_side == EmptyExpression.OutAccess) {
6912                                 // TODO: best_candidate can be null at this point
6913                                 INamedBlockVariable variable = null;
6914                                 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6915                                         ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6916                                                 best_candidate.Name);
6917                                 } else {
6918                                         right_side.DoResolveLValue (ec, this);
6919                                 }
6920                                 return null;
6921                         }
6922
6923                         if (eclass == ExprClass.Unresolved) {
6924                                 var expr = OverloadResolve (ec, right_side);
6925                                 if (expr == null)
6926                                         return null;
6927
6928                                 if (expr != this)
6929                                         return expr.ResolveLValue (ec, right_side);
6930                         } else {
6931                                 ResolveInstanceExpression (ec, right_side);
6932                         }
6933
6934                         if (!ResolveSetter (ec))
6935                                 return null;
6936
6937                         return this;
6938                 }
6939
6940                 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
6941                 {
6942                         ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6943
6944                         call.Emit (ec, method, arguments, loc);
6945
6946                         ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
6947                 }
6948
6949                 //
6950                 // Implements the IAssignMethod interface for assignments
6951                 //
6952                 public virtual void Emit (EmitContext ec, bool leave_copy)
6953                 {
6954                         var call = new CallEmitter ();
6955                         call.ConditionalAccess = ConditionalAccess;
6956                         call.InstanceExpression = InstanceExpression;
6957                         if (has_await_arguments)
6958                                 call.HasAwaitArguments = true;
6959                         else
6960                                 call.DuplicateArguments = emitting_compound_assignment;
6961
6962                         if (conditional_access_receiver)
6963                                 EmitConditionalAccess (ec, ref call, Getter, Arguments);
6964                         else
6965                                 call.Emit (ec, Getter, Arguments, loc);
6966
6967                         if (call.HasAwaitArguments) {
6968                                 InstanceExpression = call.InstanceExpression;
6969                                 Arguments = call.EmittedArguments;
6970                                 has_await_arguments = true;
6971                         }
6972
6973                         if (leave_copy) {
6974                                 ec.Emit (OpCodes.Dup);
6975                                 temp = new LocalTemporary (Type);
6976                                 temp.Store (ec);
6977                         }
6978                 }
6979
6980                 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6981
6982                 public override void Emit (EmitContext ec)
6983                 {
6984                         Emit (ec, false);
6985                 }
6986
6987                 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6988                 {
6989                         has_await_arguments = true;
6990                         Emit (ec, false);
6991                         return null;
6992                 }
6993
6994                 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6995
6996                 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6997
6998                 bool ResolveGetter (ResolveContext rc)
6999                 {
7000                         if (!best_candidate.HasGet) {
7001                                 if (InstanceExpression != EmptyExpression.Null) {
7002                                         rc.Report.SymbolRelatedToPreviousError (best_candidate);
7003                                         rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7004                                                 best_candidate.GetSignatureForError ());
7005                                         return false;
7006                                 }
7007                         } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7008                                 if (best_candidate.HasDifferentAccessibility) {
7009                                         rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7010                                         rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7011                                                 TypeManager.CSharpSignature (best_candidate));
7012                                 } else {
7013                                         rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7014                                         ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7015                                 }
7016                         }
7017
7018                         if (best_candidate.HasDifferentAccessibility) {
7019                                 CheckProtectedMemberAccess (rc, best_candidate.Get);
7020                         }
7021
7022                         getter = CandidateToBaseOverride (rc, best_candidate.Get);
7023                         return true;
7024                 }
7025
7026                 bool ResolveSetter (ResolveContext rc)
7027                 {
7028                         if (!best_candidate.HasSet) {
7029                                 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7030                                         GetSignatureForError ());
7031                                 return false;
7032                         }
7033
7034                         if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7035                                 if (best_candidate.HasDifferentAccessibility) {
7036                                         rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7037                                         rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7038                                                 GetSignatureForError ());
7039                                 } else {
7040                                         rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7041                                         ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7042                                 }
7043                         }
7044
7045                         if (best_candidate.HasDifferentAccessibility)
7046                                 CheckProtectedMemberAccess (rc, best_candidate.Set);
7047
7048                         setter = CandidateToBaseOverride (rc, best_candidate.Set);
7049                         return true;
7050                 }
7051         }
7052
7053         /// <summary>
7054         ///   Fully resolved expression that evaluates to an Event
7055         /// </summary>
7056         public class EventExpr : MemberExpr, IAssignMethod
7057         {
7058                 readonly EventSpec spec;
7059                 MethodSpec op;
7060
7061                 public EventExpr (EventSpec spec, Location loc)
7062                 {
7063                         this.spec = spec;
7064                         this.loc = loc;
7065                 }
7066
7067                 #region Properties
7068
7069                 protected override TypeSpec DeclaringType {
7070                         get {
7071                                 return spec.DeclaringType;
7072                         }
7073                 }
7074
7075                 public override string Name {
7076                         get {
7077                                 return spec.Name;
7078                         }
7079                 }
7080
7081                 public override bool IsInstance {
7082                         get {
7083                                 return !spec.IsStatic;
7084                         }
7085                 }
7086
7087                 public override bool IsStatic {
7088                         get {
7089                                 return spec.IsStatic;
7090                         }
7091                 }
7092
7093                 public override string KindName {
7094                         get { return "event"; }
7095                 }
7096
7097                 public MethodSpec Operator {
7098                         get {
7099                                 return op;
7100                         }
7101                 }
7102
7103                 #endregion
7104
7105                 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7106                 {
7107                         //
7108                         // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7109                         //
7110                         if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7111                                 if (spec.BackingField != null &&
7112                                         (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7113
7114                                         spec.MemberDefinition.SetIsUsed ();
7115
7116                                         if (!ec.IsObsolete) {
7117                                                 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
7118                                                 if (oa != null)
7119                                                         AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
7120                                         }
7121
7122                                         if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7123                                                 Error_AssignmentEventOnly (ec);
7124
7125                                         FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7126
7127                                         InstanceExpression = null;
7128
7129                                         return ml.ResolveMemberAccess (ec, left, original);
7130                                 }
7131                         }
7132
7133                         return base.ResolveMemberAccess (ec, left, original);
7134                 }
7135
7136                 public override Expression CreateExpressionTree (ResolveContext ec)
7137                 {
7138                         throw new NotSupportedException ("ET");
7139                 }
7140
7141                 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7142                 {
7143                         if (right_side == EmptyExpression.EventAddition) {
7144                                 op = spec.AccessorAdd;
7145                         } else if (right_side == EmptyExpression.EventSubtraction) {
7146                                 op = spec.AccessorRemove;
7147                         }
7148
7149                         if (op == null) {
7150                                 Error_AssignmentEventOnly (ec);
7151                                 return null;
7152                         }
7153
7154                         op = CandidateToBaseOverride (ec, op);
7155                         return this;
7156                 }
7157
7158                 protected override Expression DoResolve (ResolveContext ec)
7159                 {
7160                         eclass = ExprClass.EventAccess;
7161                         type = spec.MemberType;
7162
7163                         ResolveInstanceExpression (ec, null);
7164
7165                         if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7166                                 Error_AssignmentEventOnly (ec);
7167                         }
7168
7169                         DoBestMemberChecks (ec, spec);
7170                         return this;
7171                 }               
7172
7173                 public override void Emit (EmitContext ec)
7174                 {
7175                         throw new NotSupportedException ();
7176                         //Error_CannotAssign ();
7177                 }
7178
7179                 #region IAssignMethod Members
7180
7181                 public void Emit (EmitContext ec, bool leave_copy)
7182                 {
7183                         throw new NotImplementedException ();
7184                 }
7185
7186                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7187                 {
7188                         if (leave_copy || !isCompound)
7189                                 throw new NotImplementedException ("EventExpr::EmitAssign");
7190
7191                         Arguments args = new Arguments (1);
7192                         args.Add (new Argument (source));
7193
7194                         // TODO: Wrong, needs receiver
7195 //                      if (NullShortCircuit) {
7196 //                              ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7197 //                      }
7198
7199                         var call = new CallEmitter ();
7200                         call.InstanceExpression = InstanceExpression;
7201                         call.ConditionalAccess = ConditionalAccess;
7202                         call.EmitStatement (ec, op, args, loc);
7203
7204 //                      if (NullShortCircuit)
7205 //                              ec.CloseConditionalAccess (null);
7206                 }
7207
7208                 #endregion
7209
7210                 void Error_AssignmentEventOnly (ResolveContext ec)
7211                 {
7212                         if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7213                                 ec.Report.Error (79, loc,
7214                                         "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7215                                         GetSignatureForError ());
7216                         } else {
7217                                 ec.Report.Error (70, loc,
7218                                         "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7219                                         GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7220                         }
7221                 }
7222
7223                 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7224                 {
7225                         name = name.Substring (0, name.LastIndexOf ('.'));
7226                         base.Error_CannotCallAbstractBase (rc, name);
7227                 }
7228
7229                 public override string GetSignatureForError ()
7230                 {
7231                         return TypeManager.CSharpSignature (spec);
7232                 }
7233
7234                 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7235                 {
7236                         Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7237                 }
7238         }
7239
7240         public class TemporaryVariableReference : VariableReference
7241         {
7242                 public class Declarator : Statement
7243                 {
7244                         TemporaryVariableReference variable;
7245
7246                         public Declarator (TemporaryVariableReference variable)
7247                         {
7248                                 this.variable = variable;
7249                                 loc = variable.loc;
7250                         }
7251
7252                         protected override void DoEmit (EmitContext ec)
7253                         {
7254                                 variable.li.CreateBuilder (ec);
7255                         }
7256
7257                         public override void Emit (EmitContext ec)
7258                         {
7259                                 // Don't create sequence point
7260                                 DoEmit (ec);
7261                         }
7262
7263                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7264                         {
7265                                 return false;
7266                         }
7267
7268                         protected override void CloneTo (CloneContext clonectx, Statement target)
7269                         {
7270                                 // Nothing
7271                         }
7272                 }
7273
7274                 LocalVariable li;
7275
7276                 public TemporaryVariableReference (LocalVariable li, Location loc)
7277                 {
7278                         this.li = li;
7279                         this.type = li.Type;
7280                         this.loc = loc;
7281                 }
7282
7283                 public override bool IsLockedByStatement {
7284                         get {
7285                                 return false;
7286                         }
7287                         set {
7288                         }
7289                 }
7290
7291                 public LocalVariable LocalInfo {
7292                     get {
7293                         return li;
7294                     }
7295                 }
7296
7297                 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
7298                 {
7299                         var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
7300                         return new TemporaryVariableReference (li, loc);
7301                 }
7302
7303                 protected override Expression DoResolve (ResolveContext ec)
7304                 {
7305                         eclass = ExprClass.Variable;
7306
7307                         //
7308                         // Don't capture temporary variables except when using
7309                         // state machine redirection and block yields
7310                         //
7311                         if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7312                                 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7313                                 ec.IsVariableCapturingRequired) {
7314                                 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7315                                 storey.CaptureLocalVariable (ec, li);
7316                         }
7317
7318                         return this;
7319                 }
7320
7321                 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7322                 {
7323                         return Resolve (ec);
7324                 }
7325                 
7326                 public override void Emit (EmitContext ec)
7327                 {
7328                         li.CreateBuilder (ec);
7329
7330                         Emit (ec, false);
7331                 }
7332
7333                 public void EmitAssign (EmitContext ec, Expression source)
7334                 {
7335                         li.CreateBuilder (ec);
7336
7337                         EmitAssign (ec, source, false, false);
7338                 }
7339
7340                 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7341                 {
7342                         return li.HoistedVariant;
7343                 }
7344
7345                 public override bool IsFixed {
7346                         get { return true; }
7347                 }
7348
7349                 public override bool IsRef {
7350                         get { return false; }
7351                 }
7352
7353                 public override string Name {
7354                         get { throw new NotImplementedException (); }
7355                 }
7356
7357                 public override void SetHasAddressTaken ()
7358                 {
7359                         throw new NotImplementedException ();
7360                 }
7361
7362                 protected override ILocalVariable Variable {
7363                         get { return li; }
7364                 }
7365
7366                 public override VariableInfo VariableInfo {
7367                         get { return null; }
7368                 }
7369         }
7370
7371         /// 
7372         /// Handles `var' contextual keyword; var becomes a keyword only
7373         /// if no type called var exists in a variable scope
7374         /// 
7375         class VarExpr : SimpleName
7376         {
7377                 public VarExpr (Location loc)
7378                         : base ("var", loc)
7379                 {
7380                 }
7381
7382                 public bool InferType (ResolveContext ec, Expression right_side)
7383                 {
7384                         if (type != null)
7385                                 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7386                         
7387                         type = right_side.Type;
7388                         if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7389                                 ec.Report.Error (815, loc,
7390                                         "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7391                                         type.GetSignatureForError ());
7392                                 return false;
7393                         }
7394
7395                         eclass = ExprClass.Variable;
7396                         return true;
7397                 }
7398
7399                 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7400                 {
7401                         if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7402                                 base.Error_TypeOrNamespaceNotFound (ec);
7403                         else
7404                                 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
7405                 }
7406         }
7407 }