#endregion
- bool CheckConflictingInheritedConstraint (TypeSpec ba, TypeSpec bb, IMemberContext context, Location loc)
+ public static bool CheckConflictingInheritedConstraint (TypeParameterSpec spec, TypeSpec bb, IMemberContext context, Location loc)
{
- if (!TypeSpec.IsBaseClass (ba, bb, false) && !TypeSpec.IsBaseClass (bb, ba, false)) {
+ if (spec.HasSpecialClass && bb.IsStruct) {
context.Compiler.Report.Error (455, loc,
"Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
- tparam.Value,
- ba.GetSignatureForError (), bb.GetSignatureForError ());
+ spec.Name, "class", bb.GetSignatureForError ());
+
return false;
}
- return true;
+ return CheckConflictingInheritedConstraint (spec, spec.BaseType, bb, context, loc);
+ }
+
+ static bool CheckConflictingInheritedConstraint (TypeParameterSpec spec, TypeSpec ba, TypeSpec bb, IMemberContext context, Location loc)
+ {
+ if (ba == bb)
+ return true;
+
+ if (TypeSpec.IsBaseClass (ba, bb, false) || TypeSpec.IsBaseClass (bb, ba, false))
+ return true;
+
+ context.Compiler.Report.Error (455, loc,
+ "Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
+ spec.Name, ba.GetSignatureForError (), bb.GetSignatureForError ());
+ return false;
}
public void CheckGenericConstraints (IMemberContext context)
//
if (constraint_tp.HasTypeConstraint) {
if (spec.HasTypeConstraint || spec.HasSpecialStruct) {
- if (!CheckConflictingInheritedConstraint (spec.BaseType, constraint_tp.BaseType, context, constraint.Location))
+ if (!CheckConflictingInheritedConstraint (spec, constraint_tp.BaseType, context, constraint.Location))
continue;
} else {
for (int ii = 0; ii < tparam_types.Count; ++ii) {
if (!tparam_types[ii].HasTypeConstraint)
continue;
- if (!CheckConflictingInheritedConstraint (tparam_types[ii].BaseType, constraint_tp.BaseType, context, constraint.Location))
+ if (!CheckConflictingInheritedConstraint (spec, tparam_types[ii].BaseType, constraint_tp.BaseType, context, constraint.Location))
break;
}
}
#endregion
+ public void ChangeTypeArgumentToBaseType (int index)
+ {
+ BaseType = targs [index];
+ if (targs.Length == 1) {
+ targs = null;
+ } else {
+ var copy = new TypeSpec[targs.Length - 1];
+ if (index > 0)
+ Array.Copy (targs, copy, index);
+
+ Array.Copy (targs, index + 1, copy, index, targs.Length - index - 1);
+ targs = copy;
+ }
+ }
+
public string DisplayDebugInfo ()
{
var s = GetSignatureForError ();
for (int i = 0; i < ifaces.Count; ++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)
bool CheckConversion (IMemberContext mc, MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, TypeSpec ttype, Location loc)
{
- var expr = new EmptyExpression (atype);
- if (Convert.ImplicitStandardConversionExists (expr, ttype))
- return true;
+ if (TypeManager.IsValueType (atype)) {
+ if (atype == ttype || Convert.ImplicitBoxingConversion (null, atype, ttype) != null)
+ return true;
+ } else {
+ var expr = new EmptyExpression (atype);
+
+ if (atype.IsGenericParameter) {
+ if (Convert.ImplicitTypeParameterConversion (expr, ttype) != null)
+ return true;
+ }
+
+ if (Convert.ImplicitStandardConversionExists (expr, ttype))
+ return true;
+ }
//
// When partial/full type inference finds a dynamic type argument delay
//
if (base_tparams != null) {
var base_tparam = base_tparams[i];
- tp.Type.SpecialConstraint = base_tparam.SpecialConstraint;
+ var local_tparam = tp.Type;
+ local_tparam.SpecialConstraint = base_tparam.SpecialConstraint;
var inflator = new TypeParameterInflator (CurrentType, base_decl_tparams, base_targs);
- base_tparam.InflateConstraints (inflator, tp.Type);
- } else if (MethodData.implementing != null) {
+ base_tparam.InflateConstraints (inflator, local_tparam);
+
+ //
+ // Check all type argument constraints for possible collision
+ // introduced by inflating inherited constraints in this context
+ //
+ // Conflict example:
+ //
+ // class A<T> { virtual void Foo<U> () where U : class, T {} }
+ // class B : A<int> { override void Foo<U> {} }
+ //
+ var local_tparam_targs = local_tparam.TypeArguments;
+ if (local_tparam_targs != null) {
+ for (int ii = 0; ii < local_tparam_targs.Length; ++ii) {
+ var ta = local_tparam_targs [ii];
+ if (!ta.IsClass && !ta.IsStruct)
+ continue;
+
+ if (Constraints.CheckConflictingInheritedConstraint (local_tparam, ta, this, Location)) {
+ local_tparam.ChangeTypeArgumentToBaseType (ii);
+ }
+ }
+ }
+
+ continue;
+ }
+
+ if (MethodData.implementing != null) {
var base_tp = MethodData.implementing.Constraints[i];
if (!tp.Type.HasSameConstraintsImplementation (base_tp)) {
Report.SymbolRelatedToPreviousError (MethodData.implementing);