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)) {
if (base_method != null) {
base_tparams = base_method.GenericDefinition.TypeParameters;
if (base_method.DeclaringType.IsGeneric) {
base_decl_tparams = base_method.DeclaringType.MemberDefinition.TypeParameters;
var base_type_parent = CurrentType;
while (base_type_parent.BaseType != base_method.DeclaringType) {
base_type_parent = base_type_parent.BaseType;
}
base_targs = base_type_parent.BaseType.TypeArguments;
}
if (base_method.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.Select<TypeParameter, TypeSpec> (l => l.Type)).ToArray ();
} else {
base_decl_tparams = base_tparams;
base_targs = tparams.Select (l => l.Type).ToArray ();
}
}
} else if (MethodData.implementing != null) {
base_tparams = MethodData.implementing.GenericDefinition.TypeParameters;
if (MethodData.implementing.DeclaringType.IsGeneric) {
base_decl_tparams = MethodData.implementing.DeclaringType.MemberDefinition.TypeParameters;
foreach (var iface in Parent.CurrentType.Interfaces) {
if (iface == MethodData.implementing.DeclaringType) {
base_targs = iface.TypeArguments;
break;
}
}
}
}
}
for (int i = 0; i < tparams.Length; ++i) {
var tp = tparams[i];
if (!tp.ResolveConstraints (this))
continue;
//
// Copy base constraints for override/explicit methods
//
if (base_tparams != null) {
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
// 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);
Report.Error (425, Location,
"The constraints for type parameter `{0}' of method `{1}' must match the constraints for type parameter `{2}' of interface method `{3}'. Consider using an explicit interface implementation instead",
tp.GetSignatureForError (), GetSignatureForError (), base_tp.GetSignatureForError (), MethodData.implementing.GetSignatureForError ());
}
}
}
}