protected virtual void DefineTypeParameters ()
{
var tparams = CurrentTypeParameters;
TypeParameterSpec[] base_tparams = null;
TypeParameterSpec[] base_decl_tparams = TypeParameterSpec.EmptyTypes;
TypeSpec[] base_targs = TypeSpec.EmptyTypes;
if (((ModFlags & Modifiers.OVERRIDE) != 0 || IsExplicitImpl)) {
MethodSpec base_override = base_method ?? MethodData.implementing;
if (base_override != null) {
base_tparams = base_override.GenericDefinition.TypeParameters;
if (base_override.DeclaringType.IsGeneric) {
base_decl_tparams = base_override.DeclaringType.MemberDefinition.TypeParameters;
if (base_method != null) {
var base_type_parent = CurrentType;
while (base_type_parent.BaseType != base_override.DeclaringType) {
base_type_parent = base_type_parent.BaseType;
}
base_targs = base_type_parent.BaseType.TypeArguments;
} else {
foreach (var iface in Parent.CurrentType.Interfaces) {
if (iface == base_override.DeclaringType) {
base_targs = iface.TypeArguments;
break;
}
}
}
}
if (base_override.IsGeneric) {
ObsoleteAttribute oa;
foreach (var base_tp in base_tparams) {
oa = base_tp.BaseType.GetAttributeObsolete ();
if (oa != null) {
AttributeTester.Report_ObsoleteMessage (oa, base_tp.BaseType.GetSignatureForError (), Location, Report);
}
if (base_tp.InterfacesDefined != null) {
foreach (var iface in base_tp.InterfacesDefined) {
oa = iface.GetAttributeObsolete ();
if (oa != null) {
AttributeTester.Report_ObsoleteMessage (oa, iface.GetSignatureForError (), Location, Report);
}
}
}
}
if (base_decl_tparams.Length != 0) {
base_decl_tparams = base_decl_tparams.Concat (base_tparams).ToArray ();
base_targs = base_targs.Concat (tparams.Types).ToArray ();
} else {
base_decl_tparams = base_tparams;
base_targs = tparams.Types;
}
}
}
}
for (int i = 0; i < tparams.Count; ++i) {
var tp = tparams [i];
if (base_tparams == null) {
tp.ResolveConstraints (this);
continue;
}
//
// Copy base constraints for override/explicit methods
//
var base_tparam = base_tparams [i];
var local_tparam = tp.Type;
local_tparam.SpecialConstraint = base_tparam.SpecialConstraint;
var inflator = new TypeParameterInflator (this, CurrentType, base_decl_tparams, base_targs);
base_tparam.InflateConstraints (inflator, local_tparam);
//
// Check all type argument constraints for possible collision or unification
// 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;
TypeSpec[] unique_tparams = null;
for (int iii = ii + 1; iii < local_tparam_targs.Length; ++iii) {
//
// Remove any identical or unified constraint types
//
var tparam_checked = local_tparam_targs [iii];
if (TypeSpecComparer.IsEqual (ta, tparam_checked) || TypeSpec.IsBaseClass (ta, tparam_checked, false)) {
unique_tparams = new TypeSpec[local_tparam_targs.Length - 1];
Array.Copy (local_tparam_targs, 0, unique_tparams, 0, iii);
Array.Copy (local_tparam_targs, iii + 1, unique_tparams, iii, local_tparam_targs.Length - iii - 1);
} else if (!TypeSpec.IsBaseClass (tparam_checked, ta, false)) {
Constraints.Error_ConflictingConstraints (this, local_tparam, ta, tparam_checked, Location);
}
}
if (unique_tparams != null) {
local_tparam_targs = unique_tparams;
local_tparam.TypeArguments = local_tparam_targs;
continue;
}
Constraints.CheckConflictingInheritedConstraint (local_tparam, ta, this, Location);
}
}
}
if (base_tparams == null && MethodData != null && MethodData.implementing != null) {
CheckImplementingMethodConstraints (Parent, spec, MethodData.implementing);
}
}