public EntityHandle GetMethodRef(MethodDesc method)
        {
            if (_methodRefs.TryGetValue(method, out var handle))
            {
                return(handle);
            }

            EntityHandle methodHandle;

            if (method.HasInstantiation && (method.GetMethodDefinition() != method))
            {
                EntityHandle uninstantiatedHandle = GetMethodRef(method.GetMethodDefinition());
                BlobBuilder  methodSpecSig        = new BlobBuilder();
                BlobEncoder  methodSpecEncoder    = new BlobEncoder(methodSpecSig);
                methodSpecEncoder.MethodSpecificationSignature(method.Instantiation.Length);
                foreach (var type in method.Instantiation)
                {
                    EncodeType(methodSpecSig, type, EmbeddedSignatureDataEmitter.EmptySingleton);
                }

                var methodSpecSigHandle = _metadataBuilder.GetOrAddBlob(methodSpecSig);
                methodHandle = _metadataBuilder.AddMethodSpecification(uninstantiatedHandle, methodSpecSigHandle);
            }
            else
            {
                EntityHandle typeHandle = GetTypeRef((MetadataType)method.OwningType);
                StringHandle methodName = _metadataBuilder.GetOrAddString(method.Name);
                var          sig        = method.GetTypicalMethodDefinition().Signature;

                EmbeddedSignatureDataEmitter signatureDataEmitter;
                if (sig.HasEmbeddedSignatureData)
                {
                    signatureDataEmitter = new EmbeddedSignatureDataEmitter(sig.GetEmbeddedSignatureData(), this);
                }
                else
                {
                    signatureDataEmitter = EmbeddedSignatureDataEmitter.EmptySingleton;
                }

                BlobBuilder memberRefSig = new BlobBuilder();
                EncodeMethodSignature(memberRefSig, sig, signatureDataEmitter);

                if (!signatureDataEmitter.Complete)
                {
                    throw new ArgumentException();
                }

                var sigBlob = _metadataBuilder.GetOrAddBlob(memberRefSig);
                methodHandle = _metadataBuilder.AddMemberReference(typeHandle, methodName, sigBlob);
            }

            _methodRefs.Add(method, methodHandle);
            return(methodHandle);
        }
Example #2
0
        public static bool CheckConstraints(this MethodDesc method)
        {
            if (!method.OwningType.CheckConstraints())
            {
                return(false);
            }

            // Non-generic methods always pass constraints check
            if (!method.HasInstantiation)
            {
                return(true);
            }

            MethodDesc uninstantiatedMethod = method.GetMethodDefinition();

            for (int i = 0; i < uninstantiatedMethod.Instantiation.Length; i++)
            {
                if (!VerifyGenericParamConstraint(method.OwningType.Instantiation, method.Instantiation, (GenericParameterDesc)uninstantiatedMethod.Instantiation[i], method.Instantiation[i]))
                {
                    return(false);
                }
            }

            return(true);
        }
Example #3
0
        public MethodIL GetMethodIL(MethodDesc method)
        {
            if (method is EcmaMethod)
            {
                // TODO: Workaround: we should special case methods with Intrinsic attribute, but since
                //       CoreLib source is still not in the repo, we have to work with what we have, which is
                //       an MCG attribute on the type itself...
                if (((MetadataType)method.OwningType).HasCustomAttribute("System.Runtime.InteropServices", "McgIntrinsicsAttribute"))
                {
                    if (method.Name == "Call")
                    {
                        return CalliIntrinsic.EmitIL(method);
                    }
                }

                if (method.IsIntrinsic)
                {
                    MethodIL result = TryGetIntrinsicMethodIL(method);
                    if (result != null)
                        return result;
                }

                if (method.IsPInvoke)
                {
                    return PInvokeMarshallingILEmitter.EmitIL(method);
                }

                return EcmaMethodIL.Create((EcmaMethod)method);
            }
            else
            if (method is MethodForInstantiatedType)
            {
                var methodDefinitionIL = GetMethodIL(method.GetTypicalMethodDefinition());
                if (methodDefinitionIL == null)
                    return null;
                return new InstantiatedMethodIL(methodDefinitionIL, method.OwningType.Instantiation, new Instantiation());
            }
            else
            if (method is InstantiatedMethod)
            {
                var methodDefinitionIL = GetMethodIL(method.GetMethodDefinition());
                if (methodDefinitionIL == null)
                    return null;
                return new InstantiatedMethodIL(methodDefinitionIL, new Instantiation(), method.Instantiation);
            }
            else
            if (method is ILStubMethod)
            {
                return ((ILStubMethod)method).EmitIL();
            }
            else
            if (method is ArrayMethod)
            {
                return ArrayMethodILEmitter.EmitIL((ArrayMethod)method);
            }
            else
            {
                return null;
            }
        }
