Mono.CSharp.Method.DefineTypeParameters C# (CSharp) Method

DefineTypeParameters() protected method

protected DefineTypeParameters ( ) : void
return void
        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 ());
                    }
                }
            }
        }