Allow imported members cache to be setup in 2 phases as compiled one is to deal with...
[mono.git] / mcs / mcs / generic.cs
index e45400f703f1f9818ae41a75eb08063c4ed96be8..06595900499474caefa33699446c180205b01da7 100644 (file)
@@ -90,7 +90,7 @@ namespace Mono.CSharp {
 
                bool CheckConflictingInheritedConstraint (TypeSpec ba, TypeSpec bb, IMemberContext context, Location loc)
                {
-                       if (!TypeManager.IsSubclassOf (ba, bb) && !TypeManager.IsSubclassOf (bb, ba)) {
+                       if (!TypeSpec.IsBaseClass (ba, bb, false) && !TypeSpec.IsBaseClass (bb, ba, false)) {
                                context.Compiler.Report.Error (455, loc,
                                        "Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
                                        tparam.Value,
@@ -306,17 +306,25 @@ namespace Mono.CSharp {
                
                Constraints constraints;
                GenericTypeParameterBuilder builder;
-//             Variance variance;
                TypeParameterSpec spec;
 
                public TypeParameter (DeclSpace parent, int index, MemberName name, Constraints constraints, Attributes attrs, Variance variance)
                        : base (parent, name, attrs)
                {
                        this.constraints = constraints;
-//                     this.variance = variance;
                        this.spec = new TypeParameterSpec (null, index, this, SpecialConstraint.None, variance, null);
                }
 
+               public TypeParameter (TypeParameterSpec spec, DeclSpace parent, TypeSpec parentSpec, MemberName name, Attributes attrs)
+                       : base (parent, name, attrs)
+               {
+                       this.spec = new TypeParameterSpec (parentSpec, spec.DeclaredPosition, spec.MemberDefinition, spec.SpecialConstraint, spec.Variance, null) {
+                               BaseType = spec.BaseType,
+                               InterfacesDefined = spec.InterfacesDefined,
+                               TypeArguments = spec.TypeArguments
+                       };
+               }
+
                #region Properties
 
                public override AttributeTargets AttributeTargets {
@@ -401,7 +409,12 @@ namespace Mono.CSharp {
                        if (constraints != null)
                                return spec.HasSameConstraintsDefinition (tp.Type);
 
-                       constraints = new_constraints;
+                       // Copy constraint from resolved part to partial container
+                       spec.SpecialConstraint = tp.spec.SpecialConstraint;
+                       spec.InterfacesDefined = tp.spec.InterfacesDefined;
+                       spec.TypeArguments = tp.spec.TypeArguments;
+                       spec.BaseType = tp.spec.BaseType;
+                       
                        return true;
                }
 
@@ -416,15 +429,9 @@ namespace Mono.CSharp {
                                constraints.CheckGenericConstraints (this);
                }
 
-               public TypeParameter CreateHoistedCopy (TypeSpec declaringType)
+               public TypeParameter CreateHoistedCopy (TypeContainer declaringType, TypeSpec declaringSpec)
                {
-                       return new TypeParameter (Parent, spec.DeclaredPosition, MemberName, constraints, null, spec.Variance) {
-                               spec = new TypeParameterSpec (declaringType, spec.DeclaredPosition, spec.MemberDefinition, spec.SpecialConstraint, spec.Variance, null) {
-                                       BaseType = spec.BaseType,
-                                       InterfacesDefined = spec.InterfacesDefined,
-                                       TypeArguments = spec.TypeArguments
-                               }
-                       };
+                       return new TypeParameter (spec, declaringType, declaringSpec, MemberName, null);
                }
 
                public override bool Define ()
@@ -525,7 +532,7 @@ namespace Mono.CSharp {
                        return MemberName.Name;
                }
 
-               public MemberCache LoadMembers (TypeSpec declaringType)
+               public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
                {
                        throw new NotSupportedException ("Not supported for compiled definition");
                }
@@ -538,7 +545,9 @@ namespace Mono.CSharp {
                        if (constraints != null)
                                return constraints.Resolve (context, this);
 
-                       spec.BaseType = TypeManager.object_type;
+                       if (spec.BaseType == null)
+                               spec.BaseType = TypeManager.object_type;
+
                        return true;
                }
 
@@ -806,7 +815,7 @@ namespace Mono.CSharp {
                        // class A : I<int> { void Foo<X> where X : int {} }
                        //
                        bool found;
-                       if (BaseType != other.BaseType) {
+                       if (!TypeSpecComparer.Override.IsEqual (BaseType, other.BaseType)) {
                                if (other.targs == null)
                                        return false;
 
@@ -938,21 +947,25 @@ namespace Mono.CSharp {
                        return constraints;
                }
 
-               public override MemberSpec InflateMember (TypeParameterInflator inflator)
+               public void InflateConstraints (TypeParameterInflator inflator, TypeParameterSpec tps)
                {
-                       var tps = (TypeParameterSpec) MemberwiseClone ();
                        tps.BaseType = inflator.Inflate (BaseType);
                        if (ifaces != null) {
-                               tps.ifaces = new TypeSpec[ifaces.Count];
+                               tps.ifaces = new List<TypeSpec> (ifaces.Count);
                                for (int i = 0; i < ifaces.Count; ++i)
-                                       tps.ifaces[i] = inflator.Inflate (ifaces[i]);
+                                       tps.ifaces.Add (inflator.Inflate (ifaces[i]));
                        }
                        if (targs != null) {
                                tps.targs = new TypeSpec[targs.Length];
                                for (int i = 0; i < targs.Length; ++i)
                                        tps.targs[i] = inflator.Inflate (targs[i]);
                        }
+               }
 
+               public override MemberSpec InflateMember (TypeParameterInflator inflator)
+               {
+                       var tps = (TypeParameterSpec) MemberwiseClone ();
+                       InflateConstraints (inflator, tps);
                        return tps;
                }
 
@@ -971,6 +984,25 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool IsConvertibleToInterface (TypeSpec iface)
+               {
+                       if (Interfaces != null) {
+                               foreach (var t in Interfaces) {
+                                       if (t == iface)
+                                               return true;
+                               }
+                       }
+
+                       if (TypeArguments != null) {
+                               foreach (var t in TypeArguments) {
+                                       if (((TypeParameterSpec) t).IsConvertibleToInterface (iface))
+                                               return true;
+                               }
+                       }
+
+                       return false;
+               }
+
                public override TypeSpec Mutate (TypeParameterMutator mutator)
                {
                        return mutator.Mutate (this);
@@ -1039,7 +1071,7 @@ namespace Mono.CSharp {
                                        // to use same cache for nested types on same generic parent
                                        //
                                        // TODO: Should use BindingRestriction.DeclaredOnly or GetMember
-                                       ts = MemberCache.FindNestedType (parent, ts.Name, targs.Length);
+                                       ts = MemberCache.FindNestedType (parent, ts.Name, ts.Arity);
 
                                        //
                                        // Handle the tricky case where parent shares local type arguments
@@ -1066,7 +1098,7 @@ namespace Mono.CSharp {
                        }
 
                        // Inflate generic type
-                       if (ts.IsGeneric)
+                       if (ts.Arity > 0)
                                return InflateTypeParameters (ts);
 
                        return ts;
@@ -1078,7 +1110,7 @@ namespace Mono.CSharp {
                                if (tparams [i] == tp)
                                        return targs[i];
 
-                       // CECIL: This can happen when inflating nested types
+                       // This can happen when inflating nested types
                        // without type arguments specified
                        return tp;
                }
@@ -1137,6 +1169,29 @@ namespace Mono.CSharp {
                        this.var = var;
                }
 
+               #region Properties
+
+               public TypeParameter[] MethodTypeParameters {
+                       get {
+                               return mvar;
+                       }
+               }
+
+               #endregion
+
+               public static TypeSpec GetMemberDeclaringType (TypeSpec type)
+               {
+                       if (type is InflatedTypeSpec) {
+                               if (type.DeclaringType == null)
+                                       return type.GetDefinition ();
+
+                               var parent = GetMemberDeclaringType (type.DeclaringType);
+                               type = MemberCache.GetMember<TypeSpec> (parent, type);
+                       }
+
+                       return type;
+               }
+
                public TypeSpec Mutate (TypeSpec ts)
                {
                        TypeSpec value;
@@ -1148,12 +1203,6 @@ namespace Mono.CSharp {
                        return value;
                }
 
-               public FieldInfo Mutate (FieldSpec fs)
-               {
-                       // TODO:
-                       return fs.GetMetaInfo ();
-               }
-
                public TypeParameterSpec Mutate (TypeParameterSpec tp)
                {
                        for (int i = 0; i < mvar.Length; ++i) {
@@ -1256,15 +1305,6 @@ namespace Mono.CSharp {
                        }
                }
 
-               public override MemberCache MemberCacheTypes {
-                       get {
-                               if (cache == null)
-                                       InitializeMemberCache (true);
-
-                               return cache;
-                       }
-               }
-
                //
                // Types used to inflate the generic  type
                //
@@ -1336,9 +1376,6 @@ namespace Mono.CSharp {
                        if (TypeManager.IsNullableType (open_type))
                                return targs[0].GetSignatureForError () + "?";
 
-                       if (MemberDefinition is AnonymousTypeClass)
-                               return ((AnonymousTypeClass) MemberDefinition).GetSignatureForError ();
-
                        return base.GetSignatureForError ();
                }
 
@@ -1353,7 +1390,7 @@ namespace Mono.CSharp {
                protected override void InitializeMemberCache (bool onlyTypes)
                {
                        if (cache == null)
-                               cache = new MemberCache (open_type.MemberCache);
+                               cache = new MemberCache (onlyTypes ? open_type.MemberCacheTypes : open_type.MemberCache);
 
                        TypeParameterSpec[] tparams_full;
                        TypeSpec[] targs_full = targs;
@@ -1419,7 +1456,7 @@ namespace Mono.CSharp {
                        // inflated because are not yet available in membercache
                        //
                        if ((state & StateFlags.PendingMemberCacheMembers) == 0) {
-                               open_type.MemberCache.InflateTypes (cache, inflator);
+                               open_type.MemberCacheTypes.InflateTypes (cache, inflator);
 
                                //
                                // Inflate any implemented interfaces
@@ -1634,8 +1671,8 @@ namespace Mono.CSharp {
 
                public override bool Resolve (IMemberContext ec)
                {
-                       // should not be called
-                       throw new NotSupportedException ();
+                       // Nothing to be resolved
+                       return true;
                }
        }
 
@@ -1722,7 +1759,7 @@ namespace Mono.CSharp {
 
                //
                // Checks the constraints of open generic type against type
-               // arguments. Has to be called onafter all members are defined
+               // arguments. Has to be called after all members have been defined
                //
                public bool CheckConstraints (IMemberContext ec)
                {
@@ -1736,7 +1773,7 @@ namespace Mono.CSharp {
                        if (constraints == null)
                                return true;
 
-                       return ConstraintChecker.CheckAll (open_type, args.Arguments, constraints, loc, ec.Compiler.Report);
+                       return new ConstraintChecker(ec).CheckAll (open_type, args.Arguments, constraints, loc);
                }
        
                public override bool CheckAccessLevel (IMemberContext mc)
@@ -1755,12 +1792,23 @@ namespace Mono.CSharp {
 
                static bool HasDynamicArguments (TypeSpec[] args)
                {
-                       foreach (var item in args) {
+                       for (int i = 0; i < args.Length; ++i) {
+                               var item = args[i];
+
                                if (item == InternalType.Dynamic)
                                        return true;
 
                                if (TypeManager.IsGenericType (item))
                                        return HasDynamicArguments (TypeManager.GetTypeArguments (item));
+
+                               if (item.IsArray) {
+                                       while (item.IsArray) {
+                                               item = ((ArrayContainer) item).Element;
+                                       }
+
+                                       if (item == InternalType.Dynamic)
+                                               return true;
+                               }
                        }
 
                        return false;
@@ -1784,59 +1832,137 @@ namespace Mono.CSharp {
                }
        }
 
-       static class ConstraintChecker
+       //
+       // Generic type with unbound type arguments, used for typeof (G<,,>)
+       //
+       class GenericOpenTypeExpr : TypeExpr
        {
-               /// <summary>
-               ///   Check the constraints; we're called from ResolveAsTypeTerminal()
-               ///   after fully resolving the constructed type.
-               /// </summary>
-               public static bool CheckAll (MemberSpec context, TypeSpec[] targs, TypeParameterSpec[] tparams, Location loc, Report report)
+               public GenericOpenTypeExpr (TypeSpec type, /*UnboundTypeArguments args,*/ Location loc)
+               {
+                       this.type = type.GetDefinition ();
+                       this.loc = loc;
+               }
+
+               protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
+               {
+                       return this;
+               }
+       }
+
+       struct ConstraintChecker
+       {
+               IMemberContext mc;
+               bool ignore_inferred_dynamic;
+
+               public ConstraintChecker (IMemberContext ctx)
+               {
+                       this.mc = ctx;
+                       ignore_inferred_dynamic = false;
+               }
+
+               #region Properties
+
+               public bool IgnoreInferredDynamic {
+                       get {
+                               return ignore_inferred_dynamic;
+                       }
+                       set {
+                               ignore_inferred_dynamic = value;
+                       }
+               }
+
+               #endregion
+
+               //
+               // Checks all type arguments againts type parameters constraints
+               // NOTE: It can run in probing mode when `mc' is null
+               //
+               public bool CheckAll (MemberSpec context, TypeSpec[] targs, TypeParameterSpec[] tparams, Location loc)
                {
                        for (int i = 0; i < tparams.Length; i++) {
-                               if (!CheckConstraint (context, targs [i], tparams [i], loc, report))
+                               if (ignore_inferred_dynamic && targs[i] == InternalType.Dynamic)
+                                       continue;
+
+                               if (!CheckConstraint (context, targs [i], tparams [i], loc))
                                        return false;
                        }
 
                        return true;
                }
 
-               static bool CheckConstraint (MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, Location loc, Report report)
+               bool CheckConstraint (MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, Location loc)
                {
                        //
                        // First, check the `class' and `struct' constraints.
                        //
                        if (tparam.HasSpecialClass && !TypeManager.IsReferenceType (atype)) {
-                               report.Error (452, loc,
-                                       "The type `{0}' must be a reference type in order to use it as type parameter `{1}' in the generic type or method `{2}'",
-                                       TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ());
+                               if (mc != null) {
+                                       mc.Compiler.Report.Error (452, loc,
+                                               "The type `{0}' must be a reference type in order to use it as type parameter `{1}' in the generic type or method `{2}'",
+                                               TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ());
+                               }
+
                                return false;
                        }
 
                        if (tparam.HasSpecialStruct && (!TypeManager.IsValueType (atype) || TypeManager.IsNullableType (atype))) {
-                               report.Error (453, loc,
-                                       "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}'",
-                                       TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ());
+                               if (mc != null) {
+                                       mc.Compiler.Report.Error (453, loc,
+                                               "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}'",
+                                               TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ());
+                               }
+
                                return false;
                        }
 
+                       bool ok = true;
+
                        //
-                       // The class constraint comes next.
+                       // Check the class constraint
                        //
                        if (tparam.HasTypeConstraint) {
-                               CheckConversion (context, atype, tparam, tparam.BaseType, loc, report);
+                               if (!CheckConversion (mc, context, atype, tparam, tparam.BaseType, loc)) {
+                                       if (mc == null)
+                                               return false;
+
+                                       ok = false;
+                               }
                        }
 
                        //
-                       // Now, check the interfaces and type parameters constraints
+                       // Check the interfaces constraints
                        //
                        if (tparam.Interfaces != null) {
                                if (TypeManager.IsNullableType (atype)) {
-                                       report.Error (313, loc,
+                                       if (mc == null)
+                                               return false;
+
+                                       mc.Compiler.Report.Error (313, loc,
                                                "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",
                                                atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError ());
+                                       ok = false;
                                } else {
                                        foreach (TypeSpec iface in tparam.Interfaces) {
-                                               CheckConversion (context, atype, tparam, iface, loc, report);
+                                               if (!CheckConversion (mc, context, atype, tparam, iface, loc)) {
+                                                       if (mc == null)
+                                                               return false;
+
+                                                       ok = false;
+                                               }
+                                       }
+                               }
+                       }
+
+                       //
+                       // Check the type parameter constraint
+                       //
+                       if (tparam.TypeArguments != null) {
+                               foreach (var ta in tparam.TypeArguments) {
+                                       if (!CheckConversion (mc, context, atype, tparam, ta, loc)) {
+                                               if (mc == null)
+                                                       return false;
+
+                                               ok = false;
                                        }
                                }
                        }
@@ -1845,38 +1971,70 @@ namespace Mono.CSharp {
                        // Finally, check the constructor constraint.
                        //
                        if (!tparam.HasSpecialConstructor)
-                               return true;
+                               return ok;
 
                        if (!HasDefaultConstructor (atype)) {
-                               report.SymbolRelatedToPreviousError (atype);
-                               report.Error (310, loc,
-                                       "The type `{0}' must have a public parameterless constructor in order to use it as parameter `{1}' in the generic type or method `{2}'",
-                                       TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ());
+                               if (mc != null) {
+                                       mc.Compiler.Report.SymbolRelatedToPreviousError (atype);
+                                       mc.Compiler.Report.Error (310, loc,
+                                               "The type `{0}' must have a public parameterless constructor in order to use it as parameter `{1}' in the generic type or method `{2}'",
+                                               TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ());
+                               }
                                return false;
                        }
 
-                       return true;
+                       return ok;
+               }
+
+               static bool HasDynamicTypeArgument (TypeSpec[] targs)
+               {
+                       for (int i = 0; i < targs.Length; ++i) {
+                               var targ = targs [i];
+                               if (targ == InternalType.Dynamic)
+                                       return true;
+
+                               if (HasDynamicTypeArgument (targ.TypeArguments))
+                                       return true;
+                       }
+
+                       return false;
                }
 
-               static void CheckConversion (MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, TypeSpec ttype, Location loc, Report report)
+               bool CheckConversion (IMemberContext mc, MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, TypeSpec ttype, Location loc)
                {
                        var expr = new EmptyExpression (atype);
-                       if (!Convert.ImplicitStandardConversionExists (expr, ttype)) {
-                               report.SymbolRelatedToPreviousError (tparam);
+                       if (Convert.ImplicitStandardConversionExists (expr, ttype))
+                               return true;
+
+                       //
+                       // When partial/full type inference finds a dynamic type argument delay
+                       // the constraint check to runtime, it can succeed for real underlying
+                       // dynamic type
+                       //
+                       if (ignore_inferred_dynamic && HasDynamicTypeArgument (ttype.TypeArguments))
+                               return true;
+
+                       if (mc != null) {
+                               mc.Compiler.Report.SymbolRelatedToPreviousError (tparam);
                                if (TypeManager.IsValueType (atype)) {
-                                       report.Error (315, loc, "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}'",
+                                       mc.Compiler.Report.Error (315, loc,
+                                               "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}'",
                                                atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
                                } else if (atype.IsGenericParameter) {
-                                       report.Error (314, loc, "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}'",
+                                       mc.Compiler.Report.Error (314, loc,
+                                               "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}'",
                                                atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
                                } else {
-                                       report.Error (311, loc, "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}'",
+                                       mc.Compiler.Report.Error (311, loc,
+                                               "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}'",
                                                atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
                                }
                        }
+
+                       return false;
                }
 
-               static bool HasDefaultConstructor (TypeSpec atype)
+               bool HasDefaultConstructor (TypeSpec atype)
                {
                        var tp = atype as TypeParameterSpec;
                        if (tp != null) {
@@ -1973,18 +2131,26 @@ namespace Mono.CSharp {
                {
                        TypeParameterName[] names = MemberName.TypeArguments.GetDeclarations ();
                        string[] snames = new string [names.Length];
+                       var block = m.Block;
                        for (int i = 0; i < names.Length; i++) {
                                string type_argument_name = names[i].Name;
-                               int idx = parameters.GetParameterIndexByName (type_argument_name);
-                               if (idx >= 0) {
-                                       Block b = m.Block;
-                                       if (b == null)
-                                               b = new Block (null);
 
-                                       b.Error_AlreadyDeclaredTypeParameter (Report, parameters [i].Location,
-                                               type_argument_name, "method parameter");
+                               if (block == null) {
+                                       int idx = parameters.GetParameterIndexByName (type_argument_name);
+                                       if (idx >= 0) {
+                                               var b = m.Block;
+                                               if (b == null)
+                                                       b = new ToplevelBlock (Compiler, Location);
+
+                                               b.Error_AlreadyDeclaredTypeParameter (type_argument_name, parameters[i].Location);
+                                       }
+                               } else {
+                                       INamedBlockVariable variable = null;
+                                       block.GetLocalName (type_argument_name, m.Block, ref variable);
+                                       if (variable != null)
+                                               variable.Block.Error_AlreadyDeclaredTypeParameter (type_argument_name, variable.Location);
                                }
-                               
+
                                snames[i] = type_argument_name;
                        }
 
@@ -2056,76 +2222,34 @@ namespace Mono.CSharp {
 
                        return Variance.None;
                }
-
-               /// <summary>
-               ///   Type inference.  Try to infer the type arguments from `method',
-               ///   which is invoked with the arguments `arguments'.  This is used
-               ///   when resolving an Invocation or a DelegateInvocation and the user
-               ///   did not explicitly specify type arguments.
-               /// </summary>
-               public static int InferTypeArguments (ResolveContext ec, Arguments arguments, ref MethodSpec method)
-               {
-                       ATypeInference ti = ATypeInference.CreateInstance (arguments);
-                       TypeSpec[] i_args = ti.InferMethodArguments (ec, method);
-                       if (i_args == null)
-                               return ti.InferenceScore;
-
-                       if (i_args.Length == 0)
-                               return 0;
-
-                       method = method.MakeGenericMethod (i_args);
-                       return 0;
-               }
-       }
-
-       abstract class ATypeInference
-       {
-               protected readonly Arguments arguments;
-               protected readonly int arg_count;
-
-               protected ATypeInference (Arguments arguments)
-               {
-                       this.arguments = arguments;
-                       if (arguments != null)
-                               arg_count = arguments.Count;
-               }
-
-               public static ATypeInference CreateInstance (Arguments arguments)
-               {
-                       return new TypeInference (arguments);
-               }
-
-               public virtual int InferenceScore {
-                       get {
-                               return int.MaxValue;
-                       }
-               }
-
-               public abstract TypeSpec[] InferMethodArguments (ResolveContext ec, MethodSpec method);
        }
 
        //
        // Implements C# type inference
        //
-       class TypeInference : ATypeInference
+       class TypeInference
        {
                //
                // Tracks successful rate of type inference
                //
                int score = int.MaxValue;
+               readonly Arguments arguments;
+               readonly int arg_count;
 
                public TypeInference (Arguments arguments)
-                       : base (arguments)
                {
+                       this.arguments = arguments;
+                       if (arguments != null)
+                               arg_count = arguments.Count;
                }
 
-               public override int InferenceScore {
+               public int InferenceScore {
                        get {
                                return score;
                        }
                }
 
-               public override TypeSpec[] InferMethodArguments (ResolveContext ec, MethodSpec method)
+               public TypeSpec[] InferMethodArguments (ResolveContext ec, MethodSpec method)
                {
                        var method_generic_args = method.GenericDefinition.TypeParameters;
                        TypeInferenceContext context = new TypeInferenceContext (method_generic_args);
@@ -2264,7 +2388,7 @@ namespace Mono.CSharp {
                        Upper   = 2
                }
 
-               class BoundInfo
+               class BoundInfo : IEquatable<BoundInfo>
                {
                        public readonly TypeSpec Type;
                        public readonly BoundKind Kind;
@@ -2280,11 +2404,14 @@ namespace Mono.CSharp {
                                return Type.GetHashCode ();
                        }
 
-                       public override bool Equals (object obj)
+                       #region IEquatable<BoundInfo> Members
+
+                       public bool Equals (BoundInfo other)
                        {
-                               BoundInfo a = (BoundInfo) obj;
-                               return Type == a.Type && Kind == a.Kind;
+                               return Type == other.Type && Kind == other.Kind;
                        }
+
+                       #endregion
                }
 
                readonly TypeSpec[] unfixed_types;
@@ -2345,23 +2472,15 @@ namespace Mono.CSharp {
 
                        var a = bounds [index];
                        if (a == null) {
-                               a = new List<BoundInfo> ();
+                               a = new List<BoundInfo> (2);
+                               a.Add (bound);
                                bounds [index] = a;
-                       } else {
-                               if (a.Contains (bound))
-                                       return;
+                               return;
                        }
 
-                       //
-                       // SPEC: does not cover type inference using constraints
-                       //
-                       //if (TypeManager.IsGenericParameter (t)) {
-                       //    GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
-                       //    if (constraints != null) {
-                       //        //if (constraints.EffectiveBaseClass != null)
-                       //        //    t = constraints.EffectiveBaseClass;
-                       //    }
-                       //}
+                       if (a.Contains (bound))
+                               return;
+
                        a.Add (bound);
                }
                
@@ -2549,13 +2668,20 @@ namespace Mono.CSharp {
                                        }
 
                                        if (bound.Kind == BoundKind.Exact || cbound.Kind == BoundKind.Exact) {
-                                               if (cbound.Kind != BoundKind.Exact) {
+                                               if (cbound.Kind == BoundKind.Lower) {
                                                        if (!Convert.ImplicitConversionExists (ec, new TypeExpression (cbound.Type, Location.Null), bound.Type)) {
                                                                break;
                                                        }
 
                                                        continue;
                                                }
+                                               if (cbound.Kind == BoundKind.Upper) {
+                                                       if (!Convert.ImplicitConversionExists (ec, new TypeExpression (bound.Type, Location.Null), cbound.Type)) {
+                                                               break;
+                                                       }
+
+                                                       continue;
+                                               }
                                                
                                                if (bound.Kind != BoundKind.Exact) {
                                                        if (!Convert.ImplicitConversionExists (ec, new TypeExpression (bound.Type, Location.Null), cbound.Type)) {
@@ -2570,21 +2696,46 @@ namespace Mono.CSharp {
                                        }
 
                                        if (bound.Kind == BoundKind.Lower) {
-                                               if (!Convert.ImplicitConversionExists (ec, new TypeExpression (cbound.Type, Location.Null), bound.Type)) {
-                                                       break;
+                                               if (cbound.Kind == BoundKind.Lower) {
+                                                       if (!Convert.ImplicitConversionExists (ec, new TypeExpression (cbound.Type, Location.Null), bound.Type)) {
+                                                               break;
+                                                       }
+                                               } else {
+                                                       if (!Convert.ImplicitConversionExists (ec, new TypeExpression (bound.Type, Location.Null), cbound.Type)) {
+                                                               break;
+                                                       }
+
+                                                       bound = cbound;
                                                }
-                                       } else {
+
+                                               continue;
+                                       }
+
+                                       if (bound.Kind == BoundKind.Upper) {
                                                if (!Convert.ImplicitConversionExists (ec, new TypeExpression (bound.Type, Location.Null), cbound.Type)) {
                                                        break;
                                                }
+                                       } else {
+                                               throw new NotImplementedException ("variance conversion");
                                        }
                                }
 
                                if (cii != candidates_count)
                                        continue;
 
-                               if (best_candidate != null && best_candidate != bound.Type)
-                                       return false;
+                               //
+                               // We already have the best candidate, break if thet are different
+                               //
+                               // Dynamic is never ambiguous as we prefer dynamic over other best candidate types
+                               //
+                               if (best_candidate != null) {
+
+                                       if (best_candidate == InternalType.Dynamic)
+                                               continue;
+
+                                       if (bound.Type != InternalType.Dynamic && best_candidate != bound.Type)
+                                               return false;
+                               }
 
                                best_candidate = bound.Type;
                        }
@@ -2598,26 +2749,31 @@ namespace Mono.CSharp {
                }
                
                //
-               // Uses inferred types to inflate delegate type argument
+               // Uses inferred or partially infered types to inflate delegate type argument. Returns
+               // null when type parameter was not yet inferres
                //
                public TypeSpec InflateGenericArgument (TypeSpec parameter)
                {
                        var tp = parameter as TypeParameterSpec;
                        if (tp != null) {
                                //
-                               // Inflate method generic argument (MVAR) only
+                               // Type inference work on generic arguments (MVAR) only
                                //
                                if (!tp.IsMethodOwned)
                                        return parameter;
 
-                               return fixed_types [tp.DeclaredPosition];
+                               return fixed_types [tp.DeclaredPosition] ?? parameter;
                        }
 
                        var gt = parameter as InflatedTypeSpec;
                        if (gt != null) {
                                var inflated_targs = new TypeSpec [gt.TypeArguments.Length];
                                for (int ii = 0; ii < inflated_targs.Length; ++ii) {
-                                       inflated_targs[ii] = InflateGenericArgument (gt.TypeArguments [ii]);
+                                       var inflated = InflateGenericArgument (gt.TypeArguments [ii]);
+                                       if (inflated == null)
+                                               return null;
+
+                                       inflated_targs[ii] = inflated;
                                }
 
                                return gt.GetDefinition ().MakeGenericType (inflated_targs);
@@ -2755,7 +2911,7 @@ namespace Mono.CSharp {
                                        //
                                        if (unique_candidate_targs != null) {
                                                TypeSpec[] second_unique_candidate_targs = TypeManager.GetTypeArguments (u_candidate);
-                                               if (TypeSpecComparer.Default.Equals (unique_candidate_targs, second_unique_candidate_targs)) {
+                                               if (TypeSpecComparer.Equals (unique_candidate_targs, second_unique_candidate_targs)) {
                                                        unique_candidate_targs = second_unique_candidate_targs;
                                                        continue;
                                                }
@@ -2822,25 +2978,39 @@ namespace Mono.CSharp {
                        // then a lower-bound inference is made from U for Tb.
                        //
                        if (e is MethodGroupExpr) {
-                               // TODO: Or expression tree
-                               if (!TypeManager.IsDelegateType (t))
-                                       return 0;
+                               if (!TypeManager.IsDelegateType (t)) {
+                                       if (TypeManager.expression_type == null || t.MemberDefinition != TypeManager.expression_type.MemberDefinition)
+                                               return 0;
+
+                                       t = TypeManager.GetTypeArguments (t)[0];
+                               }
 
                                var invoke = Delegate.GetInvokeMethod (ec.Compiler, t);
                                TypeSpec rtype = invoke.ReturnType;
 
-                               if (!TypeManager.IsGenericType (rtype))
+                               if (!rtype.IsGenericParameter && !TypeManager.IsGenericType (rtype))
                                        return 0;
 
+                               // LAMESPEC: Standard does not specify that all methodgroup arguments
+                               // has to be fixed but it does not specify how to do recursive type inference
+                               // either. We choose the simple option and infer return type only
+                               // if all delegate generic arguments are fixed.
+                               TypeSpec[] param_types = new TypeSpec [invoke.Parameters.Count];
+                               for (int i = 0; i < param_types.Length; ++i) {
+                                       var inflated = InflateGenericArgument (invoke.Parameters.Types[i]);
+                                       if (inflated == null)
+                                               return 0;
+
+                                       param_types[i] = inflated;
+                               }
+
                                MethodGroupExpr mg = (MethodGroupExpr) e;
-                               Arguments args = DelegateCreation.CreateDelegateMethodArguments (invoke.Parameters, e.Location);
-                               mg = mg.OverloadResolve (ec, ref args, true, e.Location);
+                               Arguments args = DelegateCreation.CreateDelegateMethodArguments (invoke.Parameters, param_types, e.Location);
+                               mg = mg.OverloadResolve (ec, ref args, null, OverloadResolver.Restrictions.CovariantDelegate | OverloadResolver.Restrictions.ProbingOnly);
                                if (mg == null)
                                        return 0;
 
-                               // TODO: What should happen when return type is of generic type ?
-                               throw new NotImplementedException ();
-//                             return LowerBoundInference (null, rtype) + 1;
+                               return LowerBoundInference (mg.BestCandidate.ReturnType, rtype) + 1;
                        }
 
                        //