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