From b5bc9d75d52ea01ecb3ae6253554ca063806bd46 Mon Sep 17 00:00:00 2001 From: Marek Safar Date: Sun, 27 Oct 2013 21:37:34 +0100 Subject: [PATCH] Update lower/upper type inference fixing to match the latest C# standard. Fixes #15505 --- mcs/mcs/generic.cs | 133 ++++++++++++++++++--------------- mcs/tests/gtest-variance-11.cs | 33 ++++++++ mcs/tests/ver-il-net_4_5.xml | 11 ++- 3 files changed, 116 insertions(+), 61 deletions(-) diff --git a/mcs/mcs/generic.cs b/mcs/mcs/generic.cs index 96d88b544f2..5a24c6898b5 100644 --- a/mcs/mcs/generic.cs +++ b/mcs/mcs/generic.cs @@ -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 // diff --git a/mcs/tests/gtest-variance-11.cs b/mcs/tests/gtest-variance-11.cs index 35c2b774488..110044f0a5d 100644 --- a/mcs/tests/gtest-variance-11.cs +++ b/mcs/tests/gtest-variance-11.cs @@ -22,8 +22,27 @@ class D return typeof (T) == typeof (object); } + public static bool CovContCont (ICovariant e1, IContravariant e2, IContravariant e3) + { + Console.WriteLine (typeof (T)); + return typeof (T) == typeof (string); + } + + public static bool ContCovContCov (IContravariant e1, ICovariant e2, IContravariant e3, ICovariant e4) + { + Console.WriteLine (typeof (T)); + return typeof (T) == typeof (string); + } + + public static bool CovCovCont (ICovariant e1, ICovariant e2, IContravariant e3) + { + Console.WriteLine (typeof (T)); + return typeof (T) == typeof (string); + } + public static int Main () { + ICovariant a = null; ICovariant b = null; if (!Covariant (a, b)) @@ -34,6 +53,20 @@ class D if (!Contra (a_1, b_1)) return 2; + ICovariant a_2 = null; + IContravariant b_2 = null; + IContravariant c_2 = null; + if (!CovContCont (a_2, b_2, c_2)) + return 3; + + IContravariant a_3 = null; + ICovariant b_3 = null; + IContravariant c_3 = null; + ICovariant d_3 = null; + if (!ContCovContCov (a_3, b_3, c_3, d_3)) + return 4; + + Console.WriteLine ("ok"); return 0; } } diff --git a/mcs/tests/ver-il-net_4_5.xml b/mcs/tests/ver-il-net_4_5.xml index 480713219dd..44afaf1727b 100644 --- a/mcs/tests/ver-il-net_4_5.xml +++ b/mcs/tests/ver-il-net_4_5.xml @@ -28755,7 +28755,7 @@ - 58 + 137 7 @@ -28766,6 +28766,15 @@ 49 + + 49 + + + 49 + + + 49 + -- 2.25.1