Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Parser/mcs/generic.cs @ 15888

Last change on this file since 15888 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 92.4 KB
Line 
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// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13//
14
15using System;
16using System.Collections.Generic;
17using System.Text;
18using System.Linq;
19
20#if STATIC
21using MetaType = IKVM.Reflection.Type;
22using IKVM.Reflection;
23using IKVM.Reflection.Emit;
24#else
25using MetaType = System.Type;
26using System.Reflection;
27using System.Reflection.Emit;
28#endif
29
30namespace Mono.CSharp {
31  public class VarianceDecl
32  {
33    public VarianceDecl (Variance variance, Location loc)
34    {
35      this.Variance = variance;
36      this.Location = loc;
37    }
38
39    public Variance Variance { get; private set; }
40    public Location Location { get; private set; }
41
42    public static Variance CheckTypeVariance (TypeSpec t, Variance expected, IMemberContext member)
43    {
44      var tp = t as TypeParameterSpec;
45      if (tp != null) {
46        var v = tp.Variance;
47        if (expected == Variance.None && v != expected ||
48          expected == Variance.Covariant && v == Variance.Contravariant ||
49          expected == Variance.Contravariant && v == Variance.Covariant) {
50          ((TypeParameter) tp.MemberDefinition).ErrorInvalidVariance (member, expected);
51        }
52
53        return expected;
54      }
55
56      if (t.TypeArguments.Length > 0) {
57        var targs_definition = t.MemberDefinition.TypeParameters;
58        TypeSpec[] targs = TypeManager.GetTypeArguments (t);
59        for (int i = 0; i < targs.Length; ++i) {
60          var v = targs_definition[i].Variance;
61          CheckTypeVariance (targs[i], (Variance) ((int) v * (int) expected), member);
62        }
63
64        return expected;
65      }
66
67      var ac = t as ArrayContainer;
68      if (ac != null)
69        return CheckTypeVariance (ac.Element, expected, member);
70
71      return Variance.None;
72    }
73  }
74
75  public enum Variance
76  {
77    //
78    // Don't add or modify internal values, they are used as -/+ calculation signs
79    //
80    None      = 0,
81    Covariant   = 1,
82    Contravariant = -1
83  }
84
85  [Flags]
86  public enum SpecialConstraint
87  {
88    None    = 0,
89    Constructor = 1 << 2,
90    Class   = 1 << 3,
91    Struct    = 1 << 4
92  }
93
94  public class SpecialContraintExpr : FullNamedExpression
95  {
96    public SpecialContraintExpr (SpecialConstraint constraint, Location loc)
97    {
98      this.loc = loc;
99      this.Constraint = constraint;
100    }
101
102    public SpecialConstraint Constraint { get; private set; }
103
104    protected override Expression DoResolve (ResolveContext rc)
105    {
106      throw new NotImplementedException ();
107    }
108
109    public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
110    {
111      throw new NotImplementedException ();
112    }
113  }
114
115  //
116  // A set of parsed constraints for a type parameter
117  //
118  public class Constraints
119  {
120    readonly SimpleMemberName tparam;
121    readonly List<FullNamedExpression> constraints;
122    readonly Location loc;
123    bool resolved;
124    bool resolving;
125   
126    public IEnumerable<FullNamedExpression> ConstraintExpressions {
127      get {
128        return constraints;
129      }
130    }
131
132    public Constraints (SimpleMemberName tparam, List<FullNamedExpression> constraints, Location loc)
133    {
134      this.tparam = tparam;
135      this.constraints = constraints;
136      this.loc = loc;
137    }
138
139    #region Properties
140
141    public List<FullNamedExpression> TypeExpressions {
142      get {
143        return constraints;
144      }
145    }
146
147    public Location Location {
148      get {
149        return loc;
150      }
151    }
152
153    public SimpleMemberName TypeParameter {
154      get {
155        return tparam;
156      }
157    }
158
159    #endregion
160
161    public static bool CheckConflictingInheritedConstraint (TypeParameterSpec spec, TypeSpec bb, IMemberContext context, Location loc)
162    {
163      if (spec.HasSpecialClass && bb.IsStruct) {
164        context.Module.Compiler.Report.Error (455, loc,
165          "Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
166          spec.Name, "class", bb.GetSignatureForError ());
167
168        return false;
169      }
170
171      return CheckConflictingInheritedConstraint (spec, spec.BaseType, bb, context, loc);
172    }
173
174    static bool CheckConflictingInheritedConstraint (TypeParameterSpec spec, TypeSpec ba, TypeSpec bb, IMemberContext context, Location loc)
175    {
176      if (ba == bb)
177        return true;
178
179      if (TypeSpec.IsBaseClass (ba, bb, false) || TypeSpec.IsBaseClass (bb, ba, false))
180        return true;
181
182      Error_ConflictingConstraints (context, spec, ba, bb, loc);
183      return false;
184    }
185
186    public static void Error_ConflictingConstraints (IMemberContext context, TypeParameterSpec tp, TypeSpec ba, TypeSpec bb, Location loc)
187    {
188      context.Module.Compiler.Report.Error (455, loc,
189        "Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
190        tp.Name, ba.GetSignatureForError (), bb.GetSignatureForError ());
191    }
192
193    public void CheckGenericConstraints (IMemberContext context, bool obsoleteCheck)
194    {
195      foreach (var c in constraints) {
196        if (c == null)
197          continue;
198
199        var t = c.Type;
200        if (t == null)
201          continue;
202
203        if (obsoleteCheck) {
204          ObsoleteAttribute obsolete_attr = t.GetAttributeObsolete ();
205          if (obsolete_attr != null)
206            AttributeTester.Report_ObsoleteMessage (obsolete_attr, t.GetSignatureForError (), c.Location, context.Module.Compiler.Report);
207        }
208
209        ConstraintChecker.Check (context, t, c.Location);
210      }
211    }
212
213    //
214    // Resolve the constraints types with only possible early checks, return
215    // value `false' is reserved for recursive failure
216    //
217    public bool Resolve (IMemberContext context, TypeParameter tp)
218    {
219      if (resolved)
220        return true;
221
222      if (resolving)
223        return false;
224
225      resolving = true;
226      var spec = tp.Type;
227      List<TypeParameterSpec> tparam_types = null;
228      bool iface_found = false;
229
230      spec.BaseType = context.Module.Compiler.BuiltinTypes.Object;
231
232      for (int i = 0; i < constraints.Count; ++i) {
233        var constraint = constraints[i];
234
235        if (constraint is SpecialContraintExpr) {
236          spec.SpecialConstraint |= ((SpecialContraintExpr) constraint).Constraint;
237          if (spec.HasSpecialStruct)
238            spec.BaseType = context.Module.Compiler.BuiltinTypes.ValueType;
239
240          // Set to null as it does not have a type
241          constraints[i] = null;
242          continue;
243        }
244
245        var type = constraint.ResolveAsType (context);
246        if (type == null)
247          continue;
248
249        if (type.Arity > 0 && ((InflatedTypeSpec) type).HasDynamicArgument ()) {
250          context.Module.Compiler.Report.Error (1968, constraint.Location,
251            "A constraint cannot be the dynamic type `{0}'", type.GetSignatureForError ());
252          continue;
253        }
254
255        if (!context.CurrentMemberDefinition.IsAccessibleAs (type)) {
256          context.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
257          context.Module.Compiler.Report.Error (703, loc,
258            "Inconsistent accessibility: constraint type `{0}' is less accessible than `{1}'",
259            type.GetSignatureForError (), context.GetSignatureForError ());
260        }
261
262        if (type.IsInterface) {
263          if (!spec.AddInterface (type)) {
264            context.Module.Compiler.Report.Error (405, constraint.Location,
265              "Duplicate constraint `{0}' for type parameter `{1}'", type.GetSignatureForError (), tparam.Value);
266          }
267
268          iface_found = true;
269          continue;
270        }
271         
272        var constraint_tp = type as TypeParameterSpec;
273        if (constraint_tp != null) {
274          if (tparam_types == null) {
275            tparam_types = new List<TypeParameterSpec> (2);
276          } else if (tparam_types.Contains (constraint_tp)) {
277            context.Module.Compiler.Report.Error (405, constraint.Location,
278              "Duplicate constraint `{0}' for type parameter `{1}'", type.GetSignatureForError (), tparam.Value);
279            continue;
280          }
281
282          //
283          // Checks whether each generic method parameter constraint type
284          // is valid with respect to T
285          //
286          if (tp.IsMethodTypeParameter) {
287            VarianceDecl.CheckTypeVariance (type, Variance.Contravariant, context);
288          }
289
290          var tp_def = constraint_tp.MemberDefinition as TypeParameter;
291          if (tp_def != null && !tp_def.ResolveConstraints (context)) {
292            context.Module.Compiler.Report.Error (454, constraint.Location,
293              "Circular constraint dependency involving `{0}' and `{1}'",
294              constraint_tp.GetSignatureForError (), tp.GetSignatureForError ());
295            continue;
296          }
297
298          //
299          // Checks whether there are no conflicts between type parameter constraints
300          //
301          // class Foo<T, U>
302          //      where T : A
303          //      where U : B, T
304          //
305          // A and B are not convertible and only 1 class constraint is allowed
306          //
307          if (constraint_tp.HasTypeConstraint) {
308            if (spec.HasTypeConstraint || spec.HasSpecialStruct) {
309              if (!CheckConflictingInheritedConstraint (spec, constraint_tp.BaseType, context, constraint.Location))
310                continue;
311            } else {
312              for (int ii = 0; ii < tparam_types.Count; ++ii) {
313                if (!tparam_types[ii].HasTypeConstraint)
314                  continue;
315
316                if (!CheckConflictingInheritedConstraint (spec, tparam_types[ii].BaseType, constraint_tp.BaseType, context, constraint.Location))
317                  break;
318              }
319            }
320          }
321
322          if (constraint_tp.TypeArguments != null) {
323            var eb = constraint_tp.GetEffectiveBase ();
324            if (eb != null && !CheckConflictingInheritedConstraint (spec, eb, spec.BaseType, context, constraint.Location))
325              break;
326          }
327
328          if (constraint_tp.HasSpecialStruct) {
329            context.Module.Compiler.Report.Error (456, constraint.Location,
330              "Type parameter `{0}' has the `struct' constraint, so it cannot be used as a constraint for `{1}'",
331              constraint_tp.GetSignatureForError (), tp.GetSignatureForError ());
332            continue;
333          }
334
335          tparam_types.Add (constraint_tp);
336          continue;
337        }
338
339        if (iface_found || spec.HasTypeConstraint) {
340          context.Module.Compiler.Report.Error (406, constraint.Location,
341            "The class type constraint `{0}' must be listed before any other constraints. Consider moving type constraint to the beginning of the constraint list",
342            type.GetSignatureForError ());
343        }
344
345        if (spec.HasSpecialStruct || spec.HasSpecialClass) {
346          context.Module.Compiler.Report.Error (450, constraint.Location,
347            "`{0}': cannot specify both a constraint class and the `class' or `struct' constraint",
348            type.GetSignatureForError ());
349        }
350
351        switch (type.BuiltinType) {
352        case BuiltinTypeSpec.Type.Array:
353        case BuiltinTypeSpec.Type.Delegate:
354        case BuiltinTypeSpec.Type.MulticastDelegate:
355        case BuiltinTypeSpec.Type.Enum:
356        case BuiltinTypeSpec.Type.ValueType:
357        case BuiltinTypeSpec.Type.Object:
358          context.Module.Compiler.Report.Error (702, constraint.Location,
359            "A constraint cannot be special class `{0}'", type.GetSignatureForError ());
360          continue;
361        case BuiltinTypeSpec.Type.Dynamic:
362          context.Module.Compiler.Report.Error (1967, constraint.Location,
363            "A constraint cannot be the dynamic type");
364          continue;
365        }
366
367        if (type.IsSealed || !type.IsClass) {
368          context.Module.Compiler.Report.Error (701, loc,
369            "`{0}' is not a valid constraint. A constraint must be an interface, a non-sealed class or a type parameter",
370            type.GetSignatureForError ());
371          continue;
372        }
373
374        if (type.IsStatic) {
375          context.Module.Compiler.Report.Error (717, constraint.Location,
376            "`{0}' is not a valid constraint. Static classes cannot be used as constraints",
377            type.GetSignatureForError ());
378        }
379
380        spec.BaseType = type;
381      }
382
383      if (tparam_types != null)
384        spec.TypeArguments = tparam_types.ToArray ();
385
386      resolving = false;
387      resolved = true;
388      return true;
389    }
390
391    public void VerifyClsCompliance (Report report)
392    {
393      foreach (var c in constraints)
394      {
395        if (c == null)
396          continue;
397
398        if (!c.Type.IsCLSCompliant ()) {
399          report.SymbolRelatedToPreviousError (c.Type);
400          report.Warning (3024, 1, loc, "Constraint type `{0}' is not CLS-compliant",
401            c.Type.GetSignatureForError ());
402        }
403      }
404    }
405  }
406
407  //
408  // A type parameter for a generic type or generic method definition
409  //
410  public class TypeParameter : MemberCore, ITypeDefinition
411  {
412    static readonly string[] attribute_target = { "type parameter" };
413   
414    Constraints constraints;
415    GenericTypeParameterBuilder builder;
416    readonly TypeParameterSpec spec;
417
418    public TypeParameter (int index, MemberName name, Constraints constraints, Attributes attrs, Variance Variance)
419      : base (null, name, attrs)
420    {
421      this.constraints = constraints;
422      this.spec = new TypeParameterSpec (null, index, this, SpecialConstraint.None, Variance, null);
423    }
424
425    //
426    // Used by parser
427    //
428    public TypeParameter (MemberName name, Attributes attrs, VarianceDecl variance)
429      : base (null, name, attrs)
430    {
431      var var = variance == null ? Variance.None : variance.Variance;
432      this.spec = new TypeParameterSpec (null, -1, this, SpecialConstraint.None, var, null);
433      this.VarianceDecl = variance;
434    }
435   
436    public TypeParameter (TypeParameterSpec spec, TypeSpec parentSpec, MemberName name, Attributes attrs)
437      : base (null, name, attrs)
438    {
439      this.spec = new TypeParameterSpec (parentSpec, spec.DeclaredPosition, spec.MemberDefinition, spec.SpecialConstraint, spec.Variance, null) {
440        BaseType = spec.BaseType,
441        InterfacesDefined = spec.InterfacesDefined,
442        TypeArguments = spec.TypeArguments
443      };
444    }
445   
446    #region Properties
447
448    public override AttributeTargets AttributeTargets {
449      get {
450        return AttributeTargets.GenericParameter;
451      }
452    }
453
454    public Constraints Constraints {
455      get {
456        return constraints;
457      }
458      set {
459        constraints = value;
460      }
461    }
462
463    public IAssemblyDefinition DeclaringAssembly {
464      get {
465        return Module.DeclaringAssembly;
466      }
467    }
468
469    public override string DocCommentHeader {
470      get {
471        throw new InvalidOperationException (
472          "Unexpected attempt to get doc comment from " + this.GetType ());
473      }
474    }
475
476    bool ITypeDefinition.IsComImport {
477      get {
478        return false;
479      }
480    }
481
482    bool ITypeDefinition.IsPartial {
483      get {
484        return false;
485      }
486    }
487
488    public bool IsMethodTypeParameter {
489      get {
490        return spec.IsMethodOwned;
491      }
492    }
493
494    bool ITypeDefinition.IsTypeForwarder {
495      get {
496        return false;
497      }
498    }
499
500    bool ITypeDefinition.IsCyclicTypeForwarder {
501      get {
502        return false;
503      }
504    }
505
506    public string Name {
507      get {
508        return MemberName.Name;
509      }
510    }
511
512    public string Namespace {
513      get {
514        return null;
515      }
516    }
517
518    public TypeParameterSpec Type {
519      get {
520        return spec;
521      }
522    }
523
524    public int TypeParametersCount {
525      get {
526        return 0;
527      }
528    }
529
530    public TypeParameterSpec[] TypeParameters {
531      get {
532        return null;
533      }
534    }
535
536    public override string[] ValidAttributeTargets {
537      get {
538        return attribute_target;
539      }
540    }
541
542    public Variance Variance {
543      get {
544        return spec.Variance;
545      }
546    }
547
548    public VarianceDecl VarianceDecl { get; private set; }
549
550    #endregion
551
552    //
553    // This is called for each part of a partial generic type definition.
554    //
555    // If partial type parameters constraints are not null and we don't
556    // already have constraints they become our constraints. If we already
557    // have constraints, we must check that they're same.
558    //
559    public bool AddPartialConstraints (TypeDefinition part, TypeParameter tp)
560    {
561      if (builder == null)
562        throw new InvalidOperationException ();
563
564      var new_constraints = tp.constraints;
565      if (new_constraints == null)
566        return true;
567
568      // TODO: could create spec only
569      //tp.Define (null, -1, part.Definition);
570      tp.spec.DeclaringType = part.Definition;
571      if (!tp.ResolveConstraints (part))
572        return false;
573
574      if (constraints != null)
575        return spec.HasSameConstraintsDefinition (tp.Type);
576
577      // Copy constraint from resolved part to partial container
578      spec.SpecialConstraint = tp.spec.SpecialConstraint;
579      spec.InterfacesDefined = tp.spec.InterfacesDefined;
580      spec.TypeArguments = tp.spec.TypeArguments;
581      spec.BaseType = tp.spec.BaseType;
582     
583      return true;
584    }
585
586    public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
587    {
588      builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
589    }
590
591    public void CheckGenericConstraints (bool obsoleteCheck)
592    {
593      if (constraints != null)
594        constraints.CheckGenericConstraints (this, obsoleteCheck);
595    }
596
597    public TypeParameter CreateHoistedCopy (TypeSpec declaringSpec)
598    {
599      return new TypeParameter (spec, declaringSpec, MemberName, null);
600    }
601
602    public override bool Define ()
603    {
604      return true;
605    }
606
607    //
608    // This is the first method which is called during the resolving
609    // process; we're called immediately after creating the type parameters
610    // with SRE (by calling `DefineGenericParameters()' on the TypeBuilder /
611    // MethodBuilder).
612    //
613    public void Create (TypeSpec declaringType, TypeContainer parent)
614    {
615      if (builder != null)
616        throw new InternalErrorException ();
617
618      // Needed to get compiler reference
619      this.Parent = parent;
620      spec.DeclaringType = declaringType;
621    }
622
623    public void Define (GenericTypeParameterBuilder type)
624    {
625      this.builder = type;
626      spec.SetMetaInfo (type);
627    }
628
629    public void Define (TypeParameter tp)
630    {
631      builder = tp.builder;
632    }
633
634    public void EmitConstraints (GenericTypeParameterBuilder builder)
635    {
636      var attr = GenericParameterAttributes.None;
637      if (spec.Variance == Variance.Contravariant)
638        attr |= GenericParameterAttributes.Contravariant;
639      else if (spec.Variance == Variance.Covariant)
640        attr |= GenericParameterAttributes.Covariant;
641
642      if (spec.HasSpecialClass)
643        attr |= GenericParameterAttributes.ReferenceTypeConstraint;
644      else if (spec.HasSpecialStruct)
645        attr |= GenericParameterAttributes.NotNullableValueTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint;
646
647      if (spec.HasSpecialConstructor)
648        attr |= GenericParameterAttributes.DefaultConstructorConstraint;
649
650      if (spec.BaseType.BuiltinType != BuiltinTypeSpec.Type.Object)
651        builder.SetBaseTypeConstraint (spec.BaseType.GetMetaInfo ());
652
653      if (spec.InterfacesDefined != null)
654        builder.SetInterfaceConstraints (spec.InterfacesDefined.Select (l => l.GetMetaInfo ()).ToArray ());
655
656      if (spec.TypeArguments != null) {
657        var meta_constraints = new List<MetaType> (spec.TypeArguments.Length);
658        foreach (var c in spec.TypeArguments) {
659          //
660          // Inflated type parameters can collide with special constraint types, don't
661          // emit any such type parameter.
662          //
663          if (c.BuiltinType == BuiltinTypeSpec.Type.Object || c.BuiltinType == BuiltinTypeSpec.Type.ValueType)
664            continue;
665
666          meta_constraints.Add (c.GetMetaInfo ());
667        }
668
669        builder.SetInterfaceConstraints (meta_constraints.ToArray ());
670      }
671
672      builder.SetGenericParameterAttributes (attr);
673    }
674
675    public override void Emit ()
676    {
677      EmitConstraints (builder);
678
679      if (OptAttributes != null)
680        OptAttributes.Emit ();
681
682      base.Emit ();
683    }
684
685    public void ErrorInvalidVariance (IMemberContext mc, Variance expected)
686    {
687      Report.SymbolRelatedToPreviousError (mc.CurrentMemberDefinition);
688      string input_variance = Variance == Variance.Contravariant ? "contravariant" : "covariant";
689      string gtype_variance;
690      switch (expected) {
691      case Variance.Contravariant: gtype_variance = "contravariantly"; break;
692      case Variance.Covariant: gtype_variance = "covariantly"; break;
693      default: gtype_variance = "invariantly"; break;
694      }
695
696      Delegate d = mc as Delegate;
697      string parameters = d != null ? d.Parameters.GetSignatureForError () : "";
698
699      Report.Error (1961, Location,
700        "The {2} type parameter `{0}' must be {3} valid on `{1}{4}'",
701          GetSignatureForError (), mc.GetSignatureForError (), input_variance, gtype_variance, parameters);
702    }
703
704    public TypeSpec GetAttributeCoClass ()
705    {
706      return null;
707    }
708
709    public string GetAttributeDefaultMember ()
710    {
711      throw new NotSupportedException ();
712    }
713
714    public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
715    {
716      throw new NotSupportedException ();
717    }
718
719    public override string GetSignatureForDocumentation ()
720    {
721      throw new NotImplementedException ();
722    }
723
724    public override string GetSignatureForError ()
725    {
726      return MemberName.Name;
727    }
728
729    bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
730    {
731      return spec.MemberDefinition.DeclaringAssembly == assembly;
732    }
733
734    public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
735    {
736      throw new NotSupportedException ("Not supported for compiled definition");
737    }
738
739    //
740    // Resolves all type parameter constraints
741    //
742    public bool ResolveConstraints (IMemberContext context)
743    {
744      if (constraints != null)
745        return constraints.Resolve (context, this);
746
747      if (spec.BaseType == null)
748        spec.BaseType = context.Module.Compiler.BuiltinTypes.Object;
749
750      return true;
751    }
752
753    public override bool IsClsComplianceRequired ()
754    {
755      return false;
756    }
757
758    public new void VerifyClsCompliance ()
759    {
760      if (constraints != null)
761        constraints.VerifyClsCompliance (Report);
762    }
763
764    public void WarningParentNameConflict (TypeParameter conflict)
765    {
766      conflict.Report.SymbolRelatedToPreviousError (conflict.Location, null);
767      conflict.Report.Warning (693, 3, Location,
768        "Type parameter `{0}' has the same name as the type parameter from outer type `{1}'",
769        GetSignatureForError (), conflict.CurrentType.GetSignatureForError ());
770    }
771  }
772
773  [System.Diagnostics.DebuggerDisplay ("{DisplayDebugInfo()}")]
774  public class TypeParameterSpec : TypeSpec
775  {
776    public static readonly new TypeParameterSpec[] EmptyTypes = new TypeParameterSpec[0];
777
778    Variance variance;
779    SpecialConstraint spec;
780    int tp_pos;
781    TypeSpec[] targs;
782    TypeSpec[] ifaces_defined;
783    TypeSpec effective_base;
784
785    //
786    // Creates type owned type parameter
787    //
788    public TypeParameterSpec (TypeSpec declaringType, int index, ITypeDefinition definition, SpecialConstraint spec, Variance variance, MetaType info)
789      : base (MemberKind.TypeParameter, declaringType, definition, info, Modifiers.PUBLIC)
790    {
791      this.variance = variance;
792      this.spec = spec;
793      state &= ~StateFlags.Obsolete_Undetected;
794      tp_pos = index;
795    }
796
797    //
798    // Creates method owned type parameter
799    //
800    public TypeParameterSpec (int index, ITypeDefinition definition, SpecialConstraint spec, Variance variance, MetaType info)
801      : this (null, index, definition, spec, variance, info)
802    {
803    }
804
805    #region Properties
806
807    public int DeclaredPosition {
808      get {
809        return tp_pos;
810      }
811      set {
812        tp_pos = value;
813      }
814    }
815
816    public bool HasSpecialConstructor {
817      get {
818        return (spec & SpecialConstraint.Constructor) != 0;
819      }
820    }
821
822    public bool HasSpecialClass {
823      get {
824        return (spec & SpecialConstraint.Class) != 0;
825      }
826    }
827
828    public bool HasSpecialStruct {
829      get {
830        return (spec & SpecialConstraint.Struct) != 0;
831      }
832    }
833
834    public bool HasAnyTypeConstraint {
835      get {
836        return (spec & (SpecialConstraint.Class | SpecialConstraint.Struct)) != 0 || ifaces != null || targs != null || HasTypeConstraint;
837      }
838    }
839
840    public bool HasTypeConstraint {
841      get {
842        var bt = BaseType.BuiltinType;
843        return bt != BuiltinTypeSpec.Type.Object && bt != BuiltinTypeSpec.Type.ValueType;
844      }
845    }
846
847    public override IList<TypeSpec> Interfaces {
848      get {
849        if ((state & StateFlags.InterfacesExpanded) == 0) {
850          if (ifaces != null) {
851            if (ifaces_defined == null)
852              ifaces_defined = ifaces.ToArray ();
853
854            for (int i = 0; i < ifaces_defined.Length; ++i ) {
855              var iface_type = ifaces_defined[i];
856              var td = iface_type.MemberDefinition as TypeDefinition;
857              if (td != null)
858                td.DoExpandBaseInterfaces ();
859
860              if (iface_type.Interfaces != null) {
861                for (int ii = 0; ii < iface_type.Interfaces.Count; ++ii) {
862                  var ii_iface_type = iface_type.Interfaces [ii];
863                  AddInterface (ii_iface_type);
864                }
865              }
866            }
867          } else if (ifaces_defined == null) {
868            ifaces_defined = ifaces == null ? TypeSpec.EmptyTypes : ifaces.ToArray ();
869          }
870
871          //
872          // Include all base type interfaces too, see ImportTypeBase for details
873          //
874          if (BaseType != null) {
875            var td = BaseType.MemberDefinition as TypeDefinition;
876            if (td != null)
877              td.DoExpandBaseInterfaces ();
878
879            if (BaseType.Interfaces != null) {
880              foreach (var iface in BaseType.Interfaces) {
881                AddInterface (iface);
882              }
883            }
884          }
885
886          state |= StateFlags.InterfacesExpanded;
887        }
888
889        return ifaces;
890      }
891    }
892
893    //
894    // Unexpanded interfaces list
895    //
896    public TypeSpec[] InterfacesDefined {
897      get {
898        if (ifaces_defined == null) {
899          ifaces_defined = ifaces == null ? TypeSpec.EmptyTypes : ifaces.ToArray ();
900        }
901
902        return ifaces_defined.Length == 0 ? null : ifaces_defined;
903      }
904      set {
905        ifaces_defined = value;
906        if (value != null && value.Length != 0)
907          ifaces = new List<TypeSpec> (value);
908      }
909    }
910
911    public bool IsConstrained {
912      get {
913        return spec != SpecialConstraint.None || ifaces != null || targs != null || HasTypeConstraint;
914      }
915    }
916
917    //
918    // Returns whether the type parameter is known to be a reference type
919    //
920    public new bool IsReferenceType {
921      get {
922        if ((spec & (SpecialConstraint.Class | SpecialConstraint.Struct)) != 0)
923          return (spec & SpecialConstraint.Class) != 0;
924
925        //
926        // Full check is needed (see IsValueType for details)
927        //
928        if (HasTypeConstraint && TypeSpec.IsReferenceType (BaseType))
929          return true;
930
931        if (targs != null) {
932          foreach (var ta in targs) {
933            //
934            // Secondary special constraints are ignored (I am not sure why)
935            //
936            var tp = ta as TypeParameterSpec;
937            if (tp != null && (tp.spec & (SpecialConstraint.Class | SpecialConstraint.Struct)) != 0)
938              continue;
939
940            if (TypeSpec.IsReferenceType (ta))
941              return true;
942          }
943        }
944
945        return false;
946      }
947    }
948
949    //
950    // Returns whether the type parameter is known to be a value type
951    //
952    public new bool IsValueType {
953      get {
954        //
955        // Even if structs/enums cannot be used directly as constraints
956        // they can apear as constraint type when inheriting base constraint
957        // which has dependant type parameter constraint which has been
958        // inflated using value type
959        //
960        // class A : B<int> { override void Foo<U> () {} }
961        // class B<T> { virtual void Foo<U> () where U : T {} }
962        //
963        if (HasSpecialStruct)
964          return true;
965
966        if (targs != null) {
967          foreach (var ta in targs) {
968            if (TypeSpec.IsValueType (ta))
969              return true;
970          }
971        }
972
973        return false;
974      }
975    }
976
977    public override string Name {
978      get {
979        return definition.Name;
980      }
981    }
982
983    public bool IsMethodOwned {
984      get {
985        return DeclaringType == null;
986      }
987    }
988
989    public SpecialConstraint SpecialConstraint {
990      get {
991        return spec;
992      }
993      set {
994        spec = value;
995      }
996    }
997
998    //
999    // Types used to inflate the generic type
1000    //
1001    public new TypeSpec[] TypeArguments {
1002      get {
1003        return targs;
1004      }
1005      set {
1006        targs = value;
1007      }
1008    }
1009
1010    public Variance Variance {
1011      get {
1012        return variance;
1013      }
1014    }
1015
1016    #endregion
1017
1018    public string DisplayDebugInfo ()
1019    {
1020      var s = GetSignatureForError ();
1021      return IsMethodOwned ? s + "!!" : s + "!";
1022    }
1023
1024    //
1025    // Finds effective base class. The effective base class is always a class-type
1026    //
1027    public TypeSpec GetEffectiveBase ()
1028    {
1029      if (HasSpecialStruct)
1030        return BaseType;
1031
1032      //
1033      // If T has a class-type constraint C but no type-parameter constraints, its effective base class is C
1034      //
1035      if (BaseType != null && targs == null) {
1036        //
1037        // If T has a constraint V that is a value-type, use instead the most specific base type of V that is a class-type.
1038        //
1039        // LAMESPEC: Is System.ValueType always the most specific base type in this case?
1040        //
1041        // Note: This can never happen in an explicitly given constraint, but may occur when the constraints of a generic method
1042        // are implicitly inherited by an overriding method declaration or an explicit implementation of an interface method.
1043        //
1044        return BaseType.IsStruct ? BaseType.BaseType : BaseType;
1045      }
1046
1047      if (effective_base != null)
1048        return effective_base;
1049
1050      var types = new TypeSpec [HasTypeConstraint ? targs.Length + 1 : targs.Length];
1051
1052      for (int i = 0; i < targs.Length; ++i) {
1053        var t = targs [i];
1054
1055        // Same issue as above, inherited constraints can be of struct type
1056        if (t.IsStruct) {
1057          types [i] = t.BaseType;
1058          continue;
1059        }
1060
1061        var tps = t as TypeParameterSpec;
1062        types [i] = tps != null ? tps.GetEffectiveBase () : t;
1063      }
1064
1065      if (HasTypeConstraint)
1066        types [types.Length - 1] = BaseType;
1067
1068      return effective_base = Convert.FindMostEncompassedType (types);
1069    }
1070
1071    public override string GetSignatureForDocumentation ()
1072    {
1073      var prefix = IsMethodOwned ? "``" : "`";
1074      return prefix + DeclaredPosition;
1075    }
1076
1077    public override string GetSignatureForError ()
1078    {
1079      return Name;
1080    }
1081
1082    //
1083    // Constraints have to match by definition but not position, used by
1084    // partial classes or methods
1085    //
1086    public bool HasSameConstraintsDefinition (TypeParameterSpec other)
1087    {
1088      if (spec != other.spec)
1089        return false;
1090
1091      if (BaseType != other.BaseType)
1092        return false;
1093
1094      if (!TypeSpecComparer.Override.IsSame (InterfacesDefined, other.InterfacesDefined))
1095        return false;
1096
1097      if (!TypeSpecComparer.Override.IsSame (targs, other.targs))
1098        return false;
1099
1100      return true;
1101    }
1102
1103    //
1104    // Constraints have to match by using same set of types, used by
1105    // implicit interface implementation
1106    //
1107    public bool HasSameConstraintsImplementation (TypeParameterSpec other)
1108    {
1109      if (spec != other.spec)
1110        return false;
1111
1112      //
1113      // It can be same base type or inflated type parameter
1114      //
1115      // interface I<T> { void Foo<U> where U : T; }
1116      // class A : I<int> { void Foo<X> where X : int {} }
1117      //
1118      bool found;
1119      if (!TypeSpecComparer.Override.IsEqual (BaseType, other.BaseType)) {
1120        if (other.targs == null)
1121          return false;
1122
1123        found = false;
1124        foreach (var otarg in other.targs) {
1125          if (TypeSpecComparer.Override.IsEqual (BaseType, otarg)) {
1126            found = true;
1127            break;
1128          }
1129        }
1130
1131        if (!found)
1132          return false;
1133      }
1134
1135      // Check interfaces implementation -> definition
1136      if (InterfacesDefined != null) {
1137        //
1138        // Iterate over inflated interfaces
1139        //
1140        foreach (var iface in Interfaces) {
1141          found = false;
1142          if (other.InterfacesDefined != null) {
1143            foreach (var oiface in other.Interfaces) {
1144              if (TypeSpecComparer.Override.IsEqual (iface, oiface)) {
1145                found = true;
1146                break;
1147              }
1148            }
1149          }
1150
1151          if (found)
1152            continue;
1153
1154          if (other.targs != null) {
1155            foreach (var otarg in other.targs) {
1156              if (TypeSpecComparer.Override.IsEqual (iface, otarg)) {
1157                found = true;
1158                break;
1159              }
1160            }
1161          }
1162
1163          if (!found)
1164            return false;
1165        }
1166      }
1167
1168      // Check interfaces implementation <- definition
1169      if (other.InterfacesDefined != null) {
1170        if (InterfacesDefined == null)
1171          return false;
1172
1173        //
1174        // Iterate over inflated interfaces
1175        //
1176        foreach (var oiface in other.Interfaces) {
1177          found = false;
1178          foreach (var iface in Interfaces) {
1179            if (TypeSpecComparer.Override.IsEqual (iface, oiface)) {
1180              found = true;
1181              break;
1182            }
1183          }
1184
1185          if (!found)
1186            return false;
1187        }
1188      }
1189
1190      // Check type parameters implementation -> definition
1191      if (targs != null) {
1192        if (other.targs == null)
1193          return false;
1194
1195        foreach (var targ in targs) {
1196          found = false;
1197          foreach (var otarg in other.targs) {
1198            if (TypeSpecComparer.Override.IsEqual (targ, otarg)) {
1199              found = true;
1200              break;
1201            }
1202          }
1203
1204          if (!found)
1205            return false;
1206        }
1207      }
1208
1209      // Check type parameters implementation <- definition
1210      if (other.targs != null) {
1211        foreach (var otarg in other.targs) {
1212          // Ignore inflated type arguments, were checked above
1213          if (!otarg.IsGenericParameter)
1214            continue;
1215
1216          if (targs == null)
1217            return false;
1218
1219          found = false;
1220          foreach (var targ in targs) {
1221            if (TypeSpecComparer.Override.IsEqual (targ, otarg)) {
1222              found = true;
1223              break;
1224            }
1225          }
1226
1227          if (!found)
1228            return false;
1229        }       
1230      }
1231
1232      return true;
1233    }
1234
1235    public static TypeParameterSpec[] InflateConstraints (TypeParameterInflator inflator, TypeParameterSpec[] tparams)
1236    {
1237      return InflateConstraints (tparams, l => l, inflator);
1238    }
1239
1240    public static TypeParameterSpec[] InflateConstraints<T> (TypeParameterSpec[] tparams, Func<T, TypeParameterInflator> inflatorFactory, T arg)
1241    {
1242      TypeParameterSpec[] constraints = null;
1243      TypeParameterInflator? inflator = null;
1244
1245      for (int i = 0; i < tparams.Length; ++i) {
1246        var tp = tparams[i];
1247        if (tp.HasTypeConstraint || tp.InterfacesDefined != null || tp.TypeArguments != null) {
1248          if (constraints == null) {
1249            constraints = new TypeParameterSpec[tparams.Length];
1250            Array.Copy (tparams, constraints, constraints.Length);
1251          }
1252
1253          //
1254          // Using a factory to avoid possibly expensive inflator build up
1255          //
1256          if (inflator == null)
1257            inflator = inflatorFactory (arg);
1258
1259          constraints[i] = (TypeParameterSpec) constraints[i].InflateMember (inflator.Value);
1260        }
1261      }
1262
1263      if (constraints == null)
1264        constraints = tparams;
1265
1266      return constraints;
1267    }
1268
1269    public void InflateConstraints (TypeParameterInflator inflator, TypeParameterSpec tps)
1270    {
1271      tps.BaseType = inflator.Inflate (BaseType);
1272
1273      var defined = InterfacesDefined;
1274      if (defined != null) {
1275        tps.ifaces_defined = new TypeSpec[defined.Length];
1276        for (int i = 0; i < defined.Length; ++i)
1277          tps.ifaces_defined [i] = inflator.Inflate (defined[i]);
1278      } else if (ifaces_defined == TypeSpec.EmptyTypes) {
1279        tps.ifaces_defined = TypeSpec.EmptyTypes;
1280      }
1281
1282      var ifaces = Interfaces;
1283      if (ifaces != null) {
1284        tps.ifaces = new List<TypeSpec> (ifaces.Count);
1285        for (int i = 0; i < ifaces.Count; ++i)
1286          tps.ifaces.Add (inflator.Inflate (ifaces[i]));
1287        tps.state |= StateFlags.InterfacesExpanded;
1288      }
1289
1290      if (targs != null) {
1291        tps.targs = new TypeSpec[targs.Length];
1292        for (int i = 0; i < targs.Length; ++i)
1293          tps.targs[i] = inflator.Inflate (targs[i]);
1294      }
1295    }
1296
1297    public override MemberSpec InflateMember (TypeParameterInflator inflator)
1298    {
1299      var tps = (TypeParameterSpec) MemberwiseClone ();
1300#if DEBUG
1301      tps.ID += 1000000;
1302#endif
1303
1304      InflateConstraints (inflator, tps);
1305      return tps;
1306    }
1307
1308    //
1309    // Populates type parameter members using type parameter constraints
1310    // The trick here is to be called late enough but not too late to
1311    // populate member cache with all members from other types
1312    //
1313    protected override void InitializeMemberCache (bool onlyTypes)
1314    {
1315      cache = new MemberCache ();
1316
1317      //
1318      // For a type parameter the membercache is the union of the sets of members of the types
1319      // specified as a primary constraint or secondary constraint
1320      //
1321      if (BaseType.BuiltinType != BuiltinTypeSpec.Type.Object && BaseType.BuiltinType != BuiltinTypeSpec.Type.ValueType)
1322        cache.AddBaseType (BaseType);
1323
1324      if (InterfacesDefined != null) {
1325        foreach (var iface_type in InterfacesDefined) {
1326          cache.AddInterface (iface_type);
1327        }
1328      }
1329
1330      if (targs != null) {
1331        foreach (var ta in targs) {
1332          var tps = ta as TypeParameterSpec;
1333          IList<TypeSpec> ifaces;
1334          if (tps != null) {
1335            var b_type = tps.GetEffectiveBase ();
1336            if (b_type != null && b_type.BuiltinType != BuiltinTypeSpec.Type.Object && b_type.BuiltinType != BuiltinTypeSpec.Type.ValueType)
1337              cache.AddBaseType (b_type);
1338
1339            ifaces = tps.InterfacesDefined;
1340          } else {
1341            ifaces = ta.Interfaces;
1342          }
1343
1344          if (ifaces != null) {
1345            foreach (var iface_type in ifaces) {
1346              cache.AddInterface (iface_type);
1347            }
1348          }
1349        }
1350      }
1351    }
1352
1353    public bool IsConvertibleToInterface (TypeSpec iface)
1354    {
1355      if (Interfaces != null) {
1356        foreach (var t in Interfaces) {
1357          if (t == iface)
1358            return true;
1359        }
1360      }
1361
1362      if (TypeArguments != null) {
1363        foreach (var t in TypeArguments) {
1364          var tps = t as TypeParameterSpec;
1365          if (tps != null) {
1366            if (tps.IsConvertibleToInterface (iface))
1367              return true;
1368
1369            continue;
1370          }
1371
1372          if (t.ImplementsInterface (iface, false))
1373            return true;
1374        }
1375      }
1376
1377      return false;
1378    }
1379
1380    public static bool HasAnyTypeParameterTypeConstrained (IGenericMethodDefinition md)
1381    {
1382      var tps = md.TypeParameters;
1383      for (int i = 0; i < md.TypeParametersCount; ++i) {
1384        if (tps[i].HasAnyTypeConstraint) {
1385          return true;
1386        }
1387      }
1388
1389      return false;
1390    }
1391
1392    public static bool HasAnyTypeParameterConstrained (IGenericMethodDefinition md)
1393    {
1394      var tps = md.TypeParameters;
1395      for (int i = 0; i < md.TypeParametersCount; ++i) {
1396        if (tps[i].IsConstrained) {
1397          return true;
1398        }
1399      }
1400
1401      return false;
1402    }
1403
1404    public bool HasDependencyOn (TypeSpec type)
1405    {
1406      if (TypeArguments != null) {
1407        foreach (var targ in TypeArguments) {
1408          if (TypeSpecComparer.Override.IsEqual (targ, type))
1409            return true;
1410
1411          var tps = targ as TypeParameterSpec;
1412          if (tps != null && tps.HasDependencyOn (type))
1413            return true;
1414        }
1415      }
1416
1417      return false;
1418    }
1419
1420    public override TypeSpec Mutate (TypeParameterMutator mutator)
1421    {
1422      return mutator.Mutate (this);
1423    }
1424  }
1425
1426  public struct TypeParameterInflator
1427  {
1428    readonly TypeSpec type;
1429    readonly TypeParameterSpec[] tparams;
1430    readonly TypeSpec[] targs;
1431    readonly IModuleContext context;
1432
1433    public TypeParameterInflator (TypeParameterInflator nested, TypeSpec type)
1434      : this (nested.context, type, nested.tparams, nested.targs)
1435    {
1436    }
1437
1438    public TypeParameterInflator (IModuleContext context, TypeSpec type, TypeParameterSpec[] tparams, TypeSpec[] targs)
1439    {
1440      if (tparams.Length != targs.Length)
1441        throw new ArgumentException ("Invalid arguments");
1442
1443      this.context = context;
1444      this.tparams = tparams;
1445      this.targs = targs;
1446      this.type = type;
1447    }
1448
1449    #region Properties
1450
1451    public IModuleContext Context {
1452      get {
1453        return context;
1454      }
1455    }
1456
1457    public TypeSpec TypeInstance {
1458      get {
1459        return type;
1460      }
1461    }
1462
1463    //
1464    // Type parameters to inflate
1465    //
1466    public TypeParameterSpec[] TypeParameters {
1467      get {
1468        return tparams;
1469      }
1470    }
1471
1472    #endregion
1473
1474    public TypeSpec Inflate (TypeSpec type)
1475    {
1476      var tp = type as TypeParameterSpec;
1477      if (tp != null)
1478        return Inflate (tp);
1479
1480      var ec = type as ElementTypeSpec;
1481      if (ec != null) {
1482        var et = Inflate (ec.Element);
1483        if (et != ec.Element) {
1484          var ac = ec as ArrayContainer;
1485          if (ac != null)
1486            return ArrayContainer.MakeType (context.Module, et, ac.Rank);
1487
1488          if (ec is PointerContainer)
1489            return PointerContainer.MakeType (context.Module, et);
1490
1491          throw new NotImplementedException ();
1492        }
1493
1494        return ec;
1495      }
1496
1497      if (type.Kind == MemberKind.MissingType)
1498        return type;
1499
1500      //
1501      // When inflating a nested type, inflate its parent first
1502      // in case it's using same type parameters (was inflated within the type)
1503      //
1504      TypeSpec[] targs;
1505      int i = 0;
1506      if (type.IsNested) {
1507        var parent = Inflate (type.DeclaringType);
1508
1509        //
1510        // Keep the inflated type arguments
1511        //
1512        targs = type.TypeArguments;
1513
1514        //
1515        // When inflating imported nested type used inside same declaring type, we get TypeSpec
1516        // because the import cache helps us to catch it. However, that means we have to look at
1517        // type definition to get type argument (they are in fact type parameter in this case)
1518        //
1519        if (targs.Length == 0 && type.Arity > 0)
1520          targs = type.MemberDefinition.TypeParameters;
1521
1522        //
1523        // Parent was inflated, find the same type on inflated type
1524        // to use same cache for nested types on same generic parent
1525        //
1526        type = MemberCache.FindNestedType (parent, type.Name, type.Arity);
1527
1528        //
1529        // Handle the tricky case where parent shares local type arguments
1530        // which means inflating inflated type
1531        //
1532        // class Test<T> {
1533        //    public static Nested<T> Foo () { return null; }
1534        //
1535        //    public class Nested<U> {}
1536        //  }
1537        //
1538        //  return type of Test<string>.Foo() has to be Test<string>.Nested<string>
1539        //
1540        if (targs.Length > 0) {
1541          var inflated_targs = new TypeSpec[targs.Length];
1542          for (; i < targs.Length; ++i)
1543            inflated_targs[i] = Inflate (targs[i]);
1544
1545          type = type.MakeGenericType (context, inflated_targs);
1546        }
1547
1548        return type;
1549      }
1550
1551      // Nothing to do for non-generic type
1552      if (type.Arity == 0)
1553        return type;
1554
1555      targs = new TypeSpec[type.Arity];
1556
1557      //
1558      // Inflating using outside type arguments, var v = new Foo<int> (), class Foo<T> {}
1559      //
1560      if (type is InflatedTypeSpec) {
1561        for (; i < targs.Length; ++i)
1562          targs[i] = Inflate (type.TypeArguments[i]);
1563
1564        type = type.GetDefinition ();
1565      } else {
1566        //
1567        // Inflating parent using inside type arguments, class Foo<T> { ITest<T> foo; }
1568        //
1569        var args = type.MemberDefinition.TypeParameters;
1570        foreach (var ds_tp in args)
1571          targs[i++] = Inflate (ds_tp);
1572      }
1573
1574      return type.MakeGenericType (context, targs);
1575    }
1576
1577    public TypeSpec Inflate (TypeParameterSpec tp)
1578    {
1579      for (int i = 0; i < tparams.Length; ++i)
1580        if (tparams [i] == tp)
1581          return targs[i];
1582
1583      // This can happen when inflating nested types
1584      // without type arguments specified
1585      return tp;
1586    }
1587  }
1588
1589  //
1590  // Before emitting any code we have to change all MVAR references to VAR
1591  // when the method is of generic type and has hoisted variables
1592  //
1593  public class TypeParameterMutator
1594  {
1595    readonly TypeParameters mvar;
1596    readonly TypeParameters var;
1597    readonly TypeParameterSpec[] src;
1598    Dictionary<TypeSpec, TypeSpec> mutated_typespec;
1599
1600    public TypeParameterMutator (TypeParameters mvar, TypeParameters var)
1601    {
1602      if (mvar.Count != var.Count)
1603        throw new ArgumentException ();
1604
1605      this.mvar = mvar;
1606      this.var = var;
1607    }
1608
1609    public TypeParameterMutator (TypeParameterSpec[] srcVar, TypeParameters destVar)
1610    {
1611      if (srcVar.Length != destVar.Count)
1612        throw new ArgumentException ();
1613
1614      this.src = srcVar;
1615      this.var = destVar;
1616    }
1617
1618    #region Properties
1619
1620    public TypeParameters MethodTypeParameters {
1621      get {
1622        return mvar;
1623      }
1624    }
1625
1626    #endregion
1627
1628    public static TypeSpec GetMemberDeclaringType (TypeSpec type)
1629    {
1630      if (type is InflatedTypeSpec) {
1631        if (type.DeclaringType == null)
1632          return type.GetDefinition ();
1633
1634        var parent = GetMemberDeclaringType (type.DeclaringType);
1635        type = MemberCache.GetMember<TypeSpec> (parent, type);
1636      }
1637
1638      return type;
1639    }
1640
1641    public TypeSpec Mutate (TypeSpec ts)
1642    {
1643      TypeSpec value;
1644      if (mutated_typespec != null && mutated_typespec.TryGetValue (ts, out value))
1645        return value;
1646
1647      value = ts.Mutate (this);
1648      if (mutated_typespec == null)
1649        mutated_typespec = new Dictionary<TypeSpec, TypeSpec> ();
1650
1651      mutated_typespec.Add (ts, value);
1652      return value;
1653    }
1654
1655    public TypeParameterSpec Mutate (TypeParameterSpec tp)
1656    {
1657      if (mvar != null) {
1658        for (int i = 0; i < mvar.Count; ++i) {
1659          if (mvar[i].Type == tp)
1660            return var[i].Type;
1661        }
1662      } else {
1663        for (int i = 0; i < src.Length; ++i) {
1664          if (src[i] == tp)
1665            return var[i].Type;
1666        }
1667      }
1668
1669      return tp;
1670    }
1671
1672    public TypeSpec[] Mutate (TypeSpec[] targs)
1673    {
1674      TypeSpec[] mutated = new TypeSpec[targs.Length];
1675      bool changed = false;
1676      for (int i = 0; i < targs.Length; ++i) {
1677        mutated[i] = Mutate (targs[i]);
1678        changed |= targs[i] != mutated[i];
1679      }
1680
1681      return changed ? mutated : targs;
1682    }
1683  }
1684
1685  /// <summary>
1686  ///   A TypeExpr which already resolved to a type parameter.
1687  /// </summary>
1688  public class TypeParameterExpr : TypeExpression
1689  {
1690    public TypeParameterExpr (TypeParameter type_parameter, Location loc)
1691      : base (type_parameter.Type, loc)
1692    {
1693      this.eclass = ExprClass.TypeParameter;
1694    }
1695  }
1696
1697  public class InflatedTypeSpec : TypeSpec
1698  {
1699    TypeSpec[] targs;
1700    TypeParameterSpec[] constraints;
1701    readonly TypeSpec open_type;
1702    readonly IModuleContext context;
1703
1704    public InflatedTypeSpec (IModuleContext context, TypeSpec openType, TypeSpec declaringType, TypeSpec[] targs)
1705      : base (openType.Kind, declaringType, openType.MemberDefinition, null, openType.Modifiers)
1706    {
1707      if (targs == null)
1708        throw new ArgumentNullException ("targs");
1709
1710      this.state &= ~SharedStateFlags;
1711      this.state |= (openType.state & SharedStateFlags);
1712
1713      this.context = context;
1714      this.open_type = openType;
1715      this.targs = targs;
1716
1717      foreach (var arg in targs) {
1718        if (arg.HasDynamicElement || arg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1719          state |= StateFlags.HasDynamicElement;
1720          break;
1721        }
1722      }
1723
1724      if (open_type.Kind == MemberKind.MissingType)
1725        MemberCache = MemberCache.Empty;
1726
1727      if ((open_type.Modifiers & Modifiers.COMPILER_GENERATED) != 0)
1728        state |= StateFlags.ConstraintsChecked;
1729    }
1730
1731    #region Properties
1732
1733    public override TypeSpec BaseType {
1734      get {
1735        if (cache == null || (state & StateFlags.PendingBaseTypeInflate) != 0)
1736          InitializeMemberCache (true);
1737
1738        return base.BaseType;
1739      }
1740    }
1741
1742    //
1743    // Inflated type parameters with constraints array, mapping with type arguments is based on index
1744    //
1745    public TypeParameterSpec[] Constraints {
1746      get {
1747        if (constraints == null) {
1748          constraints = TypeParameterSpec.InflateConstraints (MemberDefinition.TypeParameters, l => l.CreateLocalInflator (context), this);
1749        }
1750
1751        return constraints;
1752      }
1753    }
1754
1755    //
1756    // Used to cache expensive constraints validation on constructed types
1757    //
1758    public bool HasConstraintsChecked {
1759      get {
1760        return (state & StateFlags.ConstraintsChecked) != 0;
1761      }
1762      set {
1763        state = value ? state | StateFlags.ConstraintsChecked : state & ~StateFlags.ConstraintsChecked;
1764      }
1765    }
1766
1767    public override IList<TypeSpec> Interfaces {
1768      get {
1769        if (cache == null)
1770          InitializeMemberCache (true);
1771
1772        return base.Interfaces;
1773      }
1774    }
1775
1776    public override bool IsExpressionTreeType {
1777      get {
1778        return (open_type.state & StateFlags.InflatedExpressionType) != 0;
1779      }
1780    }
1781
1782    public override bool IsArrayGenericInterface {
1783      get {
1784        return (open_type.state & StateFlags.GenericIterateInterface) != 0;
1785      }
1786    }
1787
1788    public override bool IsGenericTask {
1789      get {
1790        return (open_type.state & StateFlags.GenericTask) != 0;
1791      }
1792    }
1793
1794    public override bool IsNullableType {
1795      get {
1796        return (open_type.state & StateFlags.InflatedNullableType) != 0;
1797      }
1798    }
1799
1800    //
1801    // Types used to inflate the generic  type
1802    //
1803    public override TypeSpec[] TypeArguments {
1804      get {
1805        return targs;
1806      }
1807    }
1808
1809    #endregion
1810
1811    public override bool AddInterface (TypeSpec iface)
1812    {
1813      var inflator = CreateLocalInflator (context);
1814      iface = inflator.Inflate (iface);
1815      if (iface == null)
1816        return false;
1817
1818      return base.AddInterface (iface);
1819    }
1820
1821    public static bool ContainsTypeParameter (TypeSpec type)
1822    {
1823      if (type.Kind == MemberKind.TypeParameter)
1824        return true;
1825
1826      var element_container = type as ElementTypeSpec;
1827      if (element_container != null)
1828        return ContainsTypeParameter (element_container.Element);
1829
1830      foreach (var t in type.TypeArguments) {
1831        if (ContainsTypeParameter (t)) {
1832          return true;
1833        }
1834      }
1835
1836      return false;
1837    }
1838
1839    public TypeParameterInflator CreateLocalInflator (IModuleContext context)
1840    {
1841      TypeParameterSpec[] tparams_full;
1842      TypeSpec[] targs_full = targs;
1843      if (IsNested) {
1844        //
1845        // Special case is needed when we are inflating an open type (nested type definition)
1846        // on inflated parent. Consider following case
1847        //
1848        // Foo<T>.Bar<U> => Foo<string>.Bar<U>
1849        //
1850        // Any later inflation of Foo<string>.Bar<U> has to also inflate T if used inside Bar<U>
1851        //
1852        List<TypeSpec> merged_targs = null;
1853        List<TypeParameterSpec> merged_tparams = null;
1854
1855        var type = DeclaringType;
1856
1857        do {
1858          if (type.TypeArguments.Length > 0) {
1859            if (merged_targs == null) {
1860              merged_targs = new List<TypeSpec> ();
1861              merged_tparams = new List<TypeParameterSpec> ();
1862              if (targs.Length > 0) {
1863                merged_targs.AddRange (targs);
1864                merged_tparams.AddRange (open_type.MemberDefinition.TypeParameters);
1865              }
1866            }
1867            merged_tparams.AddRange (type.MemberDefinition.TypeParameters);
1868            merged_targs.AddRange (type.TypeArguments);
1869          }
1870          type = type.DeclaringType;
1871        } while (type != null);
1872
1873        if (merged_targs != null) {
1874          // Type arguments are not in the right order but it should not matter in this case
1875          targs_full = merged_targs.ToArray ();
1876          tparams_full = merged_tparams.ToArray ();
1877        } else if (targs.Length == 0) {
1878          tparams_full = TypeParameterSpec.EmptyTypes;
1879        } else {
1880          tparams_full = open_type.MemberDefinition.TypeParameters;
1881        }
1882      } else if (targs.Length == 0) {
1883        tparams_full = TypeParameterSpec.EmptyTypes;
1884      } else {
1885        tparams_full = open_type.MemberDefinition.TypeParameters;
1886      }
1887
1888      return new TypeParameterInflator (context, this, tparams_full, targs_full);
1889    }
1890
1891    MetaType CreateMetaInfo ()
1892    {
1893      //
1894      // Converts nested type arguments into right order
1895      // Foo<string, bool>.Bar<int> => string, bool, int
1896      //
1897      var all = new List<MetaType> ();
1898      TypeSpec type = this;
1899      TypeSpec definition = type;
1900      do {
1901        if (type.GetDefinition().IsGeneric) {
1902          all.InsertRange (0,
1903            type.TypeArguments != TypeSpec.EmptyTypes ?
1904            type.TypeArguments.Select (l => l.GetMetaInfo ()) :
1905            type.MemberDefinition.TypeParameters.Select (l => l.GetMetaInfo ()));
1906        }
1907
1908        definition = definition.GetDefinition ();
1909        type = type.DeclaringType;
1910      } while (type != null);
1911
1912      return definition.GetMetaInfo ().MakeGenericType (all.ToArray ());
1913    }
1914
1915    public override ObsoleteAttribute GetAttributeObsolete ()
1916    {
1917      return open_type.GetAttributeObsolete ();
1918    }
1919
1920    protected override bool IsNotCLSCompliant (out bool attrValue)
1921    {
1922      if (base.IsNotCLSCompliant (out attrValue))
1923        return true;
1924
1925      foreach (var ta in TypeArguments) {
1926        if (ta.MemberDefinition.CLSAttributeValue == false)
1927          return true;
1928      }
1929
1930      return false;
1931    }
1932
1933    public override TypeSpec GetDefinition ()
1934    {
1935      return open_type;
1936    }
1937
1938    public override MetaType GetMetaInfo ()
1939    {
1940      if (info == null)
1941        info = CreateMetaInfo ();
1942
1943      return info;
1944    }
1945
1946    public override string GetSignatureForError ()
1947    {
1948      if (IsNullableType)
1949        return targs[0].GetSignatureForError () + "?";
1950
1951      return base.GetSignatureForError ();
1952    }
1953
1954    protected override string GetTypeNameSignature ()
1955    {
1956      if (targs.Length == 0 || MemberDefinition is AnonymousTypeClass)
1957        return null;
1958
1959      return "<" + TypeManager.CSharpName (targs) + ">";
1960    }
1961
1962    public bool HasDynamicArgument ()
1963    {
1964      for (int i = 0; i < targs.Length; ++i) {
1965        var item = targs[i];
1966
1967        if (item.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1968          return true;
1969
1970        if (item is InflatedTypeSpec) {
1971          if (((InflatedTypeSpec) item).HasDynamicArgument ())
1972            return true;
1973
1974          continue;
1975        }
1976
1977        if (item.IsArray) {
1978          while (item.IsArray) {
1979            item = ((ArrayContainer) item).Element;
1980          }
1981
1982          if (item.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1983            return true;
1984        }
1985      }
1986
1987      return false;
1988    }
1989
1990    protected override void InitializeMemberCache (bool onlyTypes)
1991    {
1992      if (cache == null) {
1993        var open_cache = onlyTypes ? open_type.MemberCacheTypes : open_type.MemberCache;
1994
1995        // Surprisingly, calling MemberCache on open type could meantime create cache on this type
1996        // for imported type parameter constraints referencing nested type of this declaration
1997        if (cache == null)
1998          cache = new MemberCache (open_cache);
1999      }
2000
2001      var inflator = CreateLocalInflator (context);
2002
2003      //
2004      // Two stage inflate due to possible nested types recursive
2005      // references
2006      //
2007      // class A<T> {
2008      //    B b;
2009      //    class B {
2010      //      T Value;
2011      //    }
2012      // }
2013      //
2014      // When resolving type of `b' members of `B' cannot be
2015      // inflated because are not yet available in membercache
2016      //
2017      if ((state & StateFlags.PendingMemberCacheMembers) == 0) {
2018        open_type.MemberCacheTypes.InflateTypes (cache, inflator);
2019
2020        //
2021        // Inflate any implemented interfaces
2022        //
2023        if (open_type.Interfaces != null) {
2024          ifaces = new List<TypeSpec> (open_type.Interfaces.Count);
2025          foreach (var iface in open_type.Interfaces) {
2026            var iface_inflated = inflator.Inflate (iface);
2027            if (iface_inflated == null)
2028              continue;
2029
2030            base.AddInterface (iface_inflated);
2031          }
2032        }
2033
2034        //
2035        // Handles the tricky case of recursive nested base generic type
2036        //
2037        // class A<T> : Base<A<T>.Nested> {
2038        //    class Nested {}
2039        // }
2040        //
2041        // When inflating A<T>. base type is not yet known, secondary
2042        // inflation is required (not common case) once base scope
2043        // is known
2044        //
2045        if (open_type.BaseType == null) {
2046          if (IsClass)
2047            state |= StateFlags.PendingBaseTypeInflate;
2048        } else {
2049          BaseType = inflator.Inflate (open_type.BaseType);
2050        }
2051      } else if ((state & StateFlags.PendingBaseTypeInflate) != 0) {
2052        //
2053        // It can happen when resolving base type without being defined
2054        // which is not allowed to happen and will always lead to an error
2055        //
2056        // class B { class N {} }
2057        // class A<T> : A<B.N> {}
2058        //
2059        if (open_type.BaseType == null)
2060          return;
2061
2062        BaseType = inflator.Inflate (open_type.BaseType);
2063        state &= ~StateFlags.PendingBaseTypeInflate;
2064      }
2065
2066      if (onlyTypes) {
2067        state |= StateFlags.PendingMemberCacheMembers;
2068        return;
2069      }
2070
2071      var tc = open_type.MemberDefinition as TypeDefinition;
2072      if (tc != null && !tc.HasMembersDefined) {
2073        //
2074        // Inflating MemberCache with undefined members
2075        //
2076        return;
2077      }
2078
2079      if ((state & StateFlags.PendingBaseTypeInflate) != 0) {
2080        BaseType = inflator.Inflate (open_type.BaseType);
2081        state &= ~StateFlags.PendingBaseTypeInflate;
2082      }
2083
2084      state &= ~StateFlags.PendingMemberCacheMembers;
2085      open_type.MemberCache.InflateMembers (cache, open_type, inflator);
2086    }
2087
2088    public override TypeSpec Mutate (TypeParameterMutator mutator)
2089    {
2090      var targs = TypeArguments;
2091      if (targs != null)
2092        targs = mutator.Mutate (targs);
2093
2094      var decl = DeclaringType;
2095      if (IsNested && DeclaringType.IsGenericOrParentIsGeneric)
2096        decl = mutator.Mutate (decl);
2097
2098      if (targs == TypeArguments && decl == DeclaringType)
2099        return this;
2100
2101      var mutated = (InflatedTypeSpec) MemberwiseClone ();
2102      if (decl != DeclaringType) {
2103        // Gets back MethodInfo in case of metaInfo was inflated
2104        //mutated.info = MemberCache.GetMember<TypeSpec> (DeclaringType.GetDefinition (), this).info;
2105
2106        mutated.declaringType = decl;
2107        mutated.state |= StateFlags.PendingMetaInflate;
2108      }
2109
2110      if (targs != null) {
2111        mutated.targs = targs;
2112        mutated.info = null;
2113      }
2114
2115      return mutated;
2116    }
2117  }
2118
2119
2120  //
2121  // Tracks the type arguments when instantiating a generic type. It's used
2122  // by both type arguments and type parameters
2123  //
2124  public class TypeArguments
2125  {
2126    List<FullNamedExpression> args;
2127    TypeSpec[] atypes;
2128
2129    public List<FullNamedExpression> Args {
2130      get { return this.args; }
2131    }
2132
2133    public TypeArguments (params FullNamedExpression[] types)
2134    {
2135      this.args = new List<FullNamedExpression> (types);
2136    }
2137
2138    public void Add (FullNamedExpression type)
2139    {
2140      args.Add (type);
2141    }
2142
2143    /// <summary>
2144    ///   We may only be used after Resolve() is called and return the fully
2145    ///   resolved types.
2146    /// </summary>
2147    // TODO: Not needed, just return type from resolve
2148    public TypeSpec[] Arguments {
2149      get {
2150        return atypes;
2151      }
2152      set {
2153        atypes = value;
2154      }
2155    }
2156
2157    public int Count {
2158      get {
2159        return args.Count;
2160      }
2161    }
2162
2163    public virtual bool IsEmpty {
2164      get {
2165        return false;
2166      }
2167    }
2168
2169    public List<FullNamedExpression> TypeExpressions {
2170      get {
2171        return this.args;
2172      }
2173    }
2174
2175    public string GetSignatureForError()
2176    {
2177      StringBuilder sb = new StringBuilder ();
2178      for (int i = 0; i < Count; ++i) {
2179        var expr = args[i];
2180        if (expr != null)
2181          sb.Append (expr.GetSignatureForError ());
2182
2183        if (i + 1 < Count)
2184          sb.Append (',');
2185      }
2186
2187      return sb.ToString ();
2188    }
2189
2190    /// <summary>
2191    ///   Resolve the type arguments.
2192    /// </summary>
2193    public virtual bool Resolve (IMemberContext ec)
2194    {
2195      if (atypes != null)
2196          return true;
2197
2198      int count = args.Count;
2199      bool ok = true;
2200
2201      atypes = new TypeSpec [count];
2202
2203      var errors = ec.Module.Compiler.Report.Errors;
2204
2205      for (int i = 0; i < count; i++){
2206        var te = args[i].ResolveAsType (ec);
2207        if (te == null) {
2208          ok = false;
2209          continue;
2210        }
2211
2212        atypes[i] = te;
2213
2214        if (te.IsStatic) {
2215          ec.Module.Compiler.Report.Error (718, args[i].Location, "`{0}': static classes cannot be used as generic arguments",
2216            te.GetSignatureForError ());
2217          ok = false;
2218        }
2219
2220        if (te.IsPointer || te.IsSpecialRuntimeType) {
2221          ec.Module.Compiler.Report.Error (306, args[i].Location,
2222            "The type `{0}' may not be used as a type argument",
2223            te.GetSignatureForError ());
2224          ok = false;
2225        }
2226      }
2227
2228      if (!ok || errors != ec.Module.Compiler.Report.Errors)
2229        atypes = null;
2230
2231      return ok;
2232    }
2233
2234    public TypeArguments Clone ()
2235    {
2236      TypeArguments copy = new TypeArguments ();
2237      foreach (var ta in args)
2238        copy.args.Add (ta);
2239
2240      return copy;
2241    }
2242  }
2243
2244  public class UnboundTypeArguments : TypeArguments
2245  {
2246    public UnboundTypeArguments (int arity)
2247      : base (new FullNamedExpression[arity])
2248    {
2249    }
2250
2251    public override bool IsEmpty {
2252      get {
2253        return true;
2254      }
2255    }
2256
2257    public override bool Resolve (IMemberContext ec)
2258    {
2259      // Nothing to be resolved
2260      return true;
2261    }
2262  }
2263
2264  public class TypeParameters
2265  {
2266    List<TypeParameter> names;
2267    TypeParameterSpec[] types;
2268
2269    public TypeParameters ()
2270    {
2271      names = new List<TypeParameter> ();
2272    }
2273
2274    public TypeParameters (int count)
2275    {
2276      names = new List<TypeParameter> (count);
2277    }
2278
2279    #region Properties
2280
2281    public int Count {
2282      get {
2283        return names.Count;
2284      }
2285    }
2286
2287    public TypeParameterSpec[] Types {
2288      get {
2289        return types;
2290      }
2291    }
2292
2293    #endregion
2294
2295    public void Add (TypeParameter tparam)
2296    {
2297      names.Add (tparam);
2298    }
2299
2300    public void Add (TypeParameters tparams)
2301    {
2302      names.AddRange (tparams.names);
2303    }
2304
2305    public void Create (TypeSpec declaringType, int parentOffset, TypeContainer parent)
2306    {
2307      types = new TypeParameterSpec[Count];
2308      for (int i = 0; i < types.Length; ++i) {
2309        var tp = names[i];
2310
2311        tp.Create (declaringType, parent);
2312        types[i] = tp.Type;
2313        types[i].DeclaredPosition = i + parentOffset;
2314
2315        if (tp.Variance != Variance.None && !(declaringType != null && (declaringType.Kind == MemberKind.Interface || declaringType.Kind == MemberKind.Delegate))) {
2316          parent.Compiler.Report.Error (1960, tp.Location, "Variant type parameters can only be used with interfaces and delegates");
2317        }
2318      }
2319    }
2320
2321    public void Define (GenericTypeParameterBuilder[] builders)
2322    {
2323      for (int i = 0; i < types.Length; ++i) {
2324        var tp = names[i];
2325        tp.Define (builders [types [i].DeclaredPosition]);
2326      }
2327    }
2328
2329    public TypeParameter this[int index] {
2330      get {
2331        return names [index];
2332      }
2333      set {
2334        names[index] = value;
2335      }
2336    }
2337
2338    public TypeParameter Find (string name)
2339    {
2340      foreach (var tp in names) {
2341        if (tp.Name == name)
2342          return tp;
2343      }
2344
2345      return null;
2346    }
2347
2348    public string[] GetAllNames ()
2349    {
2350      return names.Select (l => l.Name).ToArray ();
2351    }
2352
2353    public string GetSignatureForError ()
2354    {
2355      StringBuilder sb = new StringBuilder ();
2356      for (int i = 0; i < Count; ++i) {
2357        if (i > 0)
2358          sb.Append (',');
2359
2360        var name = names[i];
2361        if (name != null)
2362          sb.Append (name.GetSignatureForError ());
2363      }
2364
2365      return sb.ToString ();
2366    }
2367
2368
2369    public void CheckPartialConstraints (Method part)
2370    {
2371      var partTypeParameters = part.CurrentTypeParameters;
2372
2373      for (int i = 0; i < Count; i++) {
2374        var tp_a = names[i];
2375        var tp_b = partTypeParameters [i];
2376        if (tp_a.Constraints == null) {
2377          if (tp_b.Constraints == null)
2378            continue;
2379        } else if (tp_b.Constraints != null && tp_a.Type.HasSameConstraintsDefinition (tp_b.Type)) {
2380          continue;
2381        }
2382
2383        part.Compiler.Report.SymbolRelatedToPreviousError (this[i].CurrentMemberDefinition.Location, "");
2384        part.Compiler.Report.Error (761, part.Location,
2385          "Partial method declarations of `{0}' have inconsistent constraints for type parameter `{1}'",
2386          part.GetSignatureForError (), partTypeParameters[i].GetSignatureForError ());
2387      }
2388    }
2389
2390    public void UpdateConstraints (TypeDefinition part)
2391    {
2392      var partTypeParameters = part.MemberName.TypeParameters;
2393
2394      for (int i = 0; i < Count; i++) {
2395        var tp = names [i];
2396        if (tp.AddPartialConstraints (part, partTypeParameters [i]))
2397          continue;
2398
2399        part.Compiler.Report.SymbolRelatedToPreviousError (this[i].CurrentMemberDefinition);
2400        part.Compiler.Report.Error (265, part.Location,
2401          "Partial declarations of `{0}' have inconsistent constraints for type parameter `{1}'",
2402          part.GetSignatureForError (), tp.GetSignatureForError ());
2403      }
2404    }
2405
2406    public void VerifyClsCompliance ()
2407    {
2408      foreach (var tp in names) {
2409        tp.VerifyClsCompliance ();
2410      }
2411    }
2412  }
2413
2414  //
2415  // A type expression of generic type with type arguments
2416  //
2417  class GenericTypeExpr : TypeExpr
2418  {
2419    TypeArguments args;
2420    TypeSpec open_type;
2421
2422    /// <summary>
2423    ///   Instantiate the generic type `t' with the type arguments `args'.
2424    ///   Use this constructor if you already know the fully resolved
2425    ///   generic type.
2426    /// </summary>   
2427    public GenericTypeExpr (TypeSpec open_type, TypeArguments args, Location l)
2428    {
2429      this.open_type = open_type;
2430      loc = l;
2431      this.args = args;
2432    }
2433
2434    public override string GetSignatureForError ()
2435    {
2436      return type.GetSignatureForError ();
2437    }
2438
2439    public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
2440    {
2441      if (eclass != ExprClass.Unresolved)
2442        return type;
2443
2444      if (!args.Resolve (mc))
2445        return null;
2446
2447      TypeSpec[] atypes = args.Arguments;
2448      if (atypes == null)
2449        return null;
2450
2451      //
2452      // Now bind the parameters
2453      //
2454      var inflated = open_type.MakeGenericType (mc, atypes);
2455      type = inflated;
2456      eclass = ExprClass.Type;
2457
2458      //
2459      // The constraints can be checked only when full type hierarchy is known
2460      //
2461      if (!inflated.HasConstraintsChecked && mc.Module.HasTypesFullyDefined) {
2462        var constraints = inflated.Constraints;
2463        if (constraints != null) {
2464          var cc = new ConstraintChecker (mc);
2465          if (cc.CheckAll (open_type, atypes, constraints, loc)) {
2466            inflated.HasConstraintsChecked = true;
2467          }
2468        }
2469      }
2470
2471      return type;
2472    }
2473
2474    public override bool Equals (object obj)
2475    {
2476      GenericTypeExpr cobj = obj as GenericTypeExpr;
2477      if (cobj == null)
2478        return false;
2479
2480      if ((type == null) || (cobj.type == null))
2481        return false;
2482
2483      return type == cobj.type;
2484    }
2485
2486    public override int GetHashCode ()
2487    {
2488      return base.GetHashCode ();
2489    }
2490  }
2491
2492  //
2493  // Generic type with unbound type arguments, used for typeof (G<,,>)
2494  //
2495  class GenericOpenTypeExpr : TypeExpression
2496  {
2497    public GenericOpenTypeExpr (TypeSpec type, /*UnboundTypeArguments args,*/ Location loc)
2498      : base (type.GetDefinition (), loc)
2499    {
2500    }
2501  }
2502
2503  struct ConstraintChecker
2504  {
2505    IMemberContext mc;
2506    bool recursive_checks;
2507
2508    public ConstraintChecker (IMemberContext ctx)
2509    {
2510      this.mc = ctx;
2511      recursive_checks = false;
2512    }
2513
2514    //
2515    // Checks the constraints of open generic type against type
2516    // arguments. This version is used for types which could not be
2517    // checked immediatelly during construction because the type
2518    // hierarchy was not yet fully setup (before Emit phase)
2519    //
2520    public static bool Check (IMemberContext mc, TypeSpec type, Location loc)
2521    {
2522      //
2523      // Check declaring type first if there is any
2524      //
2525      if (type.DeclaringType != null && !Check (mc, type.DeclaringType, loc))
2526        return false;
2527
2528      while (type is ElementTypeSpec)
2529        type = ((ElementTypeSpec) type).Element;
2530
2531      if (type.Arity == 0)
2532        return true;
2533
2534      var gtype = type as InflatedTypeSpec;
2535      if (gtype == null)
2536        return true;
2537
2538      var constraints = gtype.Constraints;
2539      if (constraints == null)
2540        return true;
2541
2542      if (gtype.HasConstraintsChecked)
2543        return true;
2544
2545      var cc = new ConstraintChecker (mc);
2546      cc.recursive_checks = true;
2547
2548      if (cc.CheckAll (gtype.GetDefinition (), type.TypeArguments, constraints, loc)) {
2549        gtype.HasConstraintsChecked = true;
2550        return true;
2551      }
2552
2553      return false;
2554    }
2555
2556    //
2557    // Checks all type arguments againts type parameters constraints
2558    // NOTE: It can run in probing mode when `this.mc' is null
2559    //
2560    public bool CheckAll (MemberSpec context, TypeSpec[] targs, TypeParameterSpec[] tparams, Location loc)
2561    {
2562      for (int i = 0; i < tparams.Length; i++) {
2563        var targ = targs[i];
2564        if (!CheckConstraint (context, targ, tparams [i], loc))
2565          return false;
2566
2567        if (!recursive_checks)
2568          continue;
2569
2570        if (!Check (mc, targ, loc))
2571          return false;
2572      }
2573
2574      return true;
2575    }
2576
2577    bool CheckConstraint (MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, Location loc)
2578    {
2579      //
2580      // First, check the `class' and `struct' constraints.
2581      //
2582      if (tparam.HasSpecialClass && !TypeSpec.IsReferenceType (atype)) {
2583        if (mc != null) {
2584          mc.Module.Compiler.Report.Error (452, loc,
2585            "The type `{0}' must be a reference type in order to use it as type parameter `{1}' in the generic type or method `{2}'",
2586            atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError ());
2587        }
2588
2589        return false;
2590      }
2591
2592      if (tparam.HasSpecialStruct && (!TypeSpec.IsValueType (atype) || atype.IsNullableType)) {
2593        if (mc != null) {
2594          mc.Module.Compiler.Report.Error (453, loc,
2595            "The type `{0}' must be a non-nullable value type in order to use it as type parameter `{1}' in the generic type or method `{2}'",
2596            atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError ());
2597        }
2598
2599        return false;
2600      }
2601
2602      bool ok = true;
2603
2604      //
2605      // Check the class constraint
2606      //
2607      if (tparam.HasTypeConstraint) {
2608        if (!CheckConversion (mc, context, atype, tparam, tparam.BaseType, loc)) {
2609          if (mc == null)
2610            return false;
2611
2612          ok = false;
2613        }
2614      }
2615
2616      //
2617      // Check the interfaces constraints
2618      //
2619      if (tparam.InterfacesDefined != null) {
2620        foreach (TypeSpec iface in tparam.InterfacesDefined) {
2621          if (!CheckConversion (mc, context, atype, tparam, iface, loc)) {
2622            if (mc == null)
2623              return false;
2624
2625            ok = false;
2626            break;
2627          }
2628        }
2629      }
2630
2631      //
2632      // Check the type parameter constraint
2633      //
2634      if (tparam.TypeArguments != null) {
2635        foreach (var ta in tparam.TypeArguments) {
2636          if (!CheckConversion (mc, context, atype, tparam, ta, loc)) {
2637            if (mc == null)
2638              return false;
2639
2640            ok = false;
2641            break;
2642          }
2643        }
2644      }
2645
2646      //
2647      // Finally, check the constructor constraint.
2648      //
2649      if (!tparam.HasSpecialConstructor)
2650        return ok;
2651
2652      if (!HasDefaultConstructor (atype)) {
2653        if (mc != null) {
2654          mc.Module.Compiler.Report.SymbolRelatedToPreviousError (atype);
2655          mc.Module.Compiler.Report.Error (310, loc,
2656            "The type `{0}' must have a public parameterless constructor in order to use it as parameter `{1}' in the generic type or method `{2}'",
2657            atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError ());
2658        }
2659        return false;
2660      }
2661
2662      return ok;
2663    }
2664
2665    static bool HasDynamicTypeArgument (TypeSpec[] targs)
2666    {
2667      for (int i = 0; i < targs.Length; ++i) {
2668        var targ = targs [i];
2669        if (targ.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
2670          return true;
2671
2672        if (HasDynamicTypeArgument (targ.TypeArguments))
2673          return true;
2674      }
2675
2676      return false;
2677    }
2678
2679    bool CheckConversion (IMemberContext mc, MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, TypeSpec ttype, Location loc)
2680    {
2681      if (atype == ttype)
2682        return true;
2683
2684      if (atype.IsGenericParameter) {
2685        var tps = (TypeParameterSpec) atype;
2686        if (tps.HasDependencyOn (ttype))
2687          return true;
2688
2689        if (Convert.ImplicitTypeParameterConversion (null, tps, ttype) != null)
2690          return true;
2691
2692      } else if (TypeSpec.IsValueType (atype)) {
2693        if (atype.IsNullableType) {
2694          //
2695          // LAMESPEC: Only identity or base type ValueType or Object satisfy nullable type
2696          //
2697          if (TypeSpec.IsBaseClass (atype, ttype, false))
2698            return true;
2699        } else {
2700          if (Convert.ImplicitBoxingConversion (null, atype, ttype) != null)
2701            return true;
2702        }
2703      } else {
2704        if (Convert.ImplicitReferenceConversionExists (atype, ttype) || Convert.ImplicitBoxingConversion (null, atype, ttype) != null)
2705          return true;
2706      }
2707
2708      if (mc != null) {
2709        mc.Module.Compiler.Report.SymbolRelatedToPreviousError (tparam);
2710        if (atype.IsGenericParameter) {
2711          mc.Module.Compiler.Report.Error (314, loc,
2712            "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing or type parameter conversion from `{0}' to `{3}'",
2713            atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
2714        } else if (TypeSpec.IsValueType (atype)) {
2715          if (atype.IsNullableType) {
2716            if (ttype.IsInterface) {
2717              mc.Module.Compiler.Report.Error (313, loc,
2718                "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. The nullable type `{0}' never satisfies interface constraint `{3}'",
2719                atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
2720            } else {
2721              mc.Module.Compiler.Report.Error (312, loc,
2722                "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. The nullable type `{0}' does not satisfy constraint `{3}'",
2723                atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
2724            }
2725          } else {
2726            mc.Module.Compiler.Report.Error (315, loc,
2727              "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing conversion from `{0}' to `{3}'",
2728              atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
2729          }
2730        } else {
2731          mc.Module.Compiler.Report.Error (311, loc,
2732            "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no implicit reference conversion from `{0}' to `{3}'",
2733            atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
2734        }
2735      }
2736
2737      return false;
2738    }
2739
2740    static bool HasDefaultConstructor (TypeSpec atype)
2741    {
2742      var tp = atype as TypeParameterSpec;
2743      if (tp != null) {
2744        return tp.HasSpecialConstructor || tp.HasSpecialStruct;
2745      }
2746
2747      if (atype.IsStruct || atype.IsEnum)
2748        return true;
2749
2750      if (atype.IsAbstract)
2751        return false;
2752
2753      var tdef = atype.GetDefinition ();
2754
2755      var found = MemberCache.FindMember (tdef,
2756        MemberFilter.Constructor (ParametersCompiled.EmptyReadOnlyParameters),
2757        BindingRestriction.DeclaredOnly | BindingRestriction.InstanceOnly);
2758
2759      return found != null && (found.Modifiers & Modifiers.PUBLIC) != 0;
2760    }
2761  }
2762
2763  //
2764  // Implements C# type inference
2765  //
2766  class TypeInference
2767  {
2768    //
2769    // Tracks successful rate of type inference
2770    //
2771    int score = int.MaxValue;
2772    readonly Arguments arguments;
2773    readonly int arg_count;
2774
2775    public TypeInference (Arguments arguments)
2776    {
2777      this.arguments = arguments;
2778      if (arguments != null)
2779        arg_count = arguments.Count;
2780    }
2781
2782    public int InferenceScore {
2783      get {
2784        return score;
2785      }
2786    }
2787
2788    public TypeSpec[] InferMethodArguments (ResolveContext ec, MethodSpec method)
2789    {
2790      var method_generic_args = method.GenericDefinition.TypeParameters;
2791      TypeInferenceContext context = new TypeInferenceContext (method_generic_args);
2792      if (!context.UnfixedVariableExists)
2793        return TypeSpec.EmptyTypes;
2794
2795      AParametersCollection pd = method.Parameters;
2796      if (!InferInPhases (ec, context, pd))
2797        return null;
2798
2799      return context.InferredTypeArguments;
2800    }
2801
2802    //
2803    // Implements method type arguments inference
2804    //
2805    bool InferInPhases (ResolveContext ec, TypeInferenceContext tic, AParametersCollection methodParameters)
2806    {
2807      int params_arguments_start;
2808      if (methodParameters.HasParams) {
2809        params_arguments_start = methodParameters.Count - 1;
2810      } else {
2811        params_arguments_start = arg_count;
2812      }
2813
2814      TypeSpec [] ptypes = methodParameters.Types;
2815     
2816      //
2817      // The first inference phase
2818      //
2819      TypeSpec method_parameter = null;
2820      for (int i = 0; i < arg_count; i++) {
2821        Argument a = arguments [i];
2822        if (a == null)
2823          continue;
2824       
2825        if (i < params_arguments_start) {
2826          method_parameter = methodParameters.Types [i];
2827        } else if (i == params_arguments_start) {
2828          if (arg_count == params_arguments_start + 1 && TypeManager.HasElementType (a.Type))
2829            method_parameter = methodParameters.Types [params_arguments_start];
2830          else
2831            method_parameter = TypeManager.GetElementType (methodParameters.Types [params_arguments_start]);
2832
2833          ptypes = (TypeSpec[]) ptypes.Clone ();
2834          ptypes [i] = method_parameter;
2835        }
2836
2837        //
2838        // When a lambda expression, an anonymous method
2839        // is used an explicit argument type inference takes a place
2840        //
2841        AnonymousMethodExpression am = a.Expr as AnonymousMethodExpression;
2842        if (am != null) {
2843          if (am.ExplicitTypeInference (tic, method_parameter))
2844            --score;
2845          continue;
2846        }
2847
2848        if (a.IsByRef) {
2849          score -= tic.ExactInference (a.Type, method_parameter);
2850          continue;
2851        }
2852
2853        if (a.Expr.Type == InternalType.NullLiteral)
2854          continue;
2855
2856        if (TypeSpec.IsValueType (method_parameter)) {
2857          score -= tic.LowerBoundInference (a.Type, method_parameter);
2858          continue;
2859        }
2860
2861        //
2862        // Otherwise an output type inference is made
2863        //
2864        score -= tic.OutputTypeInference (ec, a.Expr, method_parameter);
2865      }
2866
2867      //
2868      // Part of the second phase but because it happens only once
2869      // we don't need to call it in cycle
2870      //
2871      bool fixed_any = false;
2872      if (!tic.FixIndependentTypeArguments (ec, ptypes, ref fixed_any))
2873        return false;
2874
2875      return DoSecondPhase (ec, tic, ptypes, !fixed_any);
2876    }
2877
2878    bool DoSecondPhase (ResolveContext ec, TypeInferenceContext tic, TypeSpec[] methodParameters, bool fixDependent)
2879    {
2880      bool fixed_any = false;
2881      if (fixDependent && !tic.FixDependentTypes (ec, ref fixed_any))
2882        return false;
2883
2884      // If no further unfixed type variables exist, type inference succeeds
2885      if (!tic.UnfixedVariableExists)
2886        return true;
2887
2888      if (!fixed_any && fixDependent)
2889        return false;
2890     
2891      // For all arguments where the corresponding argument output types
2892      // contain unfixed type variables but the input types do not,
2893      // an output type inference is made
2894      for (int i = 0; i < arg_count; i++) {
2895       
2896        // Align params arguments
2897        TypeSpec t_i = methodParameters [i >= methodParameters.Length ? methodParameters.Length - 1: i];
2898       
2899        if (!t_i.IsDelegate) {
2900          if (!t_i.IsExpressionTreeType)
2901            continue;
2902
2903          t_i = TypeManager.GetTypeArguments (t_i) [0];
2904        }
2905
2906        var mi = Delegate.GetInvokeMethod (t_i);
2907        TypeSpec rtype = mi.ReturnType;
2908
2909        if (tic.IsReturnTypeNonDependent (mi, rtype)) {
2910          // It can be null for default arguments
2911          if (arguments[i] == null)
2912            continue;
2913
2914          score -= tic.OutputTypeInference (ec, arguments[i].Expr, t_i);
2915        }
2916      }
2917
2918
2919      return DoSecondPhase (ec, tic, methodParameters, true);
2920    }
2921  }
2922
2923  public class TypeInferenceContext
2924  {
2925    protected enum BoundKind
2926    {
2927      Exact = 0,
2928      Lower = 1,
2929      Upper = 2
2930    }
2931
2932    struct BoundInfo : IEquatable<BoundInfo>
2933    {
2934      public readonly TypeSpec Type;
2935      public readonly BoundKind Kind;
2936
2937      public BoundInfo (TypeSpec type, BoundKind kind)
2938      {
2939        this.Type = type;
2940        this.Kind = kind;
2941      }
2942     
2943      public override int GetHashCode ()
2944      {
2945        return Type.GetHashCode ();
2946      }
2947
2948      public Expression GetTypeExpression ()
2949      {
2950        return new TypeExpression (Type, Location.Null);
2951      }
2952
2953      #region IEquatable<BoundInfo> Members
2954
2955      public bool Equals (BoundInfo other)
2956      {
2957        return Type == other.Type && Kind == other.Kind;
2958      }
2959
2960      #endregion
2961    }
2962
2963    readonly TypeSpec[] tp_args;
2964    readonly TypeSpec[] fixed_types;
2965    readonly List<BoundInfo>[] bounds;
2966
2967    // TODO MemberCache: Could it be TypeParameterSpec[] ??
2968    public TypeInferenceContext (TypeSpec[] typeArguments)
2969    {
2970      if (typeArguments.Length == 0)
2971        throw new ArgumentException ("Empty generic arguments");
2972
2973      fixed_types = new TypeSpec [typeArguments.Length];
2974      for (int i = 0; i < typeArguments.Length; ++i) {
2975        if (typeArguments [i].IsGenericParameter) {
2976          if (bounds == null) {
2977            bounds = new List<BoundInfo> [typeArguments.Length];
2978            tp_args = new TypeSpec [typeArguments.Length];
2979          }
2980          tp_args [i] = typeArguments [i];
2981        } else {
2982          fixed_types [i] = typeArguments [i];
2983        }
2984      }
2985    }
2986
2987    //
2988    // Used together with AddCommonTypeBound fo implement
2989    // 7.4.2.13 Finding the best common type of a set of expressions
2990    //
2991    public TypeInferenceContext ()
2992    {
2993      fixed_types = new TypeSpec [1];
2994      tp_args = new TypeSpec [1];
2995      tp_args[0] = InternalType.Arglist; // it can be any internal type
2996      bounds = new List<BoundInfo> [1];
2997    }
2998
2999    public TypeSpec[] InferredTypeArguments {
3000      get {
3001        return fixed_types;
3002      }
3003    }
3004
3005    public void AddCommonTypeBound (TypeSpec type)
3006    {
3007      AddToBounds (new BoundInfo (type, BoundKind.Lower), 0, false);
3008    }
3009
3010    public void AddCommonTypeBoundAsync (TypeSpec type)
3011    {
3012      AddToBounds (new BoundInfo (type, BoundKind.Lower), 0, true);
3013    }
3014
3015    void AddToBounds (BoundInfo bound, int index, bool voidAllowed)
3016    {
3017      //
3018      // Some types cannot be used as type arguments
3019      //
3020      if ((bound.Type.Kind == MemberKind.Void && !voidAllowed) || bound.Type.IsPointer || bound.Type.IsSpecialRuntimeType ||
3021        bound.Type == InternalType.MethodGroup || bound.Type == InternalType.AnonymousMethod)
3022        return;
3023
3024      var a = bounds [index];
3025      if (a == null) {
3026        a = new List<BoundInfo> (2);
3027        a.Add (bound);
3028        bounds [index] = a;
3029        return;
3030      }
3031
3032      if (a.Contains (bound))
3033        return;
3034
3035      a.Add (bound);
3036    }
3037   
3038    bool AllTypesAreFixed (TypeSpec[] types)
3039    {
3040      foreach (TypeSpec t in types) {
3041        if (t.IsGenericParameter) {
3042          if (!IsFixed (t))
3043            return false;
3044          continue;
3045        }
3046
3047        if (TypeManager.IsGenericType (t))
3048          return AllTypesAreFixed (TypeManager.GetTypeArguments (t));
3049      }
3050     
3051      return true;
3052    }   
3053
3054    //
3055    // 26.3.3.8 Exact Inference
3056    //
3057    public int ExactInference (TypeSpec u, TypeSpec v)
3058    {
3059      // If V is an array type
3060      if (v.IsArray) {
3061        if (!u.IsArray)
3062          return 0;
3063
3064        var ac_u = (ArrayContainer) u;
3065        var ac_v = (ArrayContainer) v;
3066        if (ac_u.Rank != ac_v.Rank)
3067          return 0;
3068
3069        return ExactInference (ac_u.Element, ac_v.Element);
3070      }
3071
3072      // If V is constructed type and U is constructed type
3073      if (TypeManager.IsGenericType (v)) {
3074        if (!TypeManager.IsGenericType (u) || v.MemberDefinition != u.MemberDefinition)
3075          return 0;
3076
3077        TypeSpec [] ga_u = TypeManager.GetTypeArguments (u);
3078        TypeSpec [] ga_v = TypeManager.GetTypeArguments (v);
3079        if (ga_u.Length != ga_v.Length)
3080          return 0;
3081
3082        int score = 0;
3083        for (int i = 0; i < ga_u.Length; ++i)
3084          score += ExactInference (ga_u [i], ga_v [i]);
3085
3086        return System.Math.Min (1, score);
3087      }
3088
3089      // If V is one of the unfixed type arguments
3090      int pos = IsUnfixed (v);
3091      if (pos == -1)
3092        return 0;
3093
3094      AddToBounds (new BoundInfo (u, BoundKind.Exact), pos, false);
3095      return 1;
3096    }
3097
3098    public bool FixAllTypes (ResolveContext ec)
3099    {
3100      for (int i = 0; i < tp_args.Length; ++i) {
3101        if (!FixType (ec, i))
3102          return false;
3103      }
3104      return true;
3105    }
3106
3107    //
3108    // All unfixed type variables Xi are fixed for which all of the following hold:
3109    // a, There is at least one type variable Xj that depends on Xi
3110    // b, Xi has a non-empty set of bounds
3111    //
3112    public bool FixDependentTypes (ResolveContext ec, ref bool fixed_any)
3113    {
3114      for (int i = 0; i < tp_args.Length; ++i) {
3115        if (fixed_types[i] != null)
3116          continue;
3117
3118        if (bounds[i] == null)
3119          continue;
3120
3121        if (!FixType (ec, i))
3122          return false;
3123       
3124        fixed_any = true;
3125      }
3126
3127      return true;
3128    }
3129
3130    //
3131    // All unfixed type variables Xi which depend on no Xj are fixed
3132    //
3133    public bool FixIndependentTypeArguments (ResolveContext ec, TypeSpec[] methodParameters, ref bool fixed_any)
3134    {
3135      var types_to_fix = new List<TypeSpec> (tp_args);
3136      for (int i = 0; i < methodParameters.Length; ++i) {
3137        TypeSpec t = methodParameters[i];
3138
3139        if (!t.IsDelegate) {
3140          if (!t.IsExpressionTreeType)
3141            continue;
3142
3143          t =  TypeManager.GetTypeArguments (t) [0];
3144        }
3145
3146        if (t.IsGenericParameter)
3147          continue;
3148
3149        var invoke = Delegate.GetInvokeMethod (t);
3150        TypeSpec rtype = invoke.ReturnType;
3151        while (rtype.IsArray)
3152          rtype = ((ArrayContainer) rtype).Element;
3153
3154        if (!rtype.IsGenericParameter && !TypeManager.IsGenericType (rtype))
3155          continue;
3156
3157        // Remove dependent types, they cannot be fixed yet
3158        RemoveDependentTypes (types_to_fix, rtype);
3159      }
3160
3161      foreach (TypeSpec t in types_to_fix) {
3162        if (t == null)
3163          continue;
3164
3165        int idx = IsUnfixed (t);
3166        if (idx >= 0 && !FixType (ec, idx)) {
3167          return false;
3168        }
3169      }
3170
3171      fixed_any = types_to_fix.Count > 0;
3172      return true;
3173    }
3174
3175    //
3176    // 26.3.3.10 Fixing
3177    //
3178    public bool FixType (ResolveContext ec, int i)
3179    {
3180      // It's already fixed
3181      if (fixed_types[i] != null)
3182        throw new InternalErrorException ("Type argument has been already fixed");
3183
3184      var candidates = bounds [i];
3185      if (candidates == null)
3186        return false;
3187
3188      if (candidates.Count == 1) {
3189        TypeSpec t = candidates[0].Type;
3190        if (t == InternalType.NullLiteral)
3191          return false;
3192
3193        fixed_types [i] = t;
3194        return true;
3195      }
3196
3197      //
3198      // The set of candidate types Uj starts out as the set of
3199      // all types in the set of bounds for Xi
3200      //
3201      var applicable = new bool [candidates.Count];
3202      for (int ci = 0; ci < applicable.Length; ++ci)
3203        applicable [ci] = true;
3204
3205      for (int ci = 0; ci < applicable.Length; ++ci) {
3206        var bound = candidates [ci];
3207        int cii = 0;
3208
3209        switch (bound.Kind) {
3210        case BoundKind.Exact:
3211          for (; cii != applicable.Length; ++cii) {
3212            if (ci == cii)
3213              continue;
3214
3215            if (!applicable[cii])
3216              break;
3217
3218            //
3219            // For each exact bound U of Xi all types Uj which are not identical
3220            // to U are removed from the candidate set
3221            //
3222            if (candidates [cii].Type != bound.Type)
3223              applicable[cii] = false;
3224          }
3225
3226          break;
3227        case BoundKind.Lower:
3228          for (; cii != applicable.Length; ++cii) {
3229            if (ci == cii)
3230              continue;
3231
3232            if (!applicable[cii])
3233              break;
3234
3235            //
3236            // For each lower bound U of Xi all types Uj to which there is not an implicit conversion
3237            // from U are removed from the candidate set
3238            //
3239            if (!Convert.ImplicitConversionExists (ec, bound.GetTypeExpression (), candidates [cii].Type)) {
3240              applicable[cii] = false;
3241            }
3242          }
3243
3244          break;
3245
3246        case BoundKind.Upper:
3247          for (; cii != applicable.Length; ++cii) {
3248            if (ci == cii)
3249              continue;
3250
3251            if (!applicable[cii])
3252              break;
3253
3254            //
3255            // For each upper bound U of Xi all types Uj from which there is not an implicit conversion
3256            // to U are removed from the candidate set
3257            //
3258            if (!Convert.ImplicitConversionExists (ec, candidates[cii].GetTypeExpression (), bound.Type))
3259              applicable[cii] = false;
3260          }
3261
3262          break;
3263        }
3264      }
3265
3266      TypeSpec best_candidate = null;
3267      for (int ci = 0; ci < applicable.Length; ++ci) {
3268        if (!applicable[ci])
3269          continue;
3270
3271        var bound = candidates [ci];
3272        if (bound.Type == best_candidate)
3273          continue;
3274
3275        int cii = 0;
3276        for (; cii < applicable.Length; ++cii) {
3277          if (ci == cii)
3278            continue;
3279
3280          if (!applicable[cii])
3281            continue;
3282
3283          if (!Convert.ImplicitConversionExists (ec, candidates[cii].GetTypeExpression (), bound.Type))
3284            break;
3285        }
3286
3287        if (cii != applicable.Length)
3288          continue;
3289
3290        //
3291        // We already have the best candidate, break if it's different (non-unique)
3292        //
3293        // Dynamic is never ambiguous as we prefer dynamic over other best candidate types
3294        //
3295        if (best_candidate != null) {
3296
3297          if (best_candidate.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3298            continue;
3299
3300          if (bound.Type.BuiltinType != BuiltinTypeSpec.Type.Dynamic && best_candidate != bound.Type)
3301            return false;
3302        }
3303
3304        best_candidate = bound.Type;
3305      }
3306
3307      if (best_candidate == null)
3308        return false;
3309
3310      fixed_types[i] = best_candidate;
3311      return true;
3312    }
3313
3314    public bool HasBounds (int pos)
3315    {
3316      return bounds[pos] != null;
3317    }
3318   
3319    //
3320    // Uses inferred or partially infered types to inflate delegate type argument. Returns
3321    // null when type parameter has not been fixed
3322    //
3323    public TypeSpec InflateGenericArgument (IModuleContext context, TypeSpec parameter)
3324    {
3325      var tp = parameter as TypeParameterSpec;
3326      if (tp != null) {
3327        //
3328        // Type inference works on generic arguments (MVAR) only
3329        //
3330        if (!tp.IsMethodOwned)
3331          return parameter;
3332
3333        //
3334        // Ensure the type parameter belongs to same container
3335        //
3336        if (tp.DeclaredPosition < tp_args.Length && tp_args[tp.DeclaredPosition] == parameter)
3337          return fixed_types[tp.DeclaredPosition] ?? parameter;
3338
3339        return parameter;
3340      }
3341
3342      var gt = parameter as InflatedTypeSpec;
3343      if (gt != null) {
3344        var inflated_targs = new TypeSpec [gt.TypeArguments.Length];
3345        for (int ii = 0; ii < inflated_targs.Length; ++ii) {
3346          var inflated = InflateGenericArgument (context, gt.TypeArguments [ii]);
3347          if (inflated == null)
3348            return null;
3349
3350          inflated_targs[ii] = inflated;
3351        }
3352
3353        return gt.GetDefinition ().MakeGenericType (context, inflated_targs);
3354      }
3355
3356      var ac = parameter as ArrayContainer;
3357      if (ac != null) {
3358        var inflated = InflateGenericArgument (context, ac.Element);
3359        if (inflated != ac.Element)
3360          return ArrayContainer.MakeType (context.Module, inflated);
3361      }
3362
3363      return parameter;
3364    }
3365   
3366    //
3367    // Tests whether all delegate input arguments are fixed and generic output type
3368    // requires output type inference
3369    //
3370    public bool IsReturnTypeNonDependent (MethodSpec invoke, TypeSpec returnType)
3371    {
3372      AParametersCollection d_parameters = invoke.Parameters;
3373
3374      if (d_parameters.IsEmpty)
3375        return true;
3376
3377      while (returnType.IsArray)
3378        returnType = ((ArrayContainer) returnType).Element;
3379
3380      if (returnType.IsGenericParameter) {
3381        if (IsFixed (returnType))
3382            return false;
3383      } else if (TypeManager.IsGenericType (returnType)) {
3384        TypeSpec[] g_args = TypeManager.GetTypeArguments (returnType);
3385       
3386        // At least one unfixed return type has to exist
3387        if (AllTypesAreFixed (g_args))
3388          return false;
3389      } else {
3390        return false;
3391      }
3392
3393      // All generic input arguments have to be fixed
3394      return AllTypesAreFixed (d_parameters.Types);
3395    }
3396
3397    bool IsFixed (TypeSpec type)
3398    {
3399      return IsUnfixed (type) == -1;
3400    }   
3401
3402    int IsUnfixed (TypeSpec type)
3403    {
3404      if (!type.IsGenericParameter)
3405        return -1;
3406
3407      for (int i = 0; i < tp_args.Length; ++i) {
3408        if (tp_args[i] == type) {
3409          if (fixed_types[i] != null)
3410            break;
3411
3412          return i;
3413        }
3414      }
3415
3416      return -1;
3417    }
3418
3419    //
3420    // 26.3.3.9 Lower-bound Inference
3421    //
3422    public int LowerBoundInference (TypeSpec u, TypeSpec v)
3423    {
3424      return LowerBoundInference (u, v, false);
3425    }
3426
3427    //
3428    // Lower-bound (false) or Upper-bound (true) inference based on inversed argument
3429    //
3430    int LowerBoundInference (TypeSpec u, TypeSpec v, bool inversed)
3431    {
3432      // If V is one of the unfixed type arguments
3433      int pos = IsUnfixed (v);
3434      if (pos != -1) {
3435        AddToBounds (new BoundInfo (u, inversed ? BoundKind.Upper : BoundKind.Lower), pos, false);
3436        return 1;
3437      }     
3438
3439      // If U is an array type
3440      var u_ac = u as ArrayContainer;
3441      if (u_ac != null) {
3442        var v_ac = v as ArrayContainer;
3443        if (v_ac != null) {
3444          if (u_ac.Rank != v_ac.Rank)
3445            return 0;
3446
3447          if (TypeSpec.IsValueType (u_ac.Element))
3448            return ExactInference (u_ac.Element, v_ac.Element);
3449
3450          return LowerBoundInference (u_ac.Element, v_ac.Element, inversed);
3451        }
3452
3453        if (u_ac.Rank != 1 || !v.IsArrayGenericInterface)
3454          return 0;
3455
3456        var v_i = TypeManager.GetTypeArguments (v) [0];
3457        if (TypeSpec.IsValueType (u_ac.Element))
3458          return ExactInference (u_ac.Element, v_i);
3459
3460        return LowerBoundInference (u_ac.Element, v_i);
3461      }
3462     
3463      if (v.IsGenericOrParentIsGeneric) {
3464        //
3465        // if V is a constructed type C<V1..Vk> and there is a unique type C<U1..Uk>
3466        // such that U is identical to, inherits from (directly or indirectly),
3467        // or implements (directly or indirectly) C<U1..Uk>
3468        //
3469        var u_candidates = new List<TypeSpec> ();
3470        var open_v = v.MemberDefinition;
3471
3472        for (TypeSpec t = u; t != null; t = t.BaseType) {
3473          if (open_v == t.MemberDefinition)
3474            u_candidates.Add (t);
3475
3476          //
3477          // Using this trick for dynamic type inference, the spec says the type arguments are "unknown" but
3478          // that would complicate the process a lot, instead I treat them as dynamic
3479          //
3480          if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3481            u_candidates.Add (t);
3482        }
3483
3484        if (u.Interfaces != null) {
3485          foreach (var iface in u.Interfaces) {
3486            if (open_v == iface.MemberDefinition)
3487              u_candidates.Add (iface);
3488          }
3489        }
3490
3491        TypeSpec[] unique_candidate_targs = null;
3492        var ga_v = TypeSpec.GetAllTypeArguments (v);
3493        foreach (TypeSpec u_candidate in u_candidates) {
3494          //
3495          // The unique set of types U1..Uk means that if we have an interface I<T>,
3496          // class U : I<int>, I<long> then no type inference is made when inferring
3497          // type I<T> by applying type U because T could be int or long
3498          //
3499          if (unique_candidate_targs != null) {
3500            TypeSpec[] second_unique_candidate_targs = TypeSpec.GetAllTypeArguments (u_candidate);
3501            if (TypeSpecComparer.Equals (unique_candidate_targs, second_unique_candidate_targs)) {
3502              unique_candidate_targs = second_unique_candidate_targs;
3503              continue;
3504            }
3505
3506            //
3507            // Break when candidate arguments are ambiguous
3508            //
3509            return 0;
3510          }
3511
3512          //
3513          // A candidate is dynamic type expression, to simplify things use dynamic
3514          // for all type parameter of this type. For methods like this one
3515          //
3516          // void M<T, U> (IList<T>, IList<U[]>)
3517          //
3518          // dynamic becomes both T and U when the arguments are of dynamic type
3519          //
3520          if (u_candidate.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3521            unique_candidate_targs = new TypeSpec[ga_v.Length];
3522            for (int i = 0; i < unique_candidate_targs.Length; ++i)
3523              unique_candidate_targs[i] = u_candidate;
3524          } else {
3525            unique_candidate_targs = TypeSpec.GetAllTypeArguments (u_candidate);
3526          }
3527        }
3528
3529        if (unique_candidate_targs != null) {
3530          int score = 0;
3531          int tp_index = -1;
3532          TypeParameterSpec[] tps = null;
3533
3534          for (int i = 0; i < unique_candidate_targs.Length; ++i) {
3535            if (tp_index < 0) {
3536              while (v.Arity == 0)
3537                v = v.DeclaringType;
3538
3539              tps = v.MemberDefinition.TypeParameters;
3540              tp_index = tps.Length - 1;
3541            }
3542
3543            Variance variance = tps [tp_index--].Variance;
3544
3545            TypeSpec u_i = unique_candidate_targs [i];
3546            if (variance == Variance.None || TypeSpec.IsValueType (u_i)) {
3547              if (ExactInference (u_i, ga_v [i]) == 0)
3548                ++score;
3549            } else {
3550              bool upper_bound = (variance == Variance.Contravariant && !inversed) ||
3551                (variance == Variance.Covariant && inversed);
3552
3553              if (LowerBoundInference (u_i, ga_v [i], upper_bound) == 0)
3554                ++score;
3555            }
3556          }
3557
3558          return score;
3559        }
3560      }
3561
3562      return 0;
3563    }
3564
3565    //
3566    // 26.3.3.6 Output Type Inference
3567    //
3568    public int OutputTypeInference (ResolveContext ec, Expression e, TypeSpec t)
3569    {
3570      // If e is a lambda or anonymous method with inferred return type
3571      AnonymousMethodExpression ame = e as AnonymousMethodExpression;
3572      if (ame != null) {
3573        TypeSpec rt = ame.InferReturnType (ec, this, t);
3574        var invoke = Delegate.GetInvokeMethod (t);
3575
3576        if (rt == null) {
3577          AParametersCollection pd = invoke.Parameters;
3578          return ame.Parameters.Count == pd.Count ? 1 : 0;
3579        }
3580
3581        TypeSpec rtype = invoke.ReturnType;
3582        return LowerBoundInference (rt, rtype) + 1;
3583      }
3584
3585      //
3586      // if E is a method group and T is a delegate type or expression tree type
3587      // return type Tb with parameter types T1..Tk and return type Tb, and overload
3588      // resolution of E with the types T1..Tk yields a single method with return type U,
3589      // then a lower-bound inference is made from U for Tb.
3590      //
3591      if (e is MethodGroupExpr) {
3592        if (!t.IsDelegate) {
3593          if (!t.IsExpressionTreeType)
3594            return 0;
3595
3596          t = TypeManager.GetTypeArguments (t)[0];
3597        }
3598
3599        var invoke = Delegate.GetInvokeMethod (t);
3600        TypeSpec rtype = invoke.ReturnType;
3601
3602        if (!IsReturnTypeNonDependent (invoke, rtype))
3603          return 0;
3604
3605        // LAMESPEC: Standard does not specify that all methodgroup arguments
3606        // has to be fixed but it does not specify how to do recursive type inference
3607        // either. We choose the simple option and infer return type only
3608        // if all delegate generic arguments are fixed.
3609        TypeSpec[] param_types = new TypeSpec [invoke.Parameters.Count];
3610        for (int i = 0; i < param_types.Length; ++i) {
3611          var inflated = InflateGenericArgument (ec, invoke.Parameters.Types[i]);
3612          if (inflated == null)
3613            return 0;
3614
3615          param_types[i] = inflated;
3616        }
3617
3618        MethodGroupExpr mg = (MethodGroupExpr) e;
3619        Arguments args = DelegateCreation.CreateDelegateMethodArguments (ec, invoke.Parameters, param_types, e.Location);
3620        mg = mg.OverloadResolve (ec, ref args, null, OverloadResolver.Restrictions.CovariantDelegate | OverloadResolver.Restrictions.ProbingOnly);
3621        if (mg == null)
3622          return 0;
3623
3624        return LowerBoundInference (mg.BestCandidateReturnType, rtype) + 1;
3625      }
3626
3627      //
3628      // if e is an expression with type U, then
3629      // a lower-bound inference is made from U for T
3630      //
3631      return LowerBoundInference (e.Type, t) * 2;
3632    }
3633
3634    void RemoveDependentTypes (List<TypeSpec> types, TypeSpec returnType)
3635    {
3636      int idx = IsUnfixed (returnType);
3637      if (idx >= 0) {
3638        types [idx] = null;
3639        return;
3640      }
3641
3642      if (TypeManager.IsGenericType (returnType)) {
3643        foreach (TypeSpec t in TypeManager.GetTypeArguments (returnType)) {
3644          RemoveDependentTypes (types, t);
3645        }
3646      }
3647    }
3648
3649    public bool UnfixedVariableExists {
3650      get {
3651        foreach (TypeSpec ut in fixed_types) {
3652          if (ut == null)
3653            return true;
3654        }
3655
3656        return false;
3657      }
3658    }
3659  }
3660}
Note: See TracBrowser for help on using the repository browser.