}
//
- // 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
//
return typeof (T) == typeof (object);
}
+ public static bool CovContCont<T> (ICovariant<T> e1, IContravariant<T> e2, IContravariant<T> e3)
+ {
+ Console.WriteLine (typeof (T));
+ return typeof (T) == typeof (string);
+ }
+
+ public static bool ContCovContCov<T> (IContravariant<T> e1, ICovariant<T> e2, IContravariant<T> e3, ICovariant<T> e4)
+ {
+ Console.WriteLine (typeof (T));
+ return typeof (T) == typeof (string);
+ }
+
+ public static bool CovCovCont<T> (ICovariant<T> e1, ICovariant<T> e2, IContravariant<T> e3)
+ {
+ Console.WriteLine (typeof (T));
+ return typeof (T) == typeof (string);
+ }
+
public static int Main ()
{
+
ICovariant<object> a = null;
ICovariant<string> b = null;
if (!Covariant (a, b))
if (!Contra (a_1, b_1))
return 2;
+ ICovariant<string> a_2 = null;
+ IContravariant<object> b_2 = null;
+ IContravariant<string> c_2 = null;
+ if (!CovContCont (a_2, b_2, c_2))
+ return 3;
+
+ IContravariant<object> a_3 = null;
+ ICovariant<string> b_3 = null;
+ IContravariant<string> c_3 = null;
+ ICovariant<string> d_3 = null;
+ if (!ContCovContCov (a_3, b_3, c_3, d_3))
+ return 4;
+
+ Console.WriteLine ("ok");
return 0;
}
}