2009-11-13 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / generic.cs
1 //
2 // generic.cs: Generics support
3 //
4 // Authors: Martin Baulig (martin@ximian.com)
5 //          Miguel de Icaza (miguel@ximian.com)
6 //          Marek Safar (marek.safar@gmail.com)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004-2008 Novell, Inc
12 //
13 using System;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Globalization;
17 using System.Collections;
18 using System.Text;
19 using System.Text.RegularExpressions;
20         
21 namespace Mono.CSharp {
22
23         /// <summary>
24         ///   Abstract base class for type parameter constraints.
25         ///   The type parameter can come from a generic type definition or from reflection.
26         /// </summary>
27         public abstract class GenericConstraints {
28                 public abstract string TypeParameter {
29                         get;
30                 }
31
32                 public abstract GenericParameterAttributes Attributes {
33                         get;
34                 }
35
36                 public bool HasConstructorConstraint {
37                         get { return (Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0; }
38                 }
39
40                 public bool HasReferenceTypeConstraint {
41                         get { return (Attributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0; }
42                 }
43
44                 public bool HasValueTypeConstraint {
45                         get { return (Attributes & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0; }
46                 }
47
48                 public virtual bool HasClassConstraint {
49                         get { return ClassConstraint != null; }
50                 }
51
52                 public abstract Type ClassConstraint {
53                         get;
54                 }
55
56                 public abstract Type[] InterfaceConstraints {
57                         get;
58                 }
59
60                 public abstract Type EffectiveBaseClass {
61                         get;
62                 }
63
64                 // <summary>
65                 //   Returns whether the type parameter is "known to be a reference type".
66                 // </summary>
67                 public virtual bool IsReferenceType {
68                         get {
69                                 if (HasReferenceTypeConstraint)
70                                         return true;
71                                 if (HasValueTypeConstraint)
72                                         return false;
73
74                                 if (ClassConstraint != null) {
75                                         if (ClassConstraint.IsValueType)
76                                                 return false;
77
78                                         if (ClassConstraint != TypeManager.object_type)
79                                                 return true;
80                                 }
81
82                                 foreach (Type t in InterfaceConstraints) {
83                                         if (!t.IsGenericParameter)
84                                                 continue;
85
86                                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
87                                         if ((gc != null) && gc.IsReferenceType)
88                                                 return true;
89                                 }
90
91                                 return false;
92                         }
93                 }
94
95                 // <summary>
96                 //   Returns whether the type parameter is "known to be a value type".
97                 // </summary>
98                 public virtual bool IsValueType {
99                         get {
100                                 if (HasValueTypeConstraint)
101                                         return true;
102                                 if (HasReferenceTypeConstraint)
103                                         return false;
104
105                                 if (ClassConstraint != null) {
106                                         if (!TypeManager.IsValueType (ClassConstraint))
107                                                 return false;
108
109                                         if (ClassConstraint != TypeManager.value_type)
110                                                 return true;
111                                 }
112
113                                 foreach (Type t in InterfaceConstraints) {
114                                         if (!t.IsGenericParameter)
115                                                 continue;
116
117                                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
118                                         if ((gc != null) && gc.IsValueType)
119                                                 return true;
120                                 }
121
122                                 return false;
123                         }
124                 }
125         }
126
127         public class ReflectionConstraints : GenericConstraints
128         {
129                 GenericParameterAttributes attrs;
130                 Type base_type;
131                 Type class_constraint;
132                 Type[] iface_constraints;
133                 string name;
134
135                 public static GenericConstraints GetConstraints (Type t)
136                 {
137                         Type[] constraints = t.GetGenericParameterConstraints ();
138                         GenericParameterAttributes attrs = t.GenericParameterAttributes;
139                         if (constraints.Length == 0 && attrs == GenericParameterAttributes.None)
140                                 return null;
141                         return new ReflectionConstraints (t.Name, constraints, attrs);
142                 }
143
144                 private ReflectionConstraints (string name, Type[] constraints, GenericParameterAttributes attrs)
145                 {
146                         this.name = name;
147                         this.attrs = attrs;
148
149                         int interface_constraints_pos = 0;
150                         if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0) {
151                                 base_type = TypeManager.value_type;
152                                 interface_constraints_pos = 1;
153                         } else if ((attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0) {
154                                 if (constraints.Length > 0 && constraints[0].IsClass) {
155                                         class_constraint = base_type = constraints[0];
156                                         interface_constraints_pos = 1;
157                                 } else {
158                                         base_type = TypeManager.object_type;
159                                 }
160                         } else {
161                                 base_type = TypeManager.object_type;
162                         }
163
164                         if (constraints.Length > interface_constraints_pos) {
165                                 if (interface_constraints_pos == 0) {
166                                         iface_constraints = constraints;
167                                 } else {
168                                         iface_constraints = new Type[constraints.Length - interface_constraints_pos];
169                                         Array.Copy (constraints, interface_constraints_pos, iface_constraints, 0, iface_constraints.Length);
170                                 }
171                         } else {
172                                 iface_constraints = Type.EmptyTypes;
173                         }
174                 }
175
176                 public override string TypeParameter
177                 {
178                         get { return name; }
179                 }
180
181                 public override GenericParameterAttributes Attributes
182                 {
183                         get { return attrs; }
184                 }
185
186                 public override Type ClassConstraint
187                 {
188                         get { return class_constraint; }
189                 }
190
191                 public override Type EffectiveBaseClass
192                 {
193                         get { return base_type; }
194                 }
195
196                 public override Type[] InterfaceConstraints
197                 {
198                         get { return iface_constraints; }
199                 }
200         }
201
202         public enum Variance
203         {
204                 //
205                 // Don't add or modify internal values, they are used as -/+ calculation signs
206                 //
207                 None                    = 0,
208                 Covariant               = 1,
209                 Contravariant   = -1
210         }
211
212         public enum SpecialConstraint
213         {
214                 Constructor,
215                 ReferenceType,
216                 ValueType
217         }
218
219         /// <summary>
220         ///   Tracks the constraints for a type parameter from a generic type definition.
221         /// </summary>
222         public class Constraints : GenericConstraints {
223                 string name;
224                 ArrayList constraints;
225                 Location loc;
226                 
227                 //
228                 // name is the identifier, constraints is an arraylist of
229                 // Expressions (with types) or `true' for the constructor constraint.
230                 // 
231                 public Constraints (string name, ArrayList constraints,
232                                     Location loc)
233                 {
234                         this.name = name;
235                         this.constraints = constraints;
236                         this.loc = loc;
237                 }
238
239                 public override string TypeParameter {
240                         get {
241                                 return name;
242                         }
243                 }
244
245                 public Constraints Clone ()
246                 {
247                         return new Constraints (name, constraints, loc);
248                 }
249
250                 GenericParameterAttributes attrs;
251                 TypeExpr class_constraint;
252                 ArrayList iface_constraints;
253                 ArrayList type_param_constraints;
254                 int num_constraints;
255                 Type class_constraint_type;
256                 Type[] iface_constraint_types;
257                 Type effective_base_type;
258                 bool resolved;
259                 bool resolved_types;
260
261                 /// <summary>
262                 ///   Resolve the constraints - but only resolve things into Expression's, not
263                 ///   into actual types.
264                 /// </summary>
265                 public bool Resolve (MemberCore ec, TypeParameter tp, Report Report)
266                 {
267                         if (resolved)
268                                 return true;
269
270                         if (ec == null)
271                                 return false;
272
273                         iface_constraints = new ArrayList (2);  // TODO: Too expensive allocation
274                         type_param_constraints = new ArrayList ();
275
276                         foreach (object obj in constraints) {
277                                 if (HasConstructorConstraint) {
278                                         Report.Error (401, loc,
279                                                       "The new() constraint must be the last constraint specified");
280                                         return false;
281                                 }
282
283                                 if (obj is SpecialConstraint) {
284                                         SpecialConstraint sc = (SpecialConstraint) obj;
285
286                                         if (sc == SpecialConstraint.Constructor) {
287                                                 if (!HasValueTypeConstraint) {
288                                                         attrs |= GenericParameterAttributes.DefaultConstructorConstraint;
289                                                         continue;
290                                                 }
291
292                                                 Report.Error (451, loc, "The `new()' constraint " +
293                                                         "cannot be used with the `struct' constraint");
294                                                 return false;
295                                         }
296
297                                         if ((num_constraints > 0) || HasReferenceTypeConstraint || HasValueTypeConstraint) {
298                                                 Report.Error (449, loc, "The `class' or `struct' " +
299                                                               "constraint must be the first constraint specified");
300                                                 return false;
301                                         }
302
303                                         if (sc == SpecialConstraint.ReferenceType)
304                                                 attrs |= GenericParameterAttributes.ReferenceTypeConstraint;
305                                         else
306                                                 attrs |= GenericParameterAttributes.NotNullableValueTypeConstraint;
307                                         continue;
308                                 }
309
310                                 int errors = Report.Errors;
311                                 FullNamedExpression fn = ((Expression) obj).ResolveAsTypeStep (ec, false);
312
313                                 if (fn == null) {
314                                         if (errors != Report.Errors)
315                                                 return false;
316
317                                         NamespaceEntry.Error_NamespaceNotFound (loc, ((Expression)obj).GetSignatureForError (), Report);
318                                         return false;
319                                 }
320
321                                 TypeExpr expr;
322                                 GenericTypeExpr cexpr = fn as GenericTypeExpr;
323                                 if (cexpr != null) {
324                                         expr = cexpr.ResolveAsBaseTerminal (ec, false);
325                                         if (expr != null && cexpr.HasDynamicArguments ()) {
326                                                 Report.Error (1968, cexpr.Location,
327                                                         "A constraint cannot be the dynamic type `{0}'",
328                                                         cexpr.GetSignatureForError ());
329                                                 expr = null;
330                                         }
331                                 } else
332                                         expr = ((Expression) obj).ResolveAsTypeTerminal (ec, false);
333
334                                 if ((expr == null) || (expr.Type == null))
335                                         return false;
336
337                                 if (TypeManager.IsGenericParameter (expr.Type))
338                                         type_param_constraints.Add (expr);
339                                 else if (expr.IsInterface)
340                                         iface_constraints.Add (expr);
341                                 else if (class_constraint != null || iface_constraints.Count != 0) {
342                                         Report.Error (406, loc,
343                                                 "The class type constraint `{0}' must be listed before any other constraints. Consider moving type constraint to the beginning of the constraint list",
344                                                 expr.GetSignatureForError ());
345                                         return false;
346                                 } else if (HasReferenceTypeConstraint || HasValueTypeConstraint) {
347                                         Report.Error (450, loc, "`{0}': cannot specify both " +
348                                                       "a constraint class and the `class' " +
349                                                       "or `struct' constraint", expr.GetSignatureForError ());
350                                         return false;
351                                 } else
352                                         class_constraint = expr;
353
354
355                                 //
356                                 // Checks whether each generic method parameter constraint type
357                                 // is valid with respect to T
358                                 //
359                                 if (tp != null && tp.Type.DeclaringMethod != null) {
360                                         TypeManager.CheckTypeVariance (expr.Type, Variance.Contravariant, ec as MemberCore);
361                                 }
362
363                                 if (!ec.IsAccessibleAs (fn.Type)) {
364                                         Report.SymbolRelatedToPreviousError (fn.Type);
365                                         Report.Error (703, loc,
366                                                 "Inconsistent accessibility: constraint type `{0}' is less accessible than `{1}'",
367                                                 fn.GetSignatureForError (), ec.GetSignatureForError ());
368                                 }
369
370                                 num_constraints++;
371                         }
372
373                         ArrayList list = new ArrayList ();
374                         foreach (TypeExpr iface_constraint in iface_constraints) {
375                                 foreach (Type type in list) {
376                                         if (!type.Equals (iface_constraint.Type))
377                                                 continue;
378
379                                         Report.Error (405, loc,
380                                                       "Duplicate constraint `{0}' for type " +
381                                                       "parameter `{1}'.", iface_constraint.GetSignatureForError (),
382                                                       name);
383                                         return false;
384                                 }
385
386                                 list.Add (iface_constraint.Type);
387                         }
388
389                         foreach (TypeExpr expr in type_param_constraints) {
390                                 foreach (Type type in list) {
391                                         if (!type.Equals (expr.Type))
392                                                 continue;
393
394                                         Report.Error (405, loc,
395                                                       "Duplicate constraint `{0}' for type " +
396                                                       "parameter `{1}'.", expr.GetSignatureForError (), name);
397                                         return false;
398                                 }
399
400                                 list.Add (expr.Type);
401                         }
402
403                         iface_constraint_types = new Type [list.Count];
404                         list.CopyTo (iface_constraint_types, 0);
405
406                         if (class_constraint != null) {
407                                 class_constraint_type = class_constraint.Type;
408                                 if (class_constraint_type == null)
409                                         return false;
410
411                                 if (class_constraint_type.IsSealed) {
412                                         if (class_constraint_type.IsAbstract)
413                                         {
414                                                 Report.Error (717, loc, "`{0}' is not a valid constraint. Static classes cannot be used as constraints",
415                                                         TypeManager.CSharpName (class_constraint_type));
416                                         }
417                                         else
418                                         {
419                                                 Report.Error (701, loc, "`{0}' is not a valid constraint. A constraint must be an interface, " +
420                                                         "a non-sealed class or a type parameter", TypeManager.CSharpName(class_constraint_type));
421                                         }
422                                         return false;
423                                 }
424
425                                 if ((class_constraint_type == TypeManager.array_type) ||
426                                     (class_constraint_type == TypeManager.delegate_type) ||
427                                     (class_constraint_type == TypeManager.enum_type) ||
428                                     (class_constraint_type == TypeManager.value_type) ||
429                                     (class_constraint_type == TypeManager.object_type) ||
430                                         class_constraint_type == TypeManager.multicast_delegate_type) {
431                                         Report.Error (702, loc,
432                                                           "A constraint cannot be special class `{0}'",
433                                                       TypeManager.CSharpName (class_constraint_type));
434                                         return false;
435                                 }
436
437                                 if (TypeManager.IsDynamicType (class_constraint_type)) {
438                                         Report.Error (1967, loc, "A constraint cannot be the dynamic type");
439                                         return false;
440                                 }
441                         }
442
443                         if (class_constraint_type != null)
444                                 effective_base_type = class_constraint_type;
445                         else if (HasValueTypeConstraint)
446                                 effective_base_type = TypeManager.value_type;
447                         else
448                                 effective_base_type = TypeManager.object_type;
449
450                         if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
451                                 attrs |= GenericParameterAttributes.DefaultConstructorConstraint;
452
453                         resolved = true;
454                         return true;
455                 }
456
457                 bool CheckTypeParameterConstraints (Type tparam, ref TypeExpr prevConstraint, ArrayList seen, Report Report)
458                 {
459                         seen.Add (tparam);
460
461                         Constraints constraints = TypeManager.LookupTypeParameter (tparam).Constraints;
462                         if (constraints == null)
463                                 return true;
464
465                         if (constraints.HasValueTypeConstraint) {
466                                 Report.Error (456, loc,
467                                         "Type parameter `{0}' has the `struct' constraint, so it cannot be used as a constraint for `{1}'",
468                                         tparam.Name, name);
469                                 return false;
470                         }
471
472                         //
473                         //  Checks whether there are no conflicts between type parameter constraints
474                         //
475                         //   class Foo<T, U>
476                         //      where T : A
477                         //      where U : A, B  // A and B are not convertible
478                         //
479                         if (constraints.HasClassConstraint) {
480                                 if (prevConstraint != null) {
481                                         Type t2 = constraints.ClassConstraint;
482                                         TypeExpr e2 = constraints.class_constraint;
483
484                                         if (!Convert.ImplicitReferenceConversionExists (prevConstraint, t2) &&
485                                                 !Convert.ImplicitReferenceConversionExists (e2, prevConstraint.Type)) {
486                                                 Report.Error (455, loc,
487                                                         "Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
488                                                         name, TypeManager.CSharpName (prevConstraint.Type), TypeManager.CSharpName (t2));
489                                                 return false;
490                                         }
491                                 }
492
493                                 prevConstraint = constraints.class_constraint;
494                         }
495
496                         if (constraints.type_param_constraints == null)
497                                 return true;
498
499                         foreach (TypeExpr expr in constraints.type_param_constraints) {
500                                 if (seen.Contains (expr.Type)) {
501                                         Report.Error (454, loc, "Circular constraint " +
502                                                       "dependency involving `{0}' and `{1}'",
503                                                       tparam.Name, expr.GetSignatureForError ());
504                                         return false;
505                                 }
506
507                                 if (!CheckTypeParameterConstraints (expr.Type, ref prevConstraint, seen, Report))
508                                         return false;
509                         }
510
511                         return true;
512                 }
513
514                 /// <summary>
515                 ///   Resolve the constraints into actual types.
516                 /// </summary>
517                 public bool ResolveTypes (IMemberContext ec, Report r)
518                 {
519                         if (resolved_types)
520                                 return true;
521
522                         resolved_types = true;
523
524                         foreach (object obj in constraints) {
525                                 GenericTypeExpr cexpr = obj as GenericTypeExpr;
526                                 if (cexpr == null)
527                                         continue;
528
529                                 if (!cexpr.CheckConstraints (ec))
530                                         return false;
531                         }
532
533                         if (type_param_constraints.Count != 0) {
534                                 ArrayList seen = new ArrayList ();
535                                 TypeExpr prev_constraint = class_constraint;
536                                 foreach (TypeExpr expr in type_param_constraints) {
537                                         if (!CheckTypeParameterConstraints (expr.Type, ref prev_constraint, seen, r))
538                                                 return false;
539                                         seen.Clear ();
540                                 }
541                         }
542
543                         for (int i = 0; i < iface_constraints.Count; ++i) {
544                                 TypeExpr iface_constraint = (TypeExpr) iface_constraints [i];
545                                 iface_constraint = iface_constraint.ResolveAsTypeTerminal (ec, false);
546                                 if (iface_constraint == null)
547                                         return false;
548                                 iface_constraints [i] = iface_constraint;
549                         }
550
551                         if (class_constraint != null) {
552                                 class_constraint = class_constraint.ResolveAsTypeTerminal (ec, false);
553                                 if (class_constraint == null)
554                                         return false;
555                         }
556
557                         return true;
558                 }
559
560                 public override GenericParameterAttributes Attributes {
561                         get { return attrs; }
562                 }
563
564                 public override bool HasClassConstraint {
565                         get { return class_constraint != null; }
566                 }
567
568                 public override Type ClassConstraint {
569                         get { return class_constraint_type; }
570                 }
571
572                 public override Type[] InterfaceConstraints {
573                         get { return iface_constraint_types; }
574                 }
575
576                 public override Type EffectiveBaseClass {
577                         get { return effective_base_type; }
578                 }
579
580                 public bool IsSubclassOf (Type t)
581                 {
582                         if ((class_constraint_type != null) &&
583                             class_constraint_type.IsSubclassOf (t))
584                                 return true;
585
586                         if (iface_constraint_types == null)
587                                 return false;
588
589                         foreach (Type iface in iface_constraint_types) {
590                                 if (TypeManager.IsSubclassOf (iface, t))
591                                         return true;
592                         }
593
594                         return false;
595                 }
596
597                 public Location Location {
598                         get {
599                                 return loc;
600                         }
601                 }
602
603                 /// <summary>
604                 ///   This is used when we're implementing a generic interface method.
605                 ///   Each method type parameter in implementing method must have the same
606                 ///   constraints than the corresponding type parameter in the interface
607                 ///   method.  To do that, we're called on each of the implementing method's
608                 ///   type parameters.
609                 /// </summary>
610                 public bool AreEqual (GenericConstraints gc)
611                 {
612                         if (gc.Attributes != attrs)
613                                 return false;
614
615                         if (HasClassConstraint != gc.HasClassConstraint)
616                                 return false;
617                         if (HasClassConstraint && !TypeManager.IsEqual (gc.ClassConstraint, ClassConstraint))
618                                 return false;
619
620                         int gc_icount = gc.InterfaceConstraints != null ?
621                                 gc.InterfaceConstraints.Length : 0;
622                         int icount = InterfaceConstraints != null ?
623                                 InterfaceConstraints.Length : 0;
624
625                         if (gc_icount != icount)
626                                 return false;
627
628                         for (int i = 0; i < gc.InterfaceConstraints.Length; ++i) {
629                                 Type iface = gc.InterfaceConstraints [i];
630                                 if (iface.IsGenericType)
631                                         iface = iface.GetGenericTypeDefinition ();
632                                 
633                                 bool ok = false;
634                                 for (int ii = 0; ii < InterfaceConstraints.Length; ii++) {
635                                         Type check = InterfaceConstraints [ii];
636                                         if (check.IsGenericType)
637                                                 check = check.GetGenericTypeDefinition ();
638                                         
639                                         if (TypeManager.IsEqual (iface, check)) {
640                                                 ok = true;
641                                                 break;
642                                         }
643                                 }
644
645                                 if (!ok)
646                                         return false;
647                         }
648
649                         return true;
650                 }
651
652                 public void VerifyClsCompliance (Report r)
653                 {
654                         if (class_constraint_type != null && !AttributeTester.IsClsCompliant (class_constraint_type))
655                                 Warning_ConstrainIsNotClsCompliant (class_constraint_type, class_constraint.Location, r);
656
657                         if (iface_constraint_types != null) {
658                                 for (int i = 0; i < iface_constraint_types.Length; ++i) {
659                                         if (!AttributeTester.IsClsCompliant (iface_constraint_types [i]))
660                                                 Warning_ConstrainIsNotClsCompliant (iface_constraint_types [i],
661                                                         ((TypeExpr)iface_constraints [i]).Location, r);
662                                 }
663                         }
664                 }
665
666                 void Warning_ConstrainIsNotClsCompliant (Type t, Location loc, Report Report)
667                 {
668                         Report.SymbolRelatedToPreviousError (t);
669                         Report.Warning (3024, 1, loc, "Constraint type `{0}' is not CLS-compliant",
670                                 TypeManager.CSharpName (t));
671                 }
672         }
673
674         /// <summary>
675         ///   A type parameter from a generic type definition.
676         /// </summary>
677         public class TypeParameter : MemberCore, IMemberContainer
678         {
679                 static readonly string[] attribute_target = new string [] { "type parameter" };
680                 
681                 DeclSpace decl;
682                 GenericConstraints gc;
683                 Constraints constraints;
684                 GenericTypeParameterBuilder type;
685                 MemberCache member_cache;
686                 Variance variance;
687
688                 public TypeParameter (DeclSpace parent, DeclSpace decl, string name,
689                                       Constraints constraints, Attributes attrs, Variance variance, Location loc)
690                         : base (parent, new MemberName (name, loc), attrs)
691                 {
692                         this.decl = decl;
693                         this.constraints = constraints;
694                         this.variance = variance;
695                 }
696
697                 public GenericConstraints GenericConstraints {
698                         get { return gc != null ? gc : constraints; }
699                 }
700
701                 public Constraints Constraints {
702                         get { return constraints; }
703                 }
704
705                 public DeclSpace DeclSpace {
706                         get { return decl; }
707                 }
708
709                 public Variance Variance {
710                         get { return variance; }
711                 }
712
713                 public Type Type {
714                         get { return type; }
715                 }
716
717                 /// <summary>
718                 ///   This is the first method which is called during the resolving
719                 ///   process; we're called immediately after creating the type parameters
720                 ///   with SRE (by calling `DefineGenericParameters()' on the TypeBuilder /
721                 ///   MethodBuilder).
722                 ///
723                 ///   We're either called from TypeContainer.DefineType() or from
724                 ///   GenericMethod.Define() (called from Method.Define()).
725                 /// </summary>
726                 public void Define (GenericTypeParameterBuilder type)
727                 {
728                         if (this.type != null)
729                                 throw new InvalidOperationException ();
730
731                         this.type = type;
732                         TypeManager.AddTypeParameter (type, this);
733                 }
734
735                 public void ErrorInvalidVariance (IMemberContext mc, Variance expected)
736                 {
737 // TODO:        Report.SymbolRelatedToPreviousError (mc);
738                         string input_variance = Variance == Variance.Contravariant ? "contravariant" : "covariant";
739                         string gtype_variance;
740                         switch (expected) {
741                         case Variance.Contravariant: gtype_variance = "contravariantly"; break;
742                         case Variance.Covariant: gtype_variance = "covariantly"; break;
743                         default: gtype_variance = "invariantly"; break;
744                         }
745
746                         Delegate d = mc as Delegate;
747                         string parameters = d != null ? d.Parameters.GetSignatureForError () : "";
748
749                         Report.Error (1961, Location,
750                                 "The {2} type parameter `{0}' must be {3} valid on `{1}{4}'",
751                                         GetSignatureForError (), mc.GetSignatureForError (), input_variance, gtype_variance, parameters);
752                 }
753
754                 /// <summary>
755                 ///   This is the second method which is called during the resolving
756                 ///   process - in case of class type parameters, we're called from
757                 ///   TypeContainer.ResolveType() - after it resolved the class'es
758                 ///   base class and interfaces. For method type parameters, we're
759                 ///   called immediately after Define().
760                 ///
761                 ///   We're just resolving the constraints into expressions here, we
762                 ///   don't resolve them into actual types.
763                 ///
764                 ///   Note that in the special case of partial generic classes, we may be
765                 ///   called _before_ Define() and we may also be called multiple types.
766                 /// </summary>
767                 public bool Resolve (DeclSpace ds)
768                 {
769                         if (constraints != null) {
770                                 if (!constraints.Resolve (ds, this, Report)) {
771                                         constraints = null;
772                                         return false;
773                                 }
774                         }
775
776                         return true;
777                 }
778
779                 /// <summary>
780                 ///   This is the third method which is called during the resolving
781                 ///   process.  We're called immediately after calling DefineConstraints()
782                 ///   on all of the current class'es type parameters.
783                 ///
784                 ///   Our job is to resolve the constraints to actual types.
785                 ///
786                 ///   Note that we may have circular dependencies on type parameters - this
787                 ///   is why Resolve() and ResolveType() are separate.
788                 /// </summary>
789                 public bool ResolveType (IMemberContext ec)
790                 {
791                         if (constraints != null) {
792                                 if (!constraints.ResolveTypes (ec, Report)) {
793                                         constraints = null;
794                                         return false;
795                                 }
796                         }
797
798                         return true;
799                 }
800
801                 /// <summary>
802                 ///   This is the fourth and last method which is called during the resolving
803                 ///   process.  We're called after everything is fully resolved and actually
804                 ///   register the constraints with SRE and the TypeManager.
805                 /// </summary>
806                 public bool DefineType (IMemberContext ec)
807                 {
808                         return DefineType (ec, null, null, false);
809                 }
810
811                 /// <summary>
812                 ///   This is the fith and last method which is called during the resolving
813                 ///   process.  We're called after everything is fully resolved and actually
814                 ///   register the constraints with SRE and the TypeManager.
815                 ///
816                 ///   The `builder', `implementing' and `is_override' arguments are only
817                 ///   applicable to method type parameters.
818                 /// </summary>
819                 public bool DefineType (IMemberContext ec, MethodBuilder builder,
820                                         MethodInfo implementing, bool is_override)
821                 {
822                         if (!ResolveType (ec))
823                                 return false;
824
825                         if (implementing != null) {
826                                 if (is_override && (constraints != null)) {
827                                         Report.Error (460, Location,
828                                                 "`{0}': Cannot specify constraints for overrides or explicit interface implementation methods",
829                                                 TypeManager.CSharpSignature (builder));
830                                         return false;
831                                 }
832
833                                 MethodBase mb = TypeManager.DropGenericMethodArguments (implementing);
834
835                                 int pos = type.GenericParameterPosition;
836                                 Type mparam = mb.GetGenericArguments () [pos];
837                                 GenericConstraints temp_gc = ReflectionConstraints.GetConstraints (mparam);
838
839                                 if (temp_gc != null)
840                                         gc = new InflatedConstraints (temp_gc, implementing.DeclaringType);
841                                 else if (constraints != null)
842                                         gc = new InflatedConstraints (constraints, implementing.DeclaringType);
843
844                                 bool ok = true;
845                                 if (constraints != null) {
846                                         if (temp_gc == null)
847                                                 ok = false;
848                                         else if (!constraints.AreEqual (gc))
849                                                 ok = false;
850                                 } else {
851                                         if (!is_override && (temp_gc != null))
852                                                 ok = false;
853                                 }
854
855                                 if (!ok) {
856                                         Report.SymbolRelatedToPreviousError (implementing);
857
858                                         Report.Error (
859                                                 425, Location, "The constraints for type " +
860                                                 "parameter `{0}' of method `{1}' must match " +
861                                                 "the constraints for type parameter `{2}' " +
862                                                 "of interface method `{3}'. Consider using " +
863                                                 "an explicit interface implementation instead",
864                                                 Name, TypeManager.CSharpSignature (builder),
865                                                 TypeManager.CSharpName (mparam), TypeManager.CSharpSignature (mb));
866                                         return false;
867                                 }
868                         } else if (DeclSpace is CompilerGeneratedClass) {
869                                 TypeParameter[] tparams = DeclSpace.TypeParameters;
870                                 Type[] types = new Type [tparams.Length];
871                                 for (int i = 0; i < tparams.Length; i++)
872                                         types [i] = tparams [i].Type;
873
874                                 if (constraints != null)
875                                         gc = new InflatedConstraints (constraints, types);
876                         } else {
877                                 gc = (GenericConstraints) constraints;
878                         }
879
880                         SetConstraints (type);
881                         return true;
882                 }
883
884                 public static TypeParameter FindTypeParameter (TypeParameter[] tparams, string name)
885                 {
886                         foreach (var tp in tparams) {
887                                 if (tp.Name == name)
888                                         return tp;
889                         }
890
891                         return null;
892                 }
893
894                 public void SetConstraints (GenericTypeParameterBuilder type)
895                 {
896                         GenericParameterAttributes attr = GenericParameterAttributes.None;
897                         if (variance == Variance.Contravariant)
898                                 attr |= GenericParameterAttributes.Contravariant;
899                         else if (variance == Variance.Covariant)
900                                 attr |= GenericParameterAttributes.Covariant;
901
902                         if (gc != null) {
903                                 if (gc.HasClassConstraint || gc.HasValueTypeConstraint)
904                                         type.SetBaseTypeConstraint (gc.EffectiveBaseClass);
905
906                                 attr |= gc.Attributes;
907                                 type.SetInterfaceConstraints (gc.InterfaceConstraints);
908                                 TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
909                         }
910                         
911                         type.SetGenericParameterAttributes (attr);
912                 }
913
914                 /// <summary>
915                 ///   This is called for each part of a partial generic type definition.
916                 ///
917                 ///   If `new_constraints' is not null and we don't already have constraints,
918                 ///   they become our constraints.  If we already have constraints, we must
919                 ///   check that they're the same.
920                 ///   con
921                 /// </summary>
922                 public bool UpdateConstraints (MemberCore ec, Constraints new_constraints)
923                 {
924                         if (type == null)
925                                 throw new InvalidOperationException ();
926
927                         if (new_constraints == null)
928                                 return true;
929
930                         if (!new_constraints.Resolve (ec, this, Report))
931                                 return false;
932                         if (!new_constraints.ResolveTypes (ec, Report))
933                                 return false;
934
935                         if (constraints != null) 
936                                 return constraints.AreEqual (new_constraints);
937
938                         constraints = new_constraints;
939                         return true;
940                 }
941
942                 public override void Emit ()
943                 {
944                         if (OptAttributes != null)
945                                 OptAttributes.Emit ();
946
947                         base.Emit ();
948                 }
949
950                 public override string DocCommentHeader {
951                         get {
952                                 throw new InvalidOperationException (
953                                         "Unexpected attempt to get doc comment from " + this.GetType () + ".");
954                         }
955                 }
956
957                 //
958                 // MemberContainer
959                 //
960
961                 public override bool Define ()
962                 {
963                         return true;
964                 }
965
966                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
967                 {
968                         type.SetCustomAttribute (cb);
969                 }
970
971                 public override AttributeTargets AttributeTargets {
972                         get {
973                                 return AttributeTargets.GenericParameter;
974                         }
975                 }
976
977                 public override string[] ValidAttributeTargets {
978                         get {
979                                 return attribute_target;
980                         }
981                 }
982
983                 //
984                 // IMemberContainer
985                 //
986
987                 string IMemberContainer.Name {
988                         get { return Name; }
989                 }
990
991                 MemberCache IMemberContainer.BaseCache {
992                         get {
993                                 if (gc == null)
994                                         return null;
995
996                                 if (gc.EffectiveBaseClass.BaseType == null)
997                                         return null;
998
999                                 return TypeManager.LookupMemberCache (gc.EffectiveBaseClass.BaseType);
1000                         }
1001                 }
1002
1003                 bool IMemberContainer.IsInterface {
1004                         get { return false; }
1005                 }
1006
1007                 MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
1008                 {
1009                         throw new NotSupportedException ();
1010                 }
1011
1012                 public MemberCache MemberCache {
1013                         get {
1014                                 if (member_cache != null)
1015                                         return member_cache;
1016
1017                                 if (gc == null)
1018                                         return null;
1019
1020                                 Type[] ifaces = TypeManager.ExpandInterfaces (gc.InterfaceConstraints);
1021                                 member_cache = new MemberCache (this, gc.EffectiveBaseClass, ifaces);
1022
1023                                 return member_cache;
1024                         }
1025                 }
1026
1027                 public MemberList FindMembers (MemberTypes mt, BindingFlags bf,
1028                                                MemberFilter filter, object criteria)
1029                 {
1030                         if (gc == null)
1031                                 return MemberList.Empty;
1032
1033                         ArrayList members = new ArrayList ();
1034
1035                         if (gc.HasClassConstraint) {
1036                                 MemberList list = TypeManager.FindMembers (
1037                                         gc.ClassConstraint, mt, bf, filter, criteria);
1038
1039                                 members.AddRange (list);
1040                         }
1041
1042                         Type[] ifaces = TypeManager.ExpandInterfaces (gc.InterfaceConstraints);
1043                         foreach (Type t in ifaces) {
1044                                 MemberList list = TypeManager.FindMembers (
1045                                         t, mt, bf, filter, criteria);
1046
1047                                 members.AddRange (list);
1048                         }
1049
1050                         return new MemberList (members);
1051                 }
1052
1053                 public bool IsSubclassOf (Type t)
1054                 {
1055                         if (type.Equals (t))
1056                                 return true;
1057
1058                         if (constraints != null)
1059                                 return constraints.IsSubclassOf (t);
1060
1061                         return false;
1062                 }
1063
1064                 public void InflateConstraints (Type declaring)
1065                 {
1066                         if (constraints != null)
1067                                 gc = new InflatedConstraints (constraints, declaring);
1068                 }
1069                 
1070                 public override bool IsClsComplianceRequired ()
1071                 {
1072                         return false;
1073                 }
1074
1075                 protected class InflatedConstraints : GenericConstraints
1076                 {
1077                         GenericConstraints gc;
1078                         Type base_type;
1079                         Type class_constraint;
1080                         Type[] iface_constraints;
1081                         Type[] dargs;
1082
1083                         public InflatedConstraints (GenericConstraints gc, Type declaring)
1084                                 : this (gc, TypeManager.GetTypeArguments (declaring))
1085                         { }
1086
1087                         public InflatedConstraints (GenericConstraints gc, Type[] dargs)
1088                         {
1089                                 this.gc = gc;
1090                                 this.dargs = dargs;
1091
1092                                 ArrayList list = new ArrayList ();
1093                                 if (gc.HasClassConstraint)
1094                                         list.Add (inflate (gc.ClassConstraint));
1095                                 foreach (Type iface in gc.InterfaceConstraints)
1096                                         list.Add (inflate (iface));
1097
1098                                 bool has_class_constr = false;
1099                                 if (list.Count > 0) {
1100                                         Type first = (Type) list [0];
1101                                         has_class_constr = !first.IsGenericParameter && !first.IsInterface;
1102                                 }
1103
1104                                 if ((list.Count > 0) && has_class_constr) {
1105                                         class_constraint = (Type) list [0];
1106                                         iface_constraints = new Type [list.Count - 1];
1107                                         list.CopyTo (1, iface_constraints, 0, list.Count - 1);
1108                                 } else {
1109                                         iface_constraints = new Type [list.Count];
1110                                         list.CopyTo (iface_constraints, 0);
1111                                 }
1112
1113                                 if (HasValueTypeConstraint)
1114                                         base_type = TypeManager.value_type;
1115                                 else if (class_constraint != null)
1116                                         base_type = class_constraint;
1117                                 else
1118                                         base_type = TypeManager.object_type;
1119                         }
1120
1121                         Type inflate (Type t)
1122                         {
1123                                 if (t == null)
1124                                         return null;
1125                                 if (t.IsGenericParameter)
1126                                         return t.GenericParameterPosition < dargs.Length ? dargs [t.GenericParameterPosition] : t;
1127                                 if (t.IsGenericType) {
1128                                         Type[] args = t.GetGenericArguments ();
1129                                         Type[] inflated = new Type [args.Length];
1130
1131                                         for (int i = 0; i < args.Length; i++)
1132                                                 inflated [i] = inflate (args [i]);
1133
1134                                         t = t.GetGenericTypeDefinition ();
1135                                         t = t.MakeGenericType (inflated);
1136                                 }
1137
1138                                 return t;
1139                         }
1140
1141                         public override string TypeParameter {
1142                                 get { return gc.TypeParameter; }
1143                         }
1144
1145                         public override GenericParameterAttributes Attributes {
1146                                 get { return gc.Attributes; }
1147                         }
1148
1149                         public override Type ClassConstraint {
1150                                 get { return class_constraint; }
1151                         }
1152
1153                         public override Type EffectiveBaseClass {
1154                                 get { return base_type; }
1155                         }
1156
1157                         public override Type[] InterfaceConstraints {
1158                                 get { return iface_constraints; }
1159                         }
1160                 }
1161         }
1162
1163         /// <summary>
1164         ///   A TypeExpr which already resolved to a type parameter.
1165         /// </summary>
1166         public class TypeParameterExpr : TypeExpr {
1167                 
1168                 public TypeParameterExpr (TypeParameter type_parameter, Location loc)
1169                 {
1170                         this.type = type_parameter.Type;
1171                         this.eclass = ExprClass.TypeParameter;
1172                         this.loc = loc;
1173                 }
1174
1175                 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
1176                 {
1177                         throw new NotSupportedException ();
1178                 }
1179
1180                 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
1181                 {
1182                         return this;
1183                 }
1184
1185                 public override bool IsInterface {
1186                         get { return false; }
1187                 }
1188
1189                 public override bool CheckAccessLevel (IMemberContext ds)
1190                 {
1191                         return true;
1192                 }
1193         }
1194
1195         //
1196         // Tracks the type arguments when instantiating a generic type. It's used
1197         // by both type arguments and type parameters
1198         //
1199         public class TypeArguments {
1200                 ArrayList args;
1201                 Type[] atypes;
1202                 
1203                 public TypeArguments ()
1204                 {
1205                         args = new ArrayList ();
1206                 }
1207
1208                 public TypeArguments (params FullNamedExpression[] types)
1209                 {
1210                         this.args = new ArrayList (types);
1211                 }
1212
1213                 public void Add (FullNamedExpression type)
1214                 {
1215                         args.Add (type);
1216                 }
1217
1218                 public void Add (TypeArguments new_args)
1219                 {
1220                         args.AddRange (new_args.args);
1221                 }
1222
1223                 // TODO: Should be deleted
1224                 public TypeParameterName[] GetDeclarations ()
1225                 {
1226                         return (TypeParameterName[]) args.ToArray (typeof (TypeParameterName));
1227                 }
1228
1229                 /// <summary>
1230                 ///   We may only be used after Resolve() is called and return the fully
1231                 ///   resolved types.
1232                 /// </summary>
1233                 public Type[] Arguments {
1234                         get {
1235                                 return atypes;
1236                         }
1237                 }
1238
1239                 public int Count {
1240                         get {
1241                                 return args.Count;
1242                         }
1243                 }
1244
1245                 public string GetSignatureForError()
1246                 {
1247                         StringBuilder sb = new StringBuilder();
1248                         for (int i = 0; i < Count; ++i)
1249                         {
1250                                 Expression expr = (Expression)args [i];
1251                                 sb.Append(expr.GetSignatureForError());
1252                                 if (i + 1 < Count)
1253                                         sb.Append(',');
1254                         }
1255                         return sb.ToString();
1256                 }
1257
1258                 /// <summary>
1259                 ///   Resolve the type arguments.
1260                 /// </summary>
1261                 public bool Resolve (IMemberContext ec)
1262                 {
1263                         if (atypes != null)
1264                                 return atypes.Length != 0;
1265
1266                         int count = args.Count;
1267                         bool ok = true;
1268
1269                         atypes = new Type [count];
1270
1271                         for (int i = 0; i < count; i++){
1272                                 TypeExpr te = ((FullNamedExpression) args[i]).ResolveAsTypeTerminal (ec, false);
1273                                 if (te == null) {
1274                                         ok = false;
1275                                         continue;
1276                                 }
1277
1278                                 atypes[i] = te.Type;
1279
1280                                 if (te.Type.IsSealed && te.Type.IsAbstract) {
1281                                         ec.Compiler.Report.Error (718, te.Location, "`{0}': static classes cannot be used as generic arguments",
1282                                                 te.GetSignatureForError ());
1283                                         ok = false;
1284                                 }
1285
1286                                 if (te.Type.IsPointer || TypeManager.IsSpecialType (te.Type)) {
1287                                         ec.Compiler.Report.Error (306, te.Location,
1288                                                 "The type `{0}' may not be used as a type argument",
1289                                                 te.GetSignatureForError ());
1290                                         ok = false;
1291                                 }
1292                         }
1293
1294                         if (!ok)
1295                                 atypes = Type.EmptyTypes;
1296
1297                         return ok;
1298                 }
1299
1300                 public TypeArguments Clone ()
1301                 {
1302                         TypeArguments copy = new TypeArguments ();
1303                         foreach (Expression ta in args)
1304                                 copy.args.Add (ta);
1305
1306                         return copy;
1307                 }
1308         }
1309
1310         public class TypeParameterName : SimpleName
1311         {
1312                 Attributes attributes;
1313                 Variance variance;
1314
1315                 public TypeParameterName (string name, Attributes attrs, Location loc)
1316                         : this (name, attrs, Variance.None, loc)
1317                 {
1318                 }
1319
1320                 public TypeParameterName (string name, Attributes attrs, Variance variance, Location loc)
1321                         : base (name, loc)
1322                 {
1323                         attributes = attrs;
1324                         this.variance = variance;
1325                 }
1326
1327                 public Attributes OptAttributes {
1328                         get {
1329                                 return attributes;
1330                         }
1331                 }
1332
1333                 public Variance Variance {
1334                         get {
1335                                 return variance;
1336                         }
1337                 }
1338         }
1339
1340         /// <summary>
1341         ///   A reference expression to generic type
1342         /// </summary>  
1343         class GenericTypeExpr : TypeExpr
1344         {
1345                 TypeArguments args;
1346                 Type[] gen_params;      // TODO: Waiting for constrains check cleanup
1347                 Type open_type;
1348
1349                 //
1350                 // Should be carefully used only with defined generic containers. Type parameters
1351                 // can be used as type arguments in this case.
1352                 //
1353                 // TODO: This could be GenericTypeExpr specialization
1354                 //
1355                 public GenericTypeExpr (DeclSpace gType, Location l)
1356                 {
1357                         open_type = gType.TypeBuilder.GetGenericTypeDefinition ();
1358
1359                         args = new TypeArguments ();
1360                         foreach (TypeParameter type_param in gType.TypeParameters)
1361                                 args.Add (new TypeParameterExpr (type_param, l));
1362
1363                         this.loc = l;
1364                 }
1365
1366                 /// <summary>
1367                 ///   Instantiate the generic type `t' with the type arguments `args'.
1368                 ///   Use this constructor if you already know the fully resolved
1369                 ///   generic type.
1370                 /// </summary>          
1371                 public GenericTypeExpr (Type t, TypeArguments args, Location l)
1372                 {
1373                         open_type = t.GetGenericTypeDefinition ();
1374
1375                         loc = l;
1376                         this.args = args;
1377                 }
1378
1379                 public TypeArguments TypeArguments {
1380                         get { return args; }
1381                 }
1382
1383                 public override string GetSignatureForError ()
1384                 {
1385                         return TypeManager.CSharpName (type);
1386                 }
1387
1388                 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
1389                 {
1390                         if (eclass != ExprClass.Invalid)
1391                                 return this;
1392
1393                         eclass = ExprClass.Type;
1394
1395                         if (!args.Resolve (ec))
1396                                 return null;
1397
1398                         gen_params = open_type.GetGenericArguments ();
1399                         Type[] atypes = args.Arguments;
1400                         
1401                         if (atypes.Length != gen_params.Length) {
1402                                 Namespace.Error_InvalidNumberOfTypeArguments (open_type, loc);
1403                                 return null;
1404                         }
1405
1406                         //
1407                         // Now bind the parameters
1408                         //
1409                         type = open_type.MakeGenericType (atypes);
1410                         return this;
1411                 }
1412
1413                 /// <summary>
1414                 ///   Check the constraints; we're called from ResolveAsTypeTerminal()
1415                 ///   after fully resolving the constructed type.
1416                 /// </summary>
1417                 public bool CheckConstraints (IMemberContext ec)
1418                 {
1419                         return ConstraintChecker.CheckConstraints (ec, open_type, gen_params, args.Arguments, loc);
1420                 }
1421         
1422                 public override bool CheckAccessLevel (IMemberContext mc)
1423                 {
1424                         return mc.CurrentTypeDefinition.CheckAccessLevel (open_type);
1425                 }
1426
1427                 public bool HasDynamicArguments ()
1428                 {
1429                         return HasDynamicArguments (args.Arguments);
1430                 }
1431
1432                 static bool HasDynamicArguments (Type[] args)
1433                 {
1434                         foreach (var item in args)
1435                         {
1436                                 if (TypeManager.IsGenericType (item))
1437                                         return HasDynamicArguments (TypeManager.GetTypeArguments (item));
1438
1439                                 if (TypeManager.IsDynamicType (item))
1440                                         return true;
1441                         }
1442
1443                         return false;
1444                 }
1445
1446                 public override bool IsClass {
1447                         get { return open_type.IsClass; }
1448                 }
1449
1450                 public override bool IsValueType {
1451                         get { return TypeManager.IsStruct (open_type); }
1452                 }
1453
1454                 public override bool IsInterface {
1455                         get { return open_type.IsInterface; }
1456                 }
1457
1458                 public override bool IsSealed {
1459                         get { return open_type.IsSealed; }
1460                 }
1461
1462                 public override bool Equals (object obj)
1463                 {
1464                         GenericTypeExpr cobj = obj as GenericTypeExpr;
1465                         if (cobj == null)
1466                                 return false;
1467
1468                         if ((type == null) || (cobj.type == null))
1469                                 return false;
1470
1471                         return type == cobj.type;
1472                 }
1473
1474                 public override int GetHashCode ()
1475                 {
1476                         return base.GetHashCode ();
1477                 }
1478         }
1479
1480         public abstract class ConstraintChecker
1481         {
1482                 protected readonly Type[] gen_params;
1483                 protected readonly Type[] atypes;
1484                 protected readonly Location loc;
1485                 protected Report Report;
1486
1487                 protected ConstraintChecker (Type[] gen_params, Type[] atypes, Location loc, Report r)
1488                 {
1489                         this.gen_params = gen_params;
1490                         this.atypes = atypes;
1491                         this.loc = loc;
1492                         this.Report = r;
1493                 }
1494
1495                 /// <summary>
1496                 ///   Check the constraints; we're called from ResolveAsTypeTerminal()
1497                 ///   after fully resolving the constructed type.
1498                 /// </summary>
1499                 public bool CheckConstraints (IMemberContext ec)
1500                 {
1501                         for (int i = 0; i < gen_params.Length; i++) {
1502                                 if (!CheckConstraints (ec, i))
1503                                         return false;
1504                         }
1505
1506                         return true;
1507                 }
1508
1509                 protected bool CheckConstraints (IMemberContext ec, int index)
1510                 {
1511                         Type atype = TypeManager.TypeToCoreType (atypes [index]);
1512                         Type ptype = gen_params [index];
1513
1514                         if (atype == ptype)
1515                                 return true;
1516
1517                         Expression aexpr = new EmptyExpression (atype);
1518
1519                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (ptype);
1520                         if (gc == null)
1521                                 return true;
1522
1523                         bool is_class, is_struct;
1524                         if (atype.IsGenericParameter) {
1525                                 GenericConstraints agc = TypeManager.GetTypeParameterConstraints (atype);
1526                                 if (agc != null) {
1527                                         if (agc is Constraints) {
1528                                                 // FIXME: No constraints can be resolved here, we are in
1529                                                 // completely wrong/different context. This path is hit
1530                                                 // when resolving base type of unresolved generic type
1531                                                 // with constraints. We are waiting with CheckConsttraints
1532                                                 // after type-definition but not in this case
1533                                                 if (!((Constraints) agc).Resolve (null, null, Report))
1534                                                         return true;
1535                                         }
1536                                         is_class = agc.IsReferenceType;
1537                                         is_struct = agc.IsValueType;
1538                                 } else {
1539                                         is_class = is_struct = false;
1540                                 }
1541                         } else {
1542                                 is_class = TypeManager.IsReferenceType (atype);
1543                                 is_struct = TypeManager.IsValueType (atype) && !TypeManager.IsNullableType (atype);
1544                         }
1545
1546                         //
1547                         // First, check the `class' and `struct' constraints.
1548                         //
1549                         if (gc.HasReferenceTypeConstraint && !is_class) {
1550                                 Report.Error (452, loc, "The type `{0}' must be " +
1551                                               "a reference type in order to use it " +
1552                                               "as type parameter `{1}' in the " +
1553                                               "generic type or method `{2}'.",
1554                                               TypeManager.CSharpName (atype),
1555                                               TypeManager.CSharpName (ptype),
1556                                               GetSignatureForError ());
1557                                 return false;
1558                         } else if (gc.HasValueTypeConstraint && !is_struct) {
1559                                 Report.Error (453, loc, "The type `{0}' must be a " +
1560                                               "non-nullable value type in order to use it " +
1561                                               "as type parameter `{1}' in the " +
1562                                               "generic type or method `{2}'.",
1563                                               TypeManager.CSharpName (atype),
1564                                               TypeManager.CSharpName (ptype),
1565                                               GetSignatureForError ());
1566                                 return false;
1567                         }
1568
1569                         //
1570                         // The class constraint comes next.
1571                         //
1572                         if (gc.HasClassConstraint) {
1573                                 if (!CheckConstraint (ec, ptype, aexpr, gc.ClassConstraint))
1574                                         return false;
1575                         }
1576
1577                         //
1578                         // Now, check the interface constraints.
1579                         //
1580                         if (gc.InterfaceConstraints != null) {
1581                                 foreach (Type it in gc.InterfaceConstraints) {
1582                                         if (!CheckConstraint (ec, ptype, aexpr, it))
1583                                                 return false;
1584                                 }
1585                         }
1586
1587                         //
1588                         // Finally, check the constructor constraint.
1589                         //
1590
1591                         if (!gc.HasConstructorConstraint)
1592                                 return true;
1593
1594                         if (TypeManager.IsValueType (atype))
1595                                 return true;
1596
1597                         if (HasDefaultConstructor (atype))
1598                                 return true;
1599
1600                         Report_SymbolRelatedToPreviousError ();
1601                         Report.SymbolRelatedToPreviousError (atype);
1602                         Report.Error (310, loc, "The type `{0}' must have a public " +
1603                                       "parameterless constructor in order to use it " +
1604                                       "as parameter `{1}' in the generic type or " +
1605                                       "method `{2}'",
1606                                       TypeManager.CSharpName (atype),
1607                                       TypeManager.CSharpName (ptype),
1608                                       GetSignatureForError ());
1609                         return false;
1610                 }
1611                 
1612                 Type InflateType(IMemberContext ec, Type ctype)
1613                 {
1614                         Type[] types = TypeManager.GetTypeArguments (ctype);
1615
1616                         TypeArguments new_args = new TypeArguments ();
1617
1618                         for (int i = 0; i < types.Length; i++) {
1619                                 Type t = TypeManager.TypeToCoreType (types [i]);
1620
1621                                 if (t.IsGenericParameter) {
1622                                         int pos = t.GenericParameterPosition;
1623                                         if (t.DeclaringMethod == null && this is MethodConstraintChecker) {
1624                                                 Type parent = ((MethodConstraintChecker) this).declaring_type;
1625                                                 t = parent.GetGenericArguments ()[pos];
1626                                         } else {
1627                                                 t = atypes [pos];
1628                                         }
1629                                 } else if(TypeManager.HasGenericArguments(t)) {
1630                                         t = InflateType (ec, t);
1631                                         if (t == null) {
1632                                                 return null;
1633                                         }
1634                                 }
1635                                 new_args.Add (new TypeExpression (t, loc));
1636                         }
1637
1638                         TypeExpr ct = new GenericTypeExpr (ctype, new_args, loc);
1639                         if (ct.ResolveAsTypeStep (ec, false) == null)
1640                                 return null;
1641                         
1642                         return ct.Type;
1643                 }
1644
1645                 protected bool CheckConstraint (IMemberContext ec, Type ptype, Expression expr,
1646                                                 Type ctype)
1647                 {
1648                         //
1649                         // All this is needed because we don't have
1650                         // real inflated type hierarchy
1651                         //
1652                         if (TypeManager.HasGenericArguments (ctype)) {
1653                                 ctype = InflateType (ec, ctype);
1654                                 if(ctype == null) {
1655                                         return false;
1656                                 }
1657                         } else if (ctype.IsGenericParameter) {
1658                                 int pos = ctype.GenericParameterPosition;
1659                                 if (ctype.DeclaringMethod == null) {
1660                                         // FIXME: Implement
1661                                         return true;
1662                                 } else {                                
1663                                         ctype = atypes [pos];
1664                                 }
1665                         }
1666
1667                         if (Convert.ImplicitStandardConversionExists (expr, ctype))
1668                                 return true;
1669
1670                         Report_SymbolRelatedToPreviousError ();
1671                         Report.SymbolRelatedToPreviousError (expr.Type);
1672
1673                         if (TypeManager.IsNullableType (expr.Type) && ctype.IsInterface) {
1674                                 Report.Error (313, loc,
1675                                         "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. " +
1676                                         "The nullable type `{0}' never satisfies interface constraint of type `{3}'",
1677                                         TypeManager.CSharpName (expr.Type), TypeManager.CSharpName (ptype),
1678                                         GetSignatureForError (), TypeManager.CSharpName (ctype));
1679                         } else {
1680                                 Report.Error (309, loc,
1681                                         "The type `{0}' must be convertible to `{1}' in order to " +
1682                                         "use it as parameter `{2}' in the generic type or method `{3}'",
1683                                         TypeManager.CSharpName (expr.Type), TypeManager.CSharpName (ctype),
1684                                         TypeManager.CSharpName (ptype), GetSignatureForError ());
1685                         }
1686                         return false;
1687                 }
1688
1689                 static bool HasDefaultConstructor (Type atype)
1690                 {
1691                         TypeParameter tparam = TypeManager.LookupTypeParameter (atype);
1692                         if (tparam != null) {
1693                                 if (tparam.GenericConstraints == null)
1694                                         return false;
1695                                                 
1696                                 return tparam.GenericConstraints.HasConstructorConstraint || 
1697                                         tparam.GenericConstraints.HasValueTypeConstraint;
1698                         }
1699                 
1700                         if (atype.IsAbstract)
1701                                 return false;
1702
1703                 again:
1704                         atype = TypeManager.DropGenericTypeArguments (atype);
1705                         if (atype is TypeBuilder) {
1706                                 TypeContainer tc = TypeManager.LookupTypeContainer (atype);
1707                                 if (tc.InstanceConstructors == null) {
1708                                         atype = atype.BaseType;
1709                                         goto again;
1710                                 }
1711
1712                                 foreach (Constructor c in tc.InstanceConstructors) {
1713                                         if ((c.ModFlags & Modifiers.PUBLIC) == 0)
1714                                                 continue;
1715                                         if ((c.Parameters.FixedParameters != null) &&
1716                                             (c.Parameters.FixedParameters.Length != 0))
1717                                                 continue;
1718                                         if (c.Parameters.HasArglist || c.Parameters.HasParams)
1719                                                 continue;
1720
1721                                         return true;
1722                                 }
1723                         }
1724
1725                         MemberInfo [] list = TypeManager.MemberLookup (null, null, atype, MemberTypes.Constructor,
1726                                 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
1727                                 ConstructorInfo.ConstructorName, null);
1728
1729                         if (list == null)
1730                                 return false;
1731
1732                         foreach (MethodBase mb in list) {
1733                                 AParametersCollection pd = TypeManager.GetParameterData (mb);
1734                                 if (pd.Count == 0)
1735                                         return true;
1736                         }
1737
1738                         return false;
1739                 }
1740
1741                 protected abstract string GetSignatureForError ();
1742                 protected abstract void Report_SymbolRelatedToPreviousError ();
1743
1744                 public static bool CheckConstraints (IMemberContext ec, MethodBase definition,
1745                                                      MethodBase instantiated, Location loc)
1746                 {
1747                         MethodConstraintChecker checker = new MethodConstraintChecker (
1748                                 definition, instantiated.DeclaringType, definition.GetGenericArguments (),
1749                                 instantiated.GetGenericArguments (), loc, ec.Compiler.Report);
1750
1751                         return checker.CheckConstraints (ec);
1752                 }
1753
1754                 public static bool CheckConstraints (IMemberContext ec, Type gt, Type[] gen_params,
1755                                                      Type[] atypes, Location loc)
1756                 {
1757                         TypeConstraintChecker checker = new TypeConstraintChecker (
1758                                 gt, gen_params, atypes, loc, ec.Compiler.Report);
1759
1760                         return checker.CheckConstraints (ec);
1761                 }
1762
1763                 protected class MethodConstraintChecker : ConstraintChecker
1764                 {
1765                         MethodBase definition;
1766                         public Type declaring_type;
1767
1768                         public MethodConstraintChecker (MethodBase definition, Type declaringType, Type[] gen_params,
1769                                                         Type[] atypes, Location loc, Report r)
1770                                 : base (gen_params, atypes, loc, r)
1771                         {
1772                                 this.declaring_type = declaringType;
1773                                 this.definition = definition;
1774                         }
1775
1776                         protected override string GetSignatureForError ()
1777                         {
1778                                 return TypeManager.CSharpSignature (definition);
1779                         }
1780
1781                         protected override void Report_SymbolRelatedToPreviousError ()
1782                         {
1783                                 Report.SymbolRelatedToPreviousError (definition);
1784                         }
1785                 }
1786
1787                 protected class TypeConstraintChecker : ConstraintChecker
1788                 {
1789                         Type gt;
1790
1791                         public TypeConstraintChecker (Type gt, Type[] gen_params, Type[] atypes,
1792                                                       Location loc, Report r)
1793                                 : base (gen_params, atypes, loc, r)
1794                         {
1795                                 this.gt = gt;
1796                         }
1797
1798                         protected override string GetSignatureForError ()
1799                         {
1800                                 return TypeManager.CSharpName (gt);
1801                         }
1802
1803                         protected override void Report_SymbolRelatedToPreviousError ()
1804                         {
1805                                 Report.SymbolRelatedToPreviousError (gt);
1806                         }
1807                 }
1808         }
1809
1810         /// <summary>
1811         ///   A generic method definition.
1812         /// </summary>
1813         public class GenericMethod : DeclSpace
1814         {
1815                 FullNamedExpression return_type;
1816                 ParametersCompiled parameters;
1817
1818                 public GenericMethod (NamespaceEntry ns, DeclSpace parent, MemberName name,
1819                                       FullNamedExpression return_type, ParametersCompiled parameters)
1820                         : base (ns, parent, name, null)
1821                 {
1822                         this.return_type = return_type;
1823                         this.parameters = parameters;
1824                 }
1825
1826                 public override TypeContainer CurrentTypeDefinition {
1827                         get {
1828                                 return Parent.CurrentTypeDefinition;
1829                         }
1830                 }
1831
1832                 public override TypeParameter[] CurrentTypeParameters {
1833                         get {
1834                                 return base.type_params;
1835                         }
1836                 }
1837
1838                 public override TypeBuilder DefineType ()
1839                 {
1840                         throw new Exception ();
1841                 }
1842
1843                 public override bool Define ()
1844                 {
1845                         for (int i = 0; i < TypeParameters.Length; i++)
1846                                 if (!TypeParameters [i].Resolve (this))
1847                                         return false;
1848
1849                         return true;
1850                 }
1851
1852                 /// <summary>
1853                 ///   Define and resolve the type parameters.
1854                 ///   We're called from Method.Define().
1855                 /// </summary>
1856                 public bool Define (MethodOrOperator m)
1857                 {
1858                         TypeParameterName[] names = MemberName.TypeArguments.GetDeclarations ();
1859                         string[] snames = new string [names.Length];
1860                         for (int i = 0; i < names.Length; i++) {
1861                                 string type_argument_name = names[i].Name;
1862                                 int idx = parameters.GetParameterIndexByName (type_argument_name);
1863                                 if (idx >= 0) {
1864                                         Block b = m.Block;
1865                                         if (b == null)
1866                                                 b = new Block (null);
1867
1868                                         b.Error_AlreadyDeclaredTypeParameter (Report, parameters [i].Location,
1869                                                 type_argument_name, "method parameter");
1870                                 }
1871                                 
1872                                 snames[i] = type_argument_name;
1873                         }
1874
1875                         GenericTypeParameterBuilder[] gen_params = m.MethodBuilder.DefineGenericParameters (snames);
1876                         for (int i = 0; i < TypeParameters.Length; i++)
1877                                 TypeParameters [i].Define (gen_params [i]);
1878
1879                         if (!Define ())
1880                                 return false;
1881
1882                         for (int i = 0; i < TypeParameters.Length; i++) {
1883                                 if (!TypeParameters [i].ResolveType (this))
1884                                         return false;
1885                         }
1886
1887                         return true;
1888                 }
1889
1890                 /// <summary>
1891                 ///   We're called from MethodData.Define() after creating the MethodBuilder.
1892                 /// </summary>
1893                 public bool DefineType (IMemberContext ec, MethodBuilder mb,
1894                                         MethodInfo implementing, bool is_override)
1895                 {
1896                         for (int i = 0; i < TypeParameters.Length; i++)
1897                                 if (!TypeParameters [i].DefineType (
1898                                             ec, mb, implementing, is_override))
1899                                         return false;
1900
1901                         bool ok = parameters.Resolve (ec);
1902
1903                         if ((return_type != null) && (return_type.ResolveAsTypeTerminal (ec, false) == null))
1904                                 ok = false;
1905
1906                         return ok;
1907                 }
1908
1909                 public void EmitAttributes ()
1910                 {
1911                         for (int i = 0; i < TypeParameters.Length; i++)
1912                                 TypeParameters [i].Emit ();
1913
1914                         if (OptAttributes != null)
1915                                 OptAttributes.Emit ();
1916                 }
1917
1918                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
1919                                                         MemberFilter filter, object criteria)
1920                 {
1921                         throw new Exception ();
1922                 }
1923
1924                 public override string GetSignatureForError ()
1925                 {
1926                         return base.GetSignatureForError () + parameters.GetSignatureForError ();
1927                 }
1928
1929                 public override MemberCache MemberCache {
1930                         get {
1931                                 return null;
1932                         }
1933                 }
1934
1935                 public override AttributeTargets AttributeTargets {
1936                         get {
1937                                 return AttributeTargets.Method | AttributeTargets.ReturnValue;
1938                         }
1939                 }
1940
1941                 public override string DocCommentHeader {
1942                         get { return "M:"; }
1943                 }
1944
1945                 public new void VerifyClsCompliance ()
1946                 {
1947                         foreach (TypeParameter tp in TypeParameters) {
1948                                 if (tp.Constraints == null)
1949                                         continue;
1950
1951                                 tp.Constraints.VerifyClsCompliance (Report);
1952                         }
1953                 }
1954         }
1955
1956         public partial class TypeManager
1957         {
1958                 static public Type activator_type;
1959         
1960                 public static TypeContainer LookupGenericTypeContainer (Type t)
1961                 {
1962                         t = DropGenericTypeArguments (t);
1963                         return LookupTypeContainer (t);
1964                 }
1965
1966                 public static Variance GetTypeParameterVariance (Type type)
1967                 {
1968                         TypeParameter tparam = LookupTypeParameter (type);
1969                         if (tparam != null)
1970                                 return tparam.Variance;
1971
1972                         switch (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) {
1973                         case GenericParameterAttributes.Covariant:
1974                                 return Variance.Covariant;
1975                         case GenericParameterAttributes.Contravariant:
1976                                 return Variance.Contravariant;
1977                         default:
1978                                 return Variance.None;
1979                         }
1980                 }
1981
1982                 public static Variance CheckTypeVariance (Type t, Variance expected, IMemberContext member)
1983                 {
1984                         TypeParameter tp = LookupTypeParameter (t);
1985                         if (tp != null) {
1986                                 Variance v = tp.Variance;
1987                                 if (expected == Variance.None && v != expected ||
1988                                         expected == Variance.Covariant && v == Variance.Contravariant ||
1989                                         expected == Variance.Contravariant && v == Variance.Covariant)
1990                                         tp.ErrorInvalidVariance (member, expected);
1991
1992                                 return expected;
1993                         }
1994
1995                         if (t.IsGenericType) {
1996                                 Type[] targs_definition = GetTypeArguments (DropGenericTypeArguments (t));
1997                                 Type[] targs = GetTypeArguments (t);
1998                                 for (int i = 0; i < targs_definition.Length; ++i) {
1999                                         Variance v = GetTypeParameterVariance (targs_definition[i]);
2000                                         CheckTypeVariance (targs[i], (Variance) ((int)v * (int)expected), member);
2001                                 }
2002
2003                                 return expected;
2004                         }
2005
2006                         if (t.IsArray)
2007                                 return CheckTypeVariance (GetElementType (t), expected, member);
2008
2009                         return Variance.None;
2010                 }
2011
2012                 public static bool IsVariantOf (Type type1, Type type2)
2013                 {
2014                         if (!type1.IsGenericType || !type2.IsGenericType)
2015                                 return false;
2016
2017                         Type generic_target_type = DropGenericTypeArguments (type2);
2018                         if (DropGenericTypeArguments (type1) != generic_target_type)
2019                                 return false;
2020
2021                         Type[] t1 = GetTypeArguments (type1);
2022                         Type[] t2 = GetTypeArguments (type2);
2023                         Type[] targs_definition = GetTypeArguments (generic_target_type);
2024                         for (int i = 0; i < targs_definition.Length; ++i) {
2025                                 Variance v = GetTypeParameterVariance (targs_definition [i]);
2026                                 if (v == Variance.None) {
2027                                         if (t1[i] == t2[i])
2028                                                 continue;
2029                                         return false;
2030                                 }
2031
2032                                 if (v == Variance.Covariant) {
2033                                         if (!Convert.ImplicitReferenceConversionExists (new EmptyExpression (t1 [i]), t2 [i]))
2034                                                 return false;
2035                                 } else if (!Convert.ImplicitReferenceConversionExists (new EmptyExpression (t2[i]), t1[i])) {
2036                                         return false;
2037                                 }
2038                         }
2039
2040                         return true;
2041                 }
2042
2043                 /// <summary>
2044                 ///   Check whether `a' and `b' may become equal generic types.
2045                 ///   The algorithm to do that is a little bit complicated.
2046                 /// </summary>
2047                 public static bool MayBecomeEqualGenericTypes (Type a, Type b, Type[] class_inferred,
2048                                                                Type[] method_inferred)
2049                 {
2050                         if (a.IsGenericParameter) {
2051                                 //
2052                                 // If a is an array of a's type, they may never
2053                                 // become equal.
2054                                 //
2055                                 while (b.IsArray) {
2056                                         b = GetElementType (b);
2057                                         if (a.Equals (b))
2058                                                 return false;
2059                                 }
2060
2061                                 //
2062                                 // If b is a generic parameter or an actual type,
2063                                 // they may become equal:
2064                                 //
2065                                 //    class X<T,U> : I<T>, I<U>
2066                                 //    class X<T> : I<T>, I<float>
2067                                 // 
2068                                 if (b.IsGenericParameter || !b.IsGenericType) {
2069                                         int pos = a.GenericParameterPosition;
2070                                         Type[] args = a.DeclaringMethod != null ? method_inferred : class_inferred;
2071                                         if (args [pos] == null) {
2072                                                 args [pos] = b;
2073                                                 return true;
2074                                         }
2075
2076                                         return args [pos] == a;
2077                                 }
2078
2079                                 //
2080                                 // We're now comparing a type parameter with a
2081                                 // generic instance.  They may become equal unless
2082                                 // the type parameter appears anywhere in the
2083                                 // generic instance:
2084                                 //
2085                                 //    class X<T,U> : I<T>, I<X<U>>
2086                                 //        -> error because you could instanciate it as
2087                                 //           X<X<int>,int>
2088                                 //
2089                                 //    class X<T> : I<T>, I<X<T>> -> ok
2090                                 //
2091
2092                                 Type[] bargs = GetTypeArguments (b);
2093                                 for (int i = 0; i < bargs.Length; i++) {
2094                                         if (a.Equals (bargs [i]))
2095                                                 return false;
2096                                 }
2097
2098                                 return true;
2099                         }
2100
2101                         if (b.IsGenericParameter)
2102                                 return MayBecomeEqualGenericTypes (b, a, class_inferred, method_inferred);
2103
2104                         //
2105                         // At this point, neither a nor b are a type parameter.
2106                         //
2107                         // If one of them is a generic instance, let
2108                         // MayBecomeEqualGenericInstances() compare them (if the
2109                         // other one is not a generic instance, they can never
2110                         // become equal).
2111                         //
2112
2113                         if (a.IsGenericType || b.IsGenericType)
2114                                 return MayBecomeEqualGenericInstances (a, b, class_inferred, method_inferred);
2115
2116                         //
2117                         // If both of them are arrays.
2118                         //
2119
2120                         if (a.IsArray && b.IsArray) {
2121                                 if (a.GetArrayRank () != b.GetArrayRank ())
2122                                         return false;
2123                         
2124                                 a = GetElementType (a);
2125                                 b = GetElementType (b);
2126
2127                                 return MayBecomeEqualGenericTypes (a, b, class_inferred, method_inferred);
2128                         }
2129
2130                         //
2131                         // Ok, two ordinary types.
2132                         //
2133
2134                         return a.Equals (b);
2135                 }
2136
2137                 //
2138                 // Checks whether two generic instances may become equal for some
2139                 // particular instantiation (26.3.1).
2140                 //
2141                 public static bool MayBecomeEqualGenericInstances (Type a, Type b,
2142                                                                    Type[] class_inferred,
2143                                                                    Type[] method_inferred)
2144                 {
2145                         if (!a.IsGenericType || !b.IsGenericType)
2146                                 return false;
2147                         if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
2148                                 return false;
2149
2150                         return MayBecomeEqualGenericInstances (
2151                                 GetTypeArguments (a), GetTypeArguments (b), class_inferred, method_inferred);
2152                 }
2153
2154                 public static bool MayBecomeEqualGenericInstances (Type[] aargs, Type[] bargs,
2155                                                                    Type[] class_inferred,
2156                                                                    Type[] method_inferred)
2157                 {
2158                         if (aargs.Length != bargs.Length)
2159                                 return false;
2160
2161                         for (int i = 0; i < aargs.Length; i++) {
2162                                 if (!MayBecomeEqualGenericTypes (aargs [i], bargs [i], class_inferred, method_inferred))
2163                                         return false;
2164                         }
2165
2166                         return true;
2167                 }
2168
2169                 /// <summary>
2170                 ///   Type inference.  Try to infer the type arguments from `method',
2171                 ///   which is invoked with the arguments `arguments'.  This is used
2172                 ///   when resolving an Invocation or a DelegateInvocation and the user
2173                 ///   did not explicitly specify type arguments.
2174                 /// </summary>
2175                 public static int InferTypeArguments (ResolveContext ec, Arguments arguments, ref MethodBase method)
2176                 {
2177                         ATypeInference ti = ATypeInference.CreateInstance (arguments);
2178                         Type[] i_args = ti.InferMethodArguments (ec, method);
2179                         if (i_args == null)
2180                                 return ti.InferenceScore;
2181
2182                         if (i_args.Length == 0)
2183                                 return 0;
2184
2185                         method = ((MethodInfo) method).MakeGenericMethod (i_args);
2186                         return 0;
2187                 }
2188
2189 /*
2190                 public static bool InferTypeArguments (ResolveContext ec, AParametersCollection param, ref MethodBase method)
2191                 {
2192                         if (!TypeManager.IsGenericMethod (method))
2193                                 return true;
2194
2195                         ATypeInference ti = ATypeInference.CreateInstance (DelegateCreation.CreateDelegateMethodArguments (param, Location.Null));
2196                         Type[] i_args = ti.InferDelegateArguments (ec, method);
2197                         if (i_args == null)
2198                                 return false;
2199
2200                         method = ((MethodInfo) method).MakeGenericMethod (i_args);
2201                         return true;
2202                 }
2203 */
2204         }
2205
2206         abstract class ATypeInference
2207         {
2208                 protected readonly Arguments arguments;
2209                 protected readonly int arg_count;
2210
2211                 protected ATypeInference (Arguments arguments)
2212                 {
2213                         this.arguments = arguments;
2214                         if (arguments != null)
2215                                 arg_count = arguments.Count;
2216                 }
2217
2218                 public static ATypeInference CreateInstance (Arguments arguments)
2219                 {
2220                         return new TypeInference (arguments);
2221                 }
2222
2223                 public virtual int InferenceScore {
2224                         get {
2225                                 return int.MaxValue;
2226                         }
2227                 }
2228
2229                 public abstract Type[] InferMethodArguments (ResolveContext ec, MethodBase method);
2230 //              public abstract Type[] InferDelegateArguments (ResolveContext ec, MethodBase method);
2231         }
2232
2233         //
2234         // Implements C# type inference
2235         //
2236         class TypeInference : ATypeInference
2237         {
2238                 //
2239                 // Tracks successful rate of type inference
2240                 //
2241                 int score = int.MaxValue;
2242
2243                 public TypeInference (Arguments arguments)
2244                         : base (arguments)
2245                 {
2246                 }
2247
2248                 public override int InferenceScore {
2249                         get {
2250                                 return score;
2251                         }
2252                 }
2253
2254 /*
2255                 public override Type[] InferDelegateArguments (ResolveContext ec, MethodBase method)
2256                 {
2257                         AParametersCollection pd = TypeManager.GetParameterData (method);
2258                         if (arg_count != pd.Count)
2259                                 return null;
2260
2261                         Type[] d_gargs = method.GetGenericArguments ();
2262                         TypeInferenceContext context = new TypeInferenceContext (d_gargs);
2263
2264                         // A lower-bound inference is made from each argument type Uj of D
2265                         // to the corresponding parameter type Tj of M
2266                         for (int i = 0; i < arg_count; ++i) {
2267                                 Type t = pd.Types [i];
2268                                 if (!t.IsGenericParameter)
2269                                         continue;
2270
2271                                 context.LowerBoundInference (arguments [i].Expr.Type, t);
2272                         }
2273
2274                         if (!context.FixAllTypes (ec))
2275                                 return null;
2276
2277                         return context.InferredTypeArguments;
2278                 }
2279 */
2280                 public override Type[] InferMethodArguments (ResolveContext ec, MethodBase method)
2281                 {
2282                         Type[] method_generic_args = method.GetGenericArguments ();
2283                         TypeInferenceContext context = new TypeInferenceContext (method_generic_args);
2284                         if (!context.UnfixedVariableExists)
2285                                 return Type.EmptyTypes;
2286
2287                         AParametersCollection pd = TypeManager.GetParameterData (method);
2288                         if (!InferInPhases (ec, context, pd))
2289                                 return null;
2290
2291                         return context.InferredTypeArguments;
2292                 }
2293
2294                 //
2295                 // Implements method type arguments inference
2296                 //
2297                 bool InferInPhases (ResolveContext ec, TypeInferenceContext tic, AParametersCollection methodParameters)
2298                 {
2299                         int params_arguments_start;
2300                         if (methodParameters.HasParams) {
2301                                 params_arguments_start = methodParameters.Count - 1;
2302                         } else {
2303                                 params_arguments_start = arg_count;
2304                         }
2305
2306                         Type [] ptypes = methodParameters.Types;
2307                         
2308                         //
2309                         // The first inference phase
2310                         //
2311                         Type method_parameter = null;
2312                         for (int i = 0; i < arg_count; i++) {
2313                                 Argument a = arguments [i];
2314                                 if (a == null)
2315                                         continue;
2316                                 
2317                                 if (i < params_arguments_start) {
2318                                         method_parameter = methodParameters.Types [i];
2319                                 } else if (i == params_arguments_start) {
2320                                         if (arg_count == params_arguments_start + 1 && TypeManager.HasElementType (a.Type))
2321                                                 method_parameter = methodParameters.Types [params_arguments_start];
2322                                         else
2323                                                 method_parameter = TypeManager.GetElementType (methodParameters.Types [params_arguments_start]);
2324
2325                                         ptypes = (Type[]) ptypes.Clone ();
2326                                         ptypes [i] = method_parameter;
2327                                 }
2328
2329                                 //
2330                                 // When a lambda expression, an anonymous method
2331                                 // is used an explicit argument type inference takes a place
2332                                 //
2333                                 AnonymousMethodExpression am = a.Expr as AnonymousMethodExpression;
2334                                 if (am != null) {
2335                                         if (am.ExplicitTypeInference (ec, tic, method_parameter))
2336                                                 --score; 
2337                                         continue;
2338                                 }
2339
2340                                 if (a.IsByRef) {
2341                                         score -= tic.ExactInference (a.Type, method_parameter);
2342                                         continue;
2343                                 }
2344
2345                                 if (a.Expr.Type == TypeManager.null_type)
2346                                         continue;
2347
2348                                 if (TypeManager.IsValueType (method_parameter)) {
2349                                         score -= tic.LowerBoundInference (a.Type, method_parameter);
2350                                         continue;
2351                                 }
2352
2353                                 //
2354                                 // Otherwise an output type inference is made
2355                                 //
2356                                 score -= tic.OutputTypeInference (ec, a.Expr, method_parameter);
2357                         }
2358
2359                         //
2360                         // Part of the second phase but because it happens only once
2361                         // we don't need to call it in cycle
2362                         //
2363                         bool fixed_any = false;
2364                         if (!tic.FixIndependentTypeArguments (ec, ptypes, ref fixed_any))
2365                                 return false;
2366
2367                         return DoSecondPhase (ec, tic, ptypes, !fixed_any);
2368                 }
2369
2370                 bool DoSecondPhase (ResolveContext ec, TypeInferenceContext tic, Type[] methodParameters, bool fixDependent)
2371                 {
2372                         bool fixed_any = false;
2373                         if (fixDependent && !tic.FixDependentTypes (ec, ref fixed_any))
2374                                 return false;
2375
2376                         // If no further unfixed type variables exist, type inference succeeds
2377                         if (!tic.UnfixedVariableExists)
2378                                 return true;
2379
2380                         if (!fixed_any && fixDependent)
2381                                 return false;
2382                         
2383                         // For all arguments where the corresponding argument output types
2384                         // contain unfixed type variables but the input types do not,
2385                         // an output type inference is made
2386                         for (int i = 0; i < arg_count; i++) {
2387                                 
2388                                 // Align params arguments
2389                                 Type t_i = methodParameters [i >= methodParameters.Length ? methodParameters.Length - 1: i];
2390                                 
2391                                 if (!TypeManager.IsDelegateType (t_i)) {
2392                                         if (TypeManager.DropGenericTypeArguments (t_i) != TypeManager.expression_type)
2393                                                 continue;
2394
2395                                         t_i = t_i.GetGenericArguments () [0];
2396                                 }
2397
2398                                 MethodInfo mi = Delegate.GetInvokeMethod (ec.Compiler, t_i, t_i);
2399                                 Type rtype = mi.ReturnType;
2400
2401 #if MS_COMPATIBLE
2402                                 // Blablabla, because reflection does not work with dynamic types
2403                                 Type[] g_args = t_i.GetGenericArguments ();
2404                                 rtype = g_args[rtype.GenericParameterPosition];
2405 #endif
2406
2407                                 if (tic.IsReturnTypeNonDependent (ec, mi, rtype))
2408                                         score -= tic.OutputTypeInference (ec, arguments [i].Expr, t_i);
2409                         }
2410
2411
2412                         return DoSecondPhase (ec, tic, methodParameters, true);
2413                 }
2414         }
2415
2416         public class TypeInferenceContext
2417         {
2418                 enum BoundKind
2419                 {
2420                         Exact   = 0,
2421                         Lower   = 1,
2422                         Upper   = 2
2423                 }
2424
2425                 class BoundInfo
2426                 {
2427                         public readonly Type Type;
2428                         public readonly BoundKind Kind;
2429
2430                         public BoundInfo (Type type, BoundKind kind)
2431                         {
2432                                 this.Type = type;
2433                                 this.Kind = kind;
2434                         }
2435                         
2436                         public override int GetHashCode ()
2437                         {
2438                                 return Type.GetHashCode ();
2439                         }
2440
2441                         public override bool Equals (object obj)
2442                         {
2443                                 BoundInfo a = (BoundInfo) obj;
2444                                 return Type == a.Type && Kind == a.Kind;
2445                         }
2446                 }
2447
2448                 readonly Type[] unfixed_types;
2449                 readonly Type[] fixed_types;
2450                 readonly ArrayList[] bounds;
2451                 bool failed;
2452                 
2453                 public TypeInferenceContext (Type[] typeArguments)
2454                 {
2455                         if (typeArguments.Length == 0)
2456                                 throw new ArgumentException ("Empty generic arguments");
2457
2458                         fixed_types = new Type [typeArguments.Length];
2459                         for (int i = 0; i < typeArguments.Length; ++i) {
2460                                 if (typeArguments [i].IsGenericParameter) {
2461                                         if (bounds == null) {
2462                                                 bounds = new ArrayList [typeArguments.Length];
2463                                                 unfixed_types = new Type [typeArguments.Length];
2464                                         }
2465                                         unfixed_types [i] = typeArguments [i];
2466                                 } else {
2467                                         fixed_types [i] = typeArguments [i];
2468                                 }
2469                         }
2470                 }
2471
2472                 // 
2473                 // Used together with AddCommonTypeBound fo implement
2474                 // 7.4.2.13 Finding the best common type of a set of expressions
2475                 //
2476                 public TypeInferenceContext ()
2477                 {
2478                         fixed_types = new Type [1];
2479                         unfixed_types = new Type [1];
2480                         unfixed_types[0] = InternalType.Arglist; // it can be any internal type
2481                         bounds = new ArrayList [1];
2482                 }
2483
2484                 public Type[] InferredTypeArguments {
2485                         get {
2486                                 return fixed_types;
2487                         }
2488                 }
2489
2490                 public void AddCommonTypeBound (Type type)
2491                 {
2492                         AddToBounds (new BoundInfo (type, BoundKind.Lower), 0);
2493                 }
2494
2495                 void AddToBounds (BoundInfo bound, int index)
2496                 {
2497                         //
2498                         // Some types cannot be used as type arguments
2499                         //
2500                         if (bound.Type == TypeManager.void_type || bound.Type.IsPointer)
2501                                 return;
2502
2503                         ArrayList a = bounds [index];
2504                         if (a == null) {
2505                                 a = new ArrayList ();
2506                                 bounds [index] = a;
2507                         } else {
2508                                 if (a.Contains (bound))
2509                                         return;
2510                         }
2511
2512                         //
2513                         // SPEC: does not cover type inference using constraints
2514                         //
2515                         //if (TypeManager.IsGenericParameter (t)) {
2516                         //    GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
2517                         //    if (constraints != null) {
2518                         //        //if (constraints.EffectiveBaseClass != null)
2519                         //        //    t = constraints.EffectiveBaseClass;
2520                         //    }
2521                         //}
2522                         a.Add (bound);
2523                 }
2524                 
2525                 bool AllTypesAreFixed (Type[] types)
2526                 {
2527                         foreach (Type t in types) {
2528                                 if (t.IsGenericParameter) {
2529                                         if (!IsFixed (t))
2530                                                 return false;
2531                                         continue;
2532                                 }
2533
2534                                 if (t.IsGenericType)
2535                                         return AllTypesAreFixed (t.GetGenericArguments ());
2536                         }
2537                         
2538                         return true;
2539                 }               
2540
2541                 //
2542                 // 26.3.3.8 Exact Inference
2543                 //
2544                 public int ExactInference (Type u, Type v)
2545                 {
2546                         // If V is an array type
2547                         if (v.IsArray) {
2548                                 if (!u.IsArray)
2549                                         return 0;
2550
2551                                 if (u.GetArrayRank () != v.GetArrayRank ())
2552                                         return 0;
2553
2554                                 return ExactInference (TypeManager.GetElementType (u), TypeManager.GetElementType (v));
2555                         }
2556
2557                         // If V is constructed type and U is constructed type
2558                         if (v.IsGenericType && !v.IsGenericTypeDefinition) {
2559                                 if (!u.IsGenericType)
2560                                         return 0;
2561
2562                                 Type [] ga_u = u.GetGenericArguments ();
2563                                 Type [] ga_v = v.GetGenericArguments ();
2564                                 if (ga_u.Length != ga_v.Length)
2565                                         return 0;
2566
2567                                 int score = 0;
2568                                 for (int i = 0; i < ga_u.Length; ++i)
2569                                         score += ExactInference (ga_u [i], ga_v [i]);
2570
2571                                 return score > 0 ? 1 : 0;
2572                         }
2573
2574                         // If V is one of the unfixed type arguments
2575                         int pos = IsUnfixed (v);
2576                         if (pos == -1)
2577                                 return 0;
2578
2579                         AddToBounds (new BoundInfo (u, BoundKind.Exact), pos);
2580                         return 1;
2581                 }
2582
2583                 public bool FixAllTypes (ResolveContext ec)
2584                 {
2585                         for (int i = 0; i < unfixed_types.Length; ++i) {
2586                                 if (!FixType (ec, i))
2587                                         return false;
2588                         }
2589                         return true;
2590                 }
2591
2592                 //
2593                 // All unfixed type variables Xi are fixed for which all of the following hold:
2594                 // a, There is at least one type variable Xj that depends on Xi
2595                 // b, Xi has a non-empty set of bounds
2596                 // 
2597                 public bool FixDependentTypes (ResolveContext ec, ref bool fixed_any)
2598                 {
2599                         for (int i = 0; i < unfixed_types.Length; ++i) {
2600                                 if (unfixed_types[i] == null)
2601                                         continue;
2602
2603                                 if (bounds[i] == null)
2604                                         continue;
2605
2606                                 if (!FixType (ec, i))
2607                                         return false;
2608                                 
2609                                 fixed_any = true;
2610                         }
2611
2612                         return true;
2613                 }
2614
2615                 //
2616                 // All unfixed type variables Xi which depend on no Xj are fixed
2617                 //
2618                 public bool FixIndependentTypeArguments (ResolveContext ec, Type[] methodParameters, ref bool fixed_any)
2619                 {
2620                         ArrayList types_to_fix = new ArrayList (unfixed_types);
2621                         for (int i = 0; i < methodParameters.Length; ++i) {
2622                                 Type t = methodParameters[i];
2623
2624                                 if (!TypeManager.IsDelegateType (t)) {
2625                                         if (TypeManager.DropGenericTypeArguments (t) != TypeManager.expression_type)
2626                                                 continue;
2627
2628                                         t = t.GetGenericArguments () [0];
2629                                 }
2630
2631                                 if (t.IsGenericParameter)
2632                                         continue;
2633
2634                                 MethodInfo invoke = Delegate.GetInvokeMethod (ec.Compiler, t, t);
2635                                 Type rtype = invoke.ReturnType;
2636                                 if (!rtype.IsGenericParameter && !rtype.IsGenericType)
2637                                         continue;
2638
2639 #if MS_COMPATIBLE
2640                                 // Blablabla, because reflection does not work with dynamic types
2641                                 if (rtype.IsGenericParameter) {
2642                                         Type [] g_args = t.GetGenericArguments ();
2643                                         rtype = g_args [rtype.GenericParameterPosition];
2644                                 }
2645 #endif
2646                                 // Remove dependent types, they cannot be fixed yet
2647                                 RemoveDependentTypes (types_to_fix, rtype);
2648                         }
2649
2650                         foreach (Type t in types_to_fix) {
2651                                 if (t == null)
2652                                         continue;
2653
2654                                 int idx = IsUnfixed (t);
2655                                 if (idx >= 0 && !FixType (ec, idx)) {
2656                                         return false;
2657                                 }
2658                         }
2659
2660                         fixed_any = types_to_fix.Count > 0;
2661                         return true;
2662                 }
2663
2664                 //
2665                 // 26.3.3.10 Fixing
2666                 //
2667                 public bool FixType (ResolveContext ec, int i)
2668                 {
2669                         // It's already fixed
2670                         if (unfixed_types[i] == null)
2671                                 throw new InternalErrorException ("Type argument has been already fixed");
2672
2673                         if (failed)
2674                                 return false;
2675
2676                         ArrayList candidates = (ArrayList)bounds [i];
2677                         if (candidates == null)
2678                                 return false;
2679
2680                         if (candidates.Count == 1) {
2681                                 unfixed_types[i] = null;
2682                                 Type t = ((BoundInfo) candidates[0]).Type;
2683                                 if (t == TypeManager.null_type)
2684                                         return false;
2685
2686                                 fixed_types [i] = t;
2687                                 return true;
2688                         }
2689
2690                         //
2691                         // Determines a unique type from which there is
2692                         // a standard implicit conversion to all the other
2693                         // candidate types.
2694                         //
2695                         Type best_candidate = null;
2696                         int cii;
2697                         int candidates_count = candidates.Count;
2698                         for (int ci = 0; ci < candidates_count; ++ci) {
2699                                 BoundInfo bound = (BoundInfo)candidates [ci];
2700                                 for (cii = 0; cii < candidates_count; ++cii) {
2701                                         if (cii == ci)
2702                                                 continue;
2703
2704                                         BoundInfo cbound = (BoundInfo) candidates[cii];
2705                                         
2706                                         // Same type parameters with different bounds
2707                                         if (cbound.Type == bound.Type) {
2708                                                 if (bound.Kind != BoundKind.Exact)
2709                                                         bound = cbound;
2710
2711                                                 continue;
2712                                         }
2713
2714                                         if (bound.Kind == BoundKind.Exact || cbound.Kind == BoundKind.Exact) {
2715                                                 if (cbound.Kind != BoundKind.Exact) {
2716                                                         if (!Convert.ImplicitConversionExists (ec, new TypeExpression (cbound.Type, Location.Null), bound.Type)) {
2717                                                                 break;
2718                                                         }
2719
2720                                                         continue;
2721                                                 }
2722                                                 
2723                                                 if (bound.Kind != BoundKind.Exact) {
2724                                                         if (!Convert.ImplicitConversionExists (ec, new TypeExpression (bound.Type, Location.Null), cbound.Type)) {
2725                                                                 break;
2726                                                         }
2727
2728                                                         bound = cbound;
2729                                                         continue;
2730                                                 }
2731                                                 
2732                                                 break;
2733                                         }
2734
2735                                         if (bound.Kind == BoundKind.Lower) {
2736                                                 if (!Convert.ImplicitConversionExists (ec, new TypeExpression (cbound.Type, Location.Null), bound.Type)) {
2737                                                         break;
2738                                                 }
2739                                         } else {
2740                                                 if (!Convert.ImplicitConversionExists (ec, new TypeExpression (bound.Type, Location.Null), cbound.Type)) {
2741                                                         break;
2742                                                 }
2743                                         }
2744                                 }
2745
2746                                 if (cii != candidates_count)
2747                                         continue;
2748
2749                                 if (best_candidate != null && best_candidate != bound.Type)
2750                                         return false;
2751
2752                                 best_candidate = bound.Type;
2753                         }
2754
2755                         if (best_candidate == null)
2756                                 return false;
2757
2758                         unfixed_types[i] = null;
2759                         fixed_types[i] = best_candidate;
2760                         return true;
2761                 }
2762                 
2763                 //
2764                 // Uses inferred types to inflate delegate type argument
2765                 //
2766                 public Type InflateGenericArgument (Type parameter)
2767                 {
2768                         if (parameter.IsGenericParameter) {
2769                                 //
2770                                 // Inflate method generic argument (MVAR) only
2771                                 //
2772                                 if (parameter.DeclaringMethod == null)
2773                                         return parameter;
2774
2775                                 return fixed_types [parameter.GenericParameterPosition];
2776                         }
2777
2778                         if (parameter.IsGenericType) {
2779                                 Type [] parameter_targs = parameter.GetGenericArguments ();
2780                                 for (int ii = 0; ii < parameter_targs.Length; ++ii) {
2781                                         parameter_targs [ii] = InflateGenericArgument (parameter_targs [ii]);
2782                                 }
2783                                 return parameter.GetGenericTypeDefinition ().MakeGenericType (parameter_targs);
2784                         }
2785
2786                         return parameter;
2787                 }
2788                 
2789                 //
2790                 // Tests whether all delegate input arguments are fixed and generic output type
2791                 // requires output type inference 
2792                 //
2793                 public bool IsReturnTypeNonDependent (ResolveContext ec, MethodInfo invoke, Type returnType)
2794                 {
2795                         if (returnType.IsGenericParameter) {
2796                                 if (IsFixed (returnType))
2797                                     return false;
2798                         } else if (returnType.IsGenericType) {
2799                                 if (TypeManager.IsDelegateType (returnType)) {
2800                                         invoke = Delegate.GetInvokeMethod (ec.Compiler, returnType, returnType);
2801                                         return IsReturnTypeNonDependent (ec, invoke, invoke.ReturnType);
2802                                 }
2803                                         
2804                                 Type[] g_args = returnType.GetGenericArguments ();
2805                                 
2806                                 // At least one unfixed return type has to exist 
2807                                 if (AllTypesAreFixed (g_args))
2808                                         return false;
2809                         } else {
2810                                 return false;
2811                         }
2812
2813                         // All generic input arguments have to be fixed
2814                         AParametersCollection d_parameters = TypeManager.GetParameterData (invoke);
2815                         return AllTypesAreFixed (d_parameters.Types);
2816                 }
2817                 
2818                 bool IsFixed (Type type)
2819                 {
2820                         return IsUnfixed (type) == -1;
2821                 }               
2822
2823                 int IsUnfixed (Type type)
2824                 {
2825                         if (!type.IsGenericParameter)
2826                                 return -1;
2827
2828                         //return unfixed_types[type.GenericParameterPosition] != null;
2829                         for (int i = 0; i < unfixed_types.Length; ++i) {
2830                                 if (unfixed_types [i] == type)
2831                                         return i;
2832                         }
2833
2834                         return -1;
2835                 }
2836
2837                 //
2838                 // 26.3.3.9 Lower-bound Inference
2839                 //
2840                 public int LowerBoundInference (Type u, Type v)
2841                 {
2842                         return LowerBoundInference (u, v, false);
2843                 }
2844
2845                 //
2846                 // Lower-bound (false) or Upper-bound (true) inference based on inversed argument
2847                 //
2848                 int LowerBoundInference (Type u, Type v, bool inversed)
2849                 {
2850                         // If V is one of the unfixed type arguments
2851                         int pos = IsUnfixed (v);
2852                         if (pos != -1) {
2853                                 AddToBounds (new BoundInfo (u, inversed ? BoundKind.Upper : BoundKind.Lower), pos);
2854                                 return 1;
2855                         }                       
2856
2857                         // If U is an array type
2858                         if (u.IsArray) {
2859                                 int u_dim = u.GetArrayRank ();
2860                                 Type v_i;
2861                                 Type u_i = TypeManager.GetElementType (u);
2862
2863                                 if (v.IsArray) {
2864                                         if (u_dim != v.GetArrayRank ())
2865                                                 return 0;
2866
2867                                         v_i = TypeManager.GetElementType (v);
2868
2869                                         if (TypeManager.IsValueType (u_i))
2870                                                 return ExactInference (u_i, v_i);
2871
2872                                         return LowerBoundInference (u_i, v_i, inversed);
2873                                 }
2874
2875                                 if (u_dim != 1)
2876                                         return 0;
2877
2878                                 if (v.IsGenericType) {
2879                                         Type g_v = v.GetGenericTypeDefinition ();
2880                                         if ((g_v != TypeManager.generic_ilist_type) && (g_v != TypeManager.generic_icollection_type) &&
2881                                                 (g_v != TypeManager.generic_ienumerable_type))
2882                                                 return 0;
2883
2884                                         v_i = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (v) [0]);
2885                                         if (TypeManager.IsValueType (u_i))
2886                                                 return ExactInference (u_i, v_i);
2887
2888                                         return LowerBoundInference (u_i, v_i);
2889                                 }
2890                         } else if (v.IsGenericType && !v.IsGenericTypeDefinition) {
2891                                 //
2892                                 // if V is a constructed type C<V1..Vk> and there is a unique type C<U1..Uk>
2893                                 // such that U is identical to, inherits from (directly or indirectly),
2894                                 // or implements (directly or indirectly) C<U1..Uk>
2895                                 //
2896                                 ArrayList u_candidates = new ArrayList ();
2897                                 if (u.IsGenericType)
2898                                         u_candidates.Add (u);
2899
2900                                 for (Type t = u.BaseType; t != null; t = t.BaseType) {
2901                                         if (t.IsGenericType && !t.IsGenericTypeDefinition)
2902                                                 u_candidates.Add (t);
2903                                 }
2904
2905                                 // TODO: Implement GetGenericInterfaces only and remove
2906                                 // the if from foreach
2907                                 u_candidates.AddRange (TypeManager.GetInterfaces (u));
2908
2909                                 Type open_v = v.GetGenericTypeDefinition ();
2910                                 Type [] unique_candidate_targs = null;
2911                                 Type [] ga_v = v.GetGenericArguments ();                        
2912                                 foreach (Type u_candidate in u_candidates) {
2913                                         if (!u_candidate.IsGenericType || u_candidate.IsGenericTypeDefinition)
2914                                                 continue;
2915
2916                                         if (TypeManager.DropGenericTypeArguments (u_candidate) != open_v)
2917                                                 continue;
2918
2919                                         //
2920                                         // The unique set of types U1..Uk means that if we have an interface I<T>,
2921                                         // class U : I<int>, I<long> then no type inference is made when inferring
2922                                         // type I<T> by applying type U because T could be int or long
2923                                         //
2924                                         if (unique_candidate_targs != null) {
2925                                                 Type[] second_unique_candidate_targs = u_candidate.GetGenericArguments ();
2926                                                 if (TypeManager.IsEqual (unique_candidate_targs, second_unique_candidate_targs)) {
2927                                                         unique_candidate_targs = second_unique_candidate_targs;
2928                                                         continue;
2929                                                 }
2930
2931                                                 //
2932                                                 // This should always cause type inference failure
2933                                                 //
2934                                                 failed = true;
2935                                                 return 1;
2936                                         }
2937
2938                                         unique_candidate_targs = u_candidate.GetGenericArguments ();
2939                                 }
2940
2941                                 if (unique_candidate_targs != null) {
2942                                         Type[] ga_open_v = open_v.GetGenericArguments ();
2943                                         int score = 0;
2944                                         for (int i = 0; i < unique_candidate_targs.Length; ++i) {
2945                                                 Variance variance = TypeManager.GetTypeParameterVariance (ga_open_v [i]);
2946
2947                                                 Type u_i = unique_candidate_targs [i];
2948                                                 if (variance == Variance.None || TypeManager.IsValueType (u_i)) {
2949                                                         if (ExactInference (u_i, ga_v [i]) == 0)
2950                                                                 ++score;
2951                                                 } else {
2952                                                         bool upper_bound = (variance == Variance.Contravariant && !inversed) ||
2953                                                                 (variance == Variance.Covariant && inversed);
2954
2955                                                         if (LowerBoundInference (u_i, ga_v [i], upper_bound) == 0)
2956                                                                 ++score;
2957                                                 }
2958                                         }
2959                                         return score;
2960                                 }
2961                         }
2962
2963                         return 0;
2964                 }
2965
2966                 //
2967                 // 26.3.3.6 Output Type Inference
2968                 //
2969                 public int OutputTypeInference (ResolveContext ec, Expression e, Type t)
2970                 {
2971                         // If e is a lambda or anonymous method with inferred return type
2972                         AnonymousMethodExpression ame = e as AnonymousMethodExpression;
2973                         if (ame != null) {
2974                                 Type rt = ame.InferReturnType (ec, this, t);
2975                                 MethodInfo invoke = Delegate.GetInvokeMethod (ec.Compiler, t, t);
2976
2977                                 if (rt == null) {
2978                                         AParametersCollection pd = TypeManager.GetParameterData (invoke);
2979                                         return ame.Parameters.Count == pd.Count ? 1 : 0;
2980                                 }
2981
2982                                 Type rtype = invoke.ReturnType;
2983 #if MS_COMPATIBLE
2984                                 // Blablabla, because reflection does not work with dynamic types
2985                                 Type [] g_args = t.GetGenericArguments ();
2986                                 rtype = g_args [rtype.GenericParameterPosition];
2987 #endif
2988                                 return LowerBoundInference (rt, rtype) + 1;
2989                         }
2990
2991                         //
2992                         // if E is a method group and T is a delegate type or expression tree type
2993                         // return type Tb with parameter types T1..Tk and return type Tb, and overload
2994                         // resolution of E with the types T1..Tk yields a single method with return type U,
2995                         // then a lower-bound inference is made from U for Tb.
2996                         //
2997                         if (e is MethodGroupExpr) {
2998                                 // TODO: Or expression tree
2999                                 if (!TypeManager.IsDelegateType (t))
3000                                         return 0;
3001
3002                                 MethodInfo invoke = Delegate.GetInvokeMethod (ec.Compiler, t, t);
3003                                 Type rtype = invoke.ReturnType;
3004 #if MS_COMPATIBLE
3005                                 // Blablabla, because reflection does not work with dynamic types
3006                                 Type [] g_args = t.GetGenericArguments ();
3007                                 rtype = g_args [rtype.GenericParameterPosition];
3008 #endif
3009
3010                                 if (!TypeManager.IsGenericType (rtype))
3011                                         return 0;
3012
3013                                 MethodGroupExpr mg = (MethodGroupExpr) e;
3014                                 Arguments args = DelegateCreation.CreateDelegateMethodArguments (TypeManager.GetParameterData (invoke), e.Location);
3015                                 mg = mg.OverloadResolve (ec, ref args, true, e.Location);
3016                                 if (mg == null)
3017                                         return 0;
3018
3019                                 // TODO: What should happen when return type is of generic type ?
3020                                 throw new NotImplementedException ();
3021 //                              return LowerBoundInference (null, rtype) + 1;
3022                         }
3023
3024                         //
3025                         // if e is an expression with type U, then
3026                         // a lower-bound inference is made from U for T
3027                         //
3028                         return LowerBoundInference (e.Type, t) * 2;
3029                 }
3030
3031                 void RemoveDependentTypes (ArrayList types, Type returnType)
3032                 {
3033                         int idx = IsUnfixed (returnType);
3034                         if (idx >= 0) {
3035                                 types [idx] = null;
3036                                 return;
3037                         }
3038
3039                         if (returnType.IsGenericType) {
3040                                 foreach (Type t in returnType.GetGenericArguments ()) {
3041                                         RemoveDependentTypes (types, t);
3042                                 }
3043                         }
3044                 }
3045
3046                 public bool UnfixedVariableExists {
3047                         get {
3048                                 if (unfixed_types == null)
3049                                         return false;
3050
3051                                 foreach (Type ut in unfixed_types)
3052                                         if (ut != null)
3053                                                 return true;
3054                                 return false;
3055                         }
3056                 }
3057         }
3058 }