presto-main/src/main/java/io/prestosql/operator/scalar/annotations/ParametricScalarImplementation.java/ParametricScalarImplementation/specialize
class ParametricScalarImplementation:    public Optional<ScalarFunctionImplementation> specialize(Signature boundSignature, BoundVariables boundVariables, Metadata metadata)
    {
        List<ScalarImplementationChoice> implementationChoices = new ArrayList<>();
        for (Map.Entry<String, Class<?>> entry : specializedTypeParameters.entrySet()) {
            if (entry.getValue() != boundVariables.getTypeVariable(entry.getKey()).getJavaType()) {
                return Optional.empty();
            }
        }

        if (returnNativeContainerType != Object.class && returnNativeContainerType != metadata.getType(boundSignature.getReturnType()).getJavaType()) {
            return Optional.empty();
        }

        for (int i = 0; i < boundSignature.getArgumentTypes().size(); i++) {
            if (boundSignature.getArgumentTypes().get(i).getBase().equals(FunctionType.NAME)) {
                if (argumentNativeContainerTypes.get(i).isPresent()) {
                    return Optional.empty();
                }
            }
            else {
                if (!argumentNativeContainerTypes.get(i).isPresent()) {
                    return Optional.empty();
                }

                Class<?> argumentType = metadata.getType(boundSignature.getArgumentTypes().get(i)).getJavaType();
                Class<?> argumentNativeContainerType = argumentNativeContainerTypes.get(i).get();
                if (argumentNativeContainerType != Object.class && argumentNativeContainerType != argumentType) {
                    return Optional.empty();
                }
            }
        }

        for (ParametricScalarImplementationChoice choice : choices) {
            MethodHandle boundMethodHandle = bindDependencies(choice.getMethodHandle(), choice.getDependencies(), boundVariables, metadata);
            Optional<MethodHandle> boundConstructor = choice.getConstructor().map(constructor -> {
                MethodHandle result = bindDependencies(constructor, choice.getConstructorDependencies(), boundVariables, metadata);
                checkCondition(
                        result.type().parameterList().isEmpty(),
                        FUNCTION_IMPLEMENTATION_ERROR,
                        "All parameters of a constructor in a function definition class must be Dependencies. Signature: %s",
                        boundSignature);
                return result;
            });

            implementationChoices.add(new ScalarImplementationChoice(
                    choice.nullable,
                    choice.argumentProperties,
                    boundMethodHandle.asType(javaMethodType(choice, boundSignature, metadata)),
                    boundConstructor));
        }
        return Optional.of(new ScalarFunctionImplementation(implementationChoices));
    }