Update lower/upper type inference fixing to match the latest C# standard. Fixes ...
[mono.git] / mcs / mcs / generic.cs
index 13836984421c838a1ebb27f52be72b66091c30d6..5a24c6898b5f8d0744eef1d11519e4320171d818 100644 (file)
@@ -1787,7 +1787,7 @@ namespace Mono.CSharp {
                        return false;
                }
 
-               TypeParameterInflator CreateLocalInflator (IModuleContext context)
+               public TypeParameterInflator CreateLocalInflator (IModuleContext context)
                {
                        TypeParameterSpec[] tparams_full;
                        TypeSpec[] targs_full = targs;
@@ -3142,87 +3142,100 @@ namespace Mono.CSharp {
                        }
 
                        //
-                       // Determines a unique type from which there is
-                       // a standard implicit conversion to all the other
-                       // candidate types.
+                       // The set of candidate types Uj starts out as the set of
+                       // all types in the set of bounds for Xi
                        //
-                       TypeSpec best_candidate = null;
-                       int cii;
-                       int candidates_count = candidates.Count;
-                       for (int ci = 0; ci < candidates_count; ++ci) {
-                               BoundInfo bound = candidates [ci];
-                               for (cii = 0; cii < candidates_count; ++cii) {
-                                       if (cii == ci)
-                                               continue;
+                       var applicable = new bool [candidates.Count];
+                       for (int ci = 0; ci < applicable.Length; ++ci)
+                               applicable [ci] = true;
+
+                       for (int ci = 0; ci < applicable.Length; ++ci) {
+                               var bound = candidates [ci];
+                               int cii = 0;
+
+                               switch (bound.Kind) {
+                               case BoundKind.Exact:
+                                       for (; cii != applicable.Length; ++cii) {
+                                               if (ci == cii)
+                                                       continue;
 
-                                       BoundInfo cbound = candidates[cii];
-                                       
-                                       // Same type parameters with different bounds
-                                       if (cbound.Type == bound.Type) {
-                                               if (bound.Kind != BoundKind.Exact)
-                                                       bound = cbound;
+                                               if (!applicable[cii])
+                                                       break;
 
-                                               continue;
+                                               //
+                                               // For each exact bound U of Xi all types Uj which are not identical
+                                               // to U are removed from the candidate set
+                                               //
+                                               if (candidates [cii].Type != bound.Type)
+                                                       applicable[cii] = false;
                                        }
 
-                                       if (bound.Kind == BoundKind.Exact || cbound.Kind == BoundKind.Exact) {
-                                               if (cbound.Kind == BoundKind.Lower) {
-                                                       if (!Convert.ImplicitConversionExists (ec, cbound.GetTypeExpression (), bound.Type)) {
-                                                               break;
-                                                       }
-
+                                       break;
+                               case BoundKind.Lower:
+                                       for (; cii != applicable.Length; ++cii) {
+                                               if (ci == cii)
                                                        continue;
-                                               }
-                                               if (cbound.Kind == BoundKind.Upper) {
-                                                       if (!Convert.ImplicitConversionExists (ec, bound.GetTypeExpression (), cbound.Type)) {
-                                                               break;
-                                                       }
 
-                                                       continue;
+                                               if (!applicable[cii])
+                                                       break;
+
+                                               //
+                                               // For each lower bound U of Xi all types Uj to which there is not an implicit conversion
+                                               // from U are removed from the candidate set
+                                               //
+                                               if (!Convert.ImplicitConversionExists (ec, bound.GetTypeExpression (), candidates [cii].Type)) {
+                                                       applicable[cii] = false;
                                                }
-                                               
-                                               if (bound.Kind != BoundKind.Exact) {
-                                                       if (!Convert.ImplicitConversionExists (ec, bound.GetTypeExpression (), cbound.Type)) {
-                                                               break;
-                                                       }
+                                       }
+
+                                       break;
 
-                                                       bound = cbound;
+                               case BoundKind.Upper:
+                                       for (; cii != applicable.Length; ++cii) {
+                                               if (ci == cii)
                                                        continue;
-                                               }
-                                               
-                                               break;
+
+                                               if (!applicable[cii])
+                                                       break;
+
+                                               //
+                                               // For each upper bound U of Xi all types Uj from which there is not an implicit conversion
+                                               // to U are removed from the candidate set
+                                               //
+                                               if (!Convert.ImplicitConversionExists (ec, candidates[cii].GetTypeExpression (), bound.Type))
+                                                       applicable[cii] = false;
                                        }
 
-                                       if (bound.Kind == BoundKind.Lower) {
-                                               if (cbound.Kind == BoundKind.Lower) {
-                                                       if (!Convert.ImplicitConversionExists (ec, cbound.GetTypeExpression (), bound.Type)) {
-                                                               break;
-                                                       }
-                                               } else {
-                                                       if (!Convert.ImplicitConversionExists (ec, bound.GetTypeExpression (), cbound.Type)) {
-                                                               break;
-                                                       }
+                                       break;
+                               }
+                       }
 
-                                                       bound = cbound;
-                                               }
+                       TypeSpec best_candidate = null;
+                       for (int ci = 0; ci < applicable.Length; ++ci) {
+                               if (!applicable[ci])
+                                       continue;
 
+                               var bound = candidates [ci];
+                               if (bound.Type == best_candidate)
+                                       continue;
+
+                               int cii = 0;
+                               for (; cii < applicable.Length; ++cii) {
+                                       if (ci == cii)
                                                continue;
-                                       }
 
-                                       if (bound.Kind == BoundKind.Upper) {
-                                               if (!Convert.ImplicitConversionExists (ec, bound.GetTypeExpression (), cbound.Type)) {
-                                                       break;
-                                               }
-                                       } else {
-                                               throw new NotImplementedException ("variance conversion");
-                                       }
+                                       if (!applicable[cii])
+                                               continue;
+
+                                       if (!Convert.ImplicitConversionExists (ec, candidates[cii].GetTypeExpression (), bound.Type))
+                                               break;
                                }
 
-                               if (cii != candidates_count)
+                               if (cii != applicable.Length)
                                        continue;
 
                                //
-                               // We already have the best candidate, break if thet are different
+                               // We already have the best candidate, break if it's different (non-unique)
                                //
                                // Dynamic is never ambiguous as we prefer dynamic over other best candidate types
                                //