public override bool Define()
{
const Modifiers RequiredModifiers = Modifiers.PUBLIC | Modifiers.STATIC;
if ((ModFlags & RequiredModifiers) != RequiredModifiers){
Report.Error (558, Location, "User-defined operator `{0}' must be declared static and public", GetSignatureForError ());
}
if (!base.Define ())
return false;
if (block != null && block.IsIterator) {
//
// Current method is turned into automatically generated
// wrapper which creates an instance of iterator
//
Iterator.CreateIterator (this, Parent.PartialContainer, ModFlags, Compiler);
ModFlags |= Modifiers.DEBUGGER_HIDDEN;
}
// imlicit and explicit operator of same types are not allowed
if (OperatorType == OpType.Explicit)
Parent.MemberCache.CheckExistingMembersOverloads (this, GetMetadataName (OpType.Implicit), parameters);
else if (OperatorType == OpType.Implicit)
Parent.MemberCache.CheckExistingMembersOverloads (this, GetMetadataName (OpType.Explicit), parameters);
TypeSpec declaring_type = Parent.CurrentType;
TypeSpec return_type = MemberType;
TypeSpec first_arg_type = ParameterTypes [0];
TypeSpec first_arg_type_unwrap = first_arg_type;
if (TypeManager.IsNullableType (first_arg_type))
first_arg_type_unwrap = TypeManager.GetTypeArguments (first_arg_type) [0];
TypeSpec return_type_unwrap = return_type;
if (TypeManager.IsNullableType (return_type))
return_type_unwrap = TypeManager.GetTypeArguments (return_type) [0];
//
// Rules for conversion operators
//
if (OperatorType == OpType.Implicit || OperatorType == OpType.Explicit) {
if (first_arg_type_unwrap == return_type_unwrap && first_arg_type_unwrap == declaring_type) {
Report.Error (555, Location,
"User-defined operator cannot take an object of the enclosing type and convert to an object of the enclosing type");
return false;
}
TypeSpec conv_type;
if (declaring_type == return_type || declaring_type == return_type_unwrap) {
conv_type = first_arg_type;
} else if (declaring_type == first_arg_type || declaring_type == first_arg_type_unwrap) {
conv_type = return_type;
} else {
Report.Error (556, Location,
"User-defined conversion must convert to or from the enclosing type");
return false;
}
if (conv_type == InternalType.Dynamic) {
Report.Error (1964, Location,
"User-defined conversion `{0}' cannot convert to or from the dynamic type",
GetSignatureForError ());
return false;
}
if (conv_type.IsInterface) {
Report.Error (552, Location, "User-defined conversion `{0}' cannot convert to or from an interface type",
GetSignatureForError ());
return false;
}
if (conv_type.IsClass) {
if (TypeSpec.IsBaseClass (declaring_type, conv_type, true)) {
Report.Error (553, Location, "User-defined conversion `{0}' cannot convert to or from a base class",
GetSignatureForError ());
return false;
}
if (TypeSpec.IsBaseClass (conv_type, declaring_type, false)) {
Report.Error (554, Location, "User-defined conversion `{0}' cannot convert to or from a derived class",
GetSignatureForError ());
return false;
}
}
} else if (OperatorType == OpType.LeftShift || OperatorType == OpType.RightShift) {
if (first_arg_type != declaring_type || parameters.Types[1] != TypeManager.int32_type) {
Report.Error (564, Location, "Overloaded shift operator must have the type of the first operand be the containing type, and the type of the second operand must be int");
return false;
}
} else if (parameters.Count == 1) {
// Checks for Unary operators
if (OperatorType == OpType.Increment || OperatorType == OpType.Decrement) {
if (return_type != declaring_type && !TypeSpec.IsBaseClass (return_type, declaring_type, false)) {
Report.Error (448, Location,
"The return type for ++ or -- operator must be the containing type or derived from the containing type");
return false;
}
if (first_arg_type != declaring_type) {
Report.Error (
559, Location, "The parameter type for ++ or -- operator must be the containing type");
return false;
}
}
if (first_arg_type_unwrap != declaring_type) {
Report.Error (562, Location,
"The parameter type of a unary operator must be the containing type");
return false;
}
if (OperatorType == OpType.True || OperatorType == OpType.False) {
if (return_type != TypeManager.bool_type) {
Report.Error (
215, Location,
"The return type of operator True or False " +
"must be bool");
return false;
}
}
} else if (first_arg_type_unwrap != declaring_type) {
// Checks for Binary operators
var second_arg_type = ParameterTypes[1];
if (TypeManager.IsNullableType (second_arg_type))
second_arg_type = TypeManager.GetTypeArguments (second_arg_type)[0];
if (second_arg_type != declaring_type) {
Report.Error (563, Location,
"One of the parameters of a binary operator must be the containing type");
return false;
}
}
return true;
}