presto-main/src/main/java/io/prestosql/metadata/FunctionRegistry.java/FunctionRegistry/resolveCoercion
class FunctionRegistry:    private ResolvedFunction resolveCoercion(Signature signature)
    {
        Collection<FunctionMetadata> allCandidates = functions.get(QualifiedName.of(signature.getName()));

        List<TypeSignatureProvider> argumentTypeSignatureProviders = fromTypeSignatures(signature.getArgumentTypes());

        List<FunctionMetadata> exactCandidates = allCandidates.stream()
                .filter(function -> possibleExactCastMatch(signature, function.getSignature()))
                .collect(Collectors.toList());
        for (FunctionMetadata candidate : exactCandidates) {
            Optional<BoundVariables> boundVariables = new SignatureBinder(metadata, candidate.getSignature(), false)
                    .bindVariables(argumentTypeSignatureProviders, signature.getReturnType());
            if (boundVariables.isPresent()) {
                return new ResolvedFunction(signature, candidate.getFunctionId());
            }
        }

        // only consider generic genericCandidates
        List<FunctionMetadata> genericCandidates = allCandidates.stream()
                .filter(function -> !function.getSignature().getTypeVariableConstraints().isEmpty())
                .collect(Collectors.toList());
        for (FunctionMetadata candidate : genericCandidates) {
            Optional<BoundVariables> boundVariables = new SignatureBinder(metadata, candidate.getSignature(), false)
                    .bindVariables(argumentTypeSignatureProviders, signature.getReturnType());
            if (boundVariables.isPresent()) {
                return new ResolvedFunction(signature, candidate.getFunctionId());
            }
        }

        throw new PrestoException(FUNCTION_IMPLEMENTATION_MISSING, format("%s not found", signature));
    }