Mono.CSharp.Operator.Define C# (CSharp) Method

Define() public method

public Define ( ) : bool
return bool
        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;
        }