Example #4
0
        /// <summary>
        /// Try to resolve a given virtual static interface method on a given constrained type and return the resolved method or null when not found.
        /// </summary>
        /// <param name="constrainedType">Type to attempt method resolution on</param>
        /// <param name="interfaceMethod">Method to resolve</param>
        /// <returns>MethodDesc of the resolved method or null when not found (runtime lookup must be used)</returns>
        private static MethodDesc TryResolveVirtualStaticMethodOnThisType(MetadataType constrainedType, MethodDesc interfaceMethod)
        {
            Debug.Assert(interfaceMethod.Signature.IsStatic);

            MethodImplRecord[] possibleImpls = constrainedType.FindMethodsImplWithMatchingDeclName(interfaceMethod.Name);
            if (possibleImpls == null)
            {
                return(null);
            }

            MethodDesc interfaceMethodDefinition = interfaceMethod.GetMethodDefinition();

            foreach (MethodImplRecord methodImpl in possibleImpls)
            {
                if (methodImpl.Decl == interfaceMethodDefinition)
                {
                    MethodDesc resolvedMethodImpl = methodImpl.Body;
                    if (interfaceMethod != interfaceMethodDefinition)
                    {
                        resolvedMethodImpl = resolvedMethodImpl.MakeInstantiatedMethod(interfaceMethod.Instantiation);
                    }
                    return(resolvedMethodImpl);
                }
            }

            return(null);
        }
Example #5
0
        private void AppendMethodSignature(StringBuilder sb, MethodDesc method)
        {
            // If this is an instantiated generic method, the formatted signature should
            // be uninstantiated (e.g. "void Foo::Bar<int>(!!0 param)", not "void Foo::Bar<int>(int param)")
            MethodSignature signature = method.GetMethodDefinition().Signature;

            AppendSignaturePrefix(sb, signature);
            sb.Append(' ');
            AppendOwningType(sb, method.OwningType);
            sb.Append("::");
            sb.Append(method.Name);

            if (method.HasInstantiation)
            {
                sb.Append('<');

                for (int i = 0; i < method.Instantiation.Length; i++)
                {
                    if (i != 0)
                        sb.Append(", ");
                    _typeNameFormatter.AppendNameWithValueClassPrefix(sb, method.Instantiation[i]);
                }

                sb.Append('>');
            }

            sb.Append('(');
            AppendSignatureArgumentList(sb, signature);
            sb.Append(')');
        }
Example #6
0
        /// <summary>
        /// Resolve a virtual function call (to a virtual method, not an interface method)
        /// </summary>
        /// <param name="targetMethod"></param>
        /// <param name="objectType"></param>
        /// <returns>The override of the virtual method that should be called</returns>
        private static MethodDesc FindVirtualFunctionTargetMethodOnObjectType(MethodDesc targetMethod, MetadataType objectType)
        {
            // Step 1, convert objectType to uninstantiated form
            MetadataType     uninstantiatedType      = objectType;
            MethodDesc       initialTargetMethod     = targetMethod;
            InstantiatedType initialInstantiatedType = objectType as InstantiatedType;

            if (initialInstantiatedType != null)
            {
                uninstantiatedType = (MetadataType)initialInstantiatedType.GetTypeDefinition();
            }

            // Step 2, convert targetMethod to method in type hierarchy of uninstantiated form
            targetMethod = targetMethod.GetMethodDefinition();
            if (uninstantiatedType != objectType)
            {
                targetMethod = uninstantiatedType.FindMethodOnTypeWithMatchingTypicalMethod(targetMethod);
            }

            // Step 3, find unification group of target method
            UnificationGroup group = new UnificationGroup(FindSlotDefiningMethodForVirtualMethod(targetMethod));

            FindBaseUnificationGroup(uninstantiatedType, group);

            // Step 4, name/sig match virtual function resolve
            MethodDesc resolutionTarget = FindNameSigOverrideForVirtualMethod(group.DefiningMethod, uninstantiatedType);

            if (resolutionTarget == null)
            {
                return(null);
            }

            // Step 5, convert resolution target from uninstantiated form target to objecttype target,
            // and instantiate as appropriate
            if (uninstantiatedType != objectType)
            {
                resolutionTarget = objectType.FindMethodOnTypeWithMatchingTypicalMethod(resolutionTarget);
            }
            if (initialTargetMethod.HasInstantiation)
            {
                resolutionTarget = resolutionTarget.MakeInstantiatedMethod(initialTargetMethod.Instantiation);
            }

            return(resolutionTarget);
        }
Example #7
0
        public virtual MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation)
        {
            Instantiation instantiation = Instantiation;

            TypeDesc[] clone = null;

            for (int i = 0; i < instantiation.Length; i++)
            {
                TypeDesc uninst = instantiation[i];
                TypeDesc inst   = uninst.InstantiateSignature(typeInstantiation, methodInstantiation);
                if (inst != uninst)
                {
                    if (clone == null)
                    {
                        clone = new TypeDesc[instantiation.Length];
                        for (int j = 0; j < clone.Length; j++)
                        {
                            clone[j] = instantiation[j];
                        }
                    }
                    clone[i] = inst;
                }
            }

            MethodDesc method = this;

            TypeDesc owningType             = method.OwningType;
            TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation);

            if (owningType != instantiatedOwningType)
            {
                method = Context.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), (InstantiatedType)instantiatedOwningType);
                if (clone == null && instantiation.Length != 0)
                {
                    return(Context.GetInstantiatedMethod(method, instantiation));
                }
            }

            return((clone == null) ? method : Context.GetInstantiatedMethod(method.GetMethodDefinition(), new Instantiation(clone)));
        }
Example #8
0
        public static DefaultInterfaceMethodResolution ResolveVariantInterfaceMethodToDefaultImplementationOnType(MethodDesc interfaceMethod, MetadataType currentType, out MethodDesc impl)
        {
            Debug.Assert(interfaceMethod.Signature.IsStatic);

            MetadataType interfaceType  = (MetadataType)interfaceMethod.OwningType;
            bool         foundInterface = IsInterfaceImplementedOnType(currentType, interfaceType);

            if (foundInterface)
            {
                DefaultInterfaceMethodResolution resolution = ResolveInterfaceMethodToDefaultImplementationOnType(interfaceMethod, currentType, out impl);
                if (resolution != DefaultInterfaceMethodResolution.None)
                {
                    return(resolution);
                }
            }

            MethodDesc interfaceMethodDefinition = interfaceMethod.GetMethodDefinition();

            foreach (TypeDesc iface in currentType.RuntimeInterfaces)
            {
                if (iface.HasSameTypeDefinition(interfaceType) && iface.CanCastTo(interfaceType))
                {
                    MethodDesc variantMethod = iface.FindMethodOnTypeWithMatchingTypicalMethod(interfaceMethodDefinition);
                    Debug.Assert(variantMethod != null);
                    if (interfaceMethod != interfaceMethodDefinition)
                    {
                        variantMethod = variantMethod.MakeInstantiatedMethod(interfaceMethod.Instantiation);
                    }
                    DefaultInterfaceMethodResolution resolution = ResolveInterfaceMethodToDefaultImplementationOnType(variantMethod, currentType, out impl);
                    if (resolution != DefaultInterfaceMethodResolution.None)
                    {
                        return(resolution);
                    }
                }
            }

            impl = null;
            return(DefaultInterfaceMethodResolution.None);
        }
Example #9
0
        /// <summary>
        /// Gets the shared runtime determined form of the method. This is a canonical form of the method
        /// where generic arguments of the method and the owning type have been converted to runtime determined types.
        /// </summary>
        public MethodDesc GetSharedRuntimeFormMethodTarget()
        {
            MethodDesc result = this;

            DefType owningType = OwningType as DefType;

            if (owningType != null)
            {
                // First find the method on the shared runtime form of the owning type
                DefType sharedRuntimeOwningType = owningType.ConvertToSharedRuntimeDeterminedForm();
                if (sharedRuntimeOwningType != owningType)
                {
                    result = Context.GetMethodForInstantiatedType(
                        GetTypicalMethodDefinition(), (InstantiatedType)sharedRuntimeOwningType);
                }

                // Now convert the method instantiation to the shared runtime form
                if (result.HasInstantiation)
                {
                    MethodDesc uninstantiatedMethod = result.GetMethodDefinition();

                    bool          changed;
                    Instantiation sharedInstantiation = RuntimeDeterminedTypeUtilities.ConvertInstantiationToSharedRuntimeForm(
                        Instantiation, uninstantiatedMethod.Instantiation, out changed);

                    // If either the instantiation changed, or we switched the owning type, we need to find the matching
                    // instantiated method.
                    if (changed || result != this)
                    {
                        result = Context.GetInstantiatedMethod(uninstantiatedMethod, sharedInstantiation);
                    }
                }
            }

            return(result);
        }
Example #10
0
        /// <summary>
        /// Attempts to resolve constrained call to <paramref name="interfaceMethod"/> into a concrete non-unboxing
        /// method on <paramref name="constrainedType"/>.
        /// The ability to resolve constraint methods is affected by the degree of code sharing we are performing
        /// for generic code.
        /// </summary>
        /// <returns>The resolved method or null if the constraint couldn't be resolved.</returns>
        public static MethodDesc TryResolveConstraintMethodApprox(this TypeDesc constrainedType, TypeDesc interfaceType, MethodDesc interfaceMethod, out bool forceRuntimeLookup)
        {
            forceRuntimeLookup = false;

            // We can't resolve constraint calls effectively for reference types, and there's
            // not a lot of perf. benefit in doing it anyway.
            if (!constrainedType.IsValueType)
            {
                return(null);
            }

            // Non-virtual methods called through constraints simply resolve to the specified method without constraint resolution.
            if (!interfaceMethod.IsVirtual)
            {
                return(null);
            }

            MethodDesc method;

            MethodDesc genInterfaceMethod = interfaceMethod.GetMethodDefinition();

            if (genInterfaceMethod.OwningType.IsInterface)
            {
                // Sometimes (when compiling shared generic code)
                // we don't have enough exact type information at JIT time
                // even to decide whether we will be able to resolve to an unboxed entry point...
                // To cope with this case we always go via the helper function if there's any
                // chance of this happening by checking for all interfaces which might possibly
                // be compatible with the call (verification will have ensured that
                // at least one of them will be)

                // Enumerate all potential interface instantiations

                // TODO: this code assumes no shared generics
                Debug.Assert(interfaceType == interfaceMethod.OwningType);

                method = constrainedType.ResolveInterfaceMethodToVirtualMethodOnType(genInterfaceMethod);
            }
            else if (genInterfaceMethod.IsVirtual)
            {
                method = constrainedType.FindVirtualFunctionTargetMethodOnObjectType(genInterfaceMethod);
            }
            else
            {
                // The method will be null if calling a non-virtual instance
                // methods on System.Object, i.e. when these are used as a constraint.
                method = null;
            }

            if (method == null)
            {
                // Fall back to VSD
                return(null);
            }

            //#TryResolveConstraintMethodApprox_DoNotReturnParentMethod
            // Only return a method if the value type itself declares the method,
            // otherwise we might get a method from Object or System.ValueType
            if (!method.OwningType.IsValueType)
            {
                // Fall back to VSD
                return(null);
            }

            // We've resolved the method, ignoring its generic method arguments
            // If the method is a generic method then go and get the instantiated descriptor
            if (interfaceMethod.HasInstantiation)
            {
                method = method.MakeInstantiatedMethod(interfaceMethod.Instantiation);
            }

            Debug.Assert(method != null);
            //assert(!pMD->IsUnboxingStub());

            return(method);
        }
Example #11
0
        /// <summary>
        /// Attempts to resolve constrained call to <paramref name="interfaceMethod"/> into a concrete non-unboxing
        /// method on <paramref name="constrainedType"/>.
        /// The ability to resolve constraint methods is affected by the degree of code sharing we are performing
        /// for generic code.
        /// </summary>
        /// <returns>The resolved method or null if the constraint couldn't be resolved.</returns>
        static public MethodDesc TryResolveConstraintMethodApprox(this MetadataType constrainedType, TypeDesc interfaceType, MethodDesc interfaceMethod, out bool forceRuntimeLookup)
        {
            forceRuntimeLookup = false;

            // We can't resolve constraint calls effectively for reference types, and there's
            // not a lot of perf. benefit in doing it anyway.
            if (!constrainedType.IsValueType)
            {
                return null;
            }

            // Non-virtual methods called through constraints simply resolve to the specified method without constraint resolution.
            if (!interfaceMethod.IsVirtual)
            {
                return null;
            }

            MetadataType canonMT = constrainedType;

            MethodDesc method;

            MethodDesc genInterfaceMethod = interfaceMethod.GetMethodDefinition();
            if (genInterfaceMethod.OwningType.IsInterface)
            {
                // Sometimes (when compiling shared generic code)
                // we don't have enough exact type information at JIT time
                // even to decide whether we will be able to resolve to an unboxed entry point...
                // To cope with this case we always go via the helper function if there's any
                // chance of this happening by checking for all interfaces which might possibly
                // be compatible with the call (verification will have ensured that
                // at least one of them will be)

                // Enumerate all potential interface instantiations

                // TODO: this code assumes no shared generics
                Debug.Assert(interfaceType == interfaceMethod.OwningType);

                method = VirtualFunctionResolution.ResolveInterfaceMethodToVirtualMethodOnType(genInterfaceMethod, constrainedType);
            }
            else if (genInterfaceMethod.IsVirtual)
            {
                method = VirtualFunctionResolution.FindVirtualFunctionTargetMethodOnObjectType(genInterfaceMethod, constrainedType);
            }
            else
            {
                // The method will be null if calling a non-virtual instance 
                // methods on System.Object, i.e. when these are used as a constraint.
                method = null;
            }

            if (method == null)
            {
                // Fall back to VSD
                return null;
            }

            //#TryResolveConstraintMethodApprox_DoNotReturnParentMethod
            // Only return a method if the value type itself declares the method, 
            // otherwise we might get a method from Object or System.ValueType
            if (!method.OwningType.IsValueType)
            {
                // Fall back to VSD
                return null;
            }

            // We've resolved the method, ignoring its generic method arguments
            // If the method is a generic method then go and get the instantiated descriptor
            if (interfaceMethod.HasInstantiation)
            {
                method = method.InstantiateSignature(interfaceType.Instantiation, interfaceMethod.Instantiation);
            }

            Debug.Assert(method != null);
            //assert(!pMD->IsUnboxingStub());

            return method;
        }
Example #12
0
        private static DefaultInterfaceMethodResolution ResolveInterfaceMethodToDefaultImplementationOnType(MethodDesc interfaceMethod, MetadataType currentType, out MethodDesc impl)
        {
            TypeDesc     interfaceMethodOwningType = interfaceMethod.OwningType;
            MetadataType mostSpecificInterface     = null;
            bool         diamondCase = false;

            impl = null;

            MethodDesc interfaceMethodDefinition = interfaceMethod.GetMethodDefinition();

            DefType[] consideredInterfaces;
            if (!currentType.IsInterface)
            {
                // If this is not an interface, only things on the interface list could provide
                // default implementations.
                consideredInterfaces = currentType.RuntimeInterfaces;
            }
            else
            {
                // If we're asking about an interface, include the interface in the list.
                consideredInterfaces = new DefType[currentType.RuntimeInterfaces.Length + 1];
                Array.Copy(currentType.RuntimeInterfaces, consideredInterfaces, currentType.RuntimeInterfaces.Length);
                consideredInterfaces[consideredInterfaces.Length - 1] = (DefType)currentType.InstantiateAsOpen();
            }

            foreach (MetadataType runtimeInterface in consideredInterfaces)
            {
                if (runtimeInterface == interfaceMethodOwningType)
                {
                    // Also consider the default interface method implementation on the interface itself
                    // if we don't have anything else yet
                    if (mostSpecificInterface == null && !interfaceMethod.IsAbstract)
                    {
                        mostSpecificInterface = runtimeInterface;
                        impl = interfaceMethodDefinition;
                    }
                }
                else if (Array.IndexOf(runtimeInterface.RuntimeInterfaces, interfaceMethodOwningType) != -1)
                {
                    // This interface might provide a default implementation
                    MethodImplRecord[] possibleImpls = runtimeInterface.FindMethodsImplWithMatchingDeclName(interfaceMethod.Name);
                    if (possibleImpls != null)
                    {
                        foreach (MethodImplRecord implRecord in possibleImpls)
                        {
                            if (implRecord.Decl == interfaceMethodDefinition)
                            {
                                // This interface provides a default implementation.
                                // Is it also most specific?
                                if (mostSpecificInterface == null || Array.IndexOf(runtimeInterface.RuntimeInterfaces, mostSpecificInterface) != -1)
                                {
                                    mostSpecificInterface = runtimeInterface;
                                    impl        = implRecord.Body;
                                    diamondCase = false;
                                }
                                else if (Array.IndexOf(mostSpecificInterface.RuntimeInterfaces, runtimeInterface) == -1)
                                {
                                    diamondCase = true;
                                }

                                break;
                            }
                        }
                    }
                }
            }

            if (diamondCase)
            {
                impl = null;
                return(DefaultInterfaceMethodResolution.Diamond);
            }
            else if (impl == null)
            {
                return(DefaultInterfaceMethodResolution.None);
            }
            else if (impl.IsAbstract)
            {
                impl = null;
                return(DefaultInterfaceMethodResolution.Reabstraction);
            }

            if (interfaceMethod != interfaceMethodDefinition)
            {
                impl = impl.MakeInstantiatedMethod(interfaceMethod.Instantiation);
            }

            return(DefaultInterfaceMethodResolution.DefaultImplementation);
        }
Example #13
0
        /// <summary>
        /// Replace some of the types in a method's construction with a new set of types.
        /// Does not replace the open generics that may be instantiated over in this type.
        ///
        /// For instance, Given MyType&lt;object, int[]&gt;.Function&lt;short&gt;(),
        ///  an array of types to replace such as {int,short}, and
        ///  an array of replacement types such as {string,char}.
        ///  The result shall be MyType&lt;object, string[]&gt;.Function&lt;char&gt;
        ///
        /// This function cannot be used to replace MyType in the above example.
        /// </summary>
        public static MethodDesc ReplaceTypesInConstructionOfMethod(this MethodDesc method, TypeDesc[] typesToReplace, TypeDesc[] replacementTypes)
        {
            TypeDesc   newOwningType      = method.OwningType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
            MethodDesc methodOnOwningType = null;
            bool       owningTypeChanged  = false;

            if (newOwningType == method.OwningType)
            {
                methodOnOwningType = method.GetMethodDefinition();
            }
            else
            {
                methodOnOwningType = TypeSystemHelpers.FindMethodOnExactTypeWithMatchingTypicalMethod(newOwningType, method);
                owningTypeChanged  = true;
            }

            MethodDesc result;

            if (!method.HasInstantiation)
            {
                result = methodOnOwningType;
            }
            else
            {
                Debug.Assert(method is InstantiatedMethod);

                TypeDesc[] newInstantiation   = null;
                int        instantiationIndex = 0;
                for (; instantiationIndex < method.Instantiation.Length; instantiationIndex++)
                {
                    TypeDesc oldType = method.Instantiation[instantiationIndex];
                    TypeDesc newType = oldType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes);
                    if ((oldType != newType) || (newInstantiation != null))
                    {
                        if (newInstantiation == null)
                        {
                            newInstantiation = new TypeDesc[method.Instantiation.Length];
                            for (int i = 0; i < instantiationIndex; i++)
                            {
                                newInstantiation[i] = method.Instantiation[i];
                            }
                        }
                        newInstantiation[instantiationIndex] = newType;
                    }
                }

                if (newInstantiation != null)
                {
                    result = method.Context.GetInstantiatedMethod(methodOnOwningType, new Instantiation(newInstantiation));
                }
                else if (owningTypeChanged)
                {
                    result = method.Context.GetInstantiatedMethod(methodOnOwningType, method.Instantiation);
                }
                else
                {
                    result = method;
                }
            }

            return(result);
        }