presto-main/src/main/java/io/prestosql/operator/annotations/FunctionsParserHelper.java/FunctionsParserHelper/createTypeVariableConstraints
class FunctionsParserHelper:    public static List<TypeVariableConstraint> createTypeVariableConstraints(Collection<TypeParameter> typeParameters, List<ImplementationDependency> dependencies)
    {
        Set<String> typeParameterNames = typeParameters.stream()
                .map(TypeParameter::value)
                .collect(toImmutableSet());

        Set<String> orderableRequired = new HashSet<>();
        Set<String> comparableRequired = new HashSet<>();
        HashMultimap<String, String> castableTo = HashMultimap.create();
        HashMultimap<String, String> castableFrom = HashMultimap.create();
        for (ImplementationDependency dependency : dependencies) {
            if (dependency instanceof OperatorImplementationDependency) {
                OperatorImplementationDependency operatorDependency = (OperatorImplementationDependency) dependency;
                OperatorType operator = operatorDependency.getOperator();
                List<TypeSignature> argumentTypes = operatorDependency.getArgumentTypes();
                if (COMPARABLE_TYPE_OPERATORS.contains(operator)) {
                    verifyOperatorSignature(operator, argumentTypes);
                    TypeSignature typeSignature = argumentTypes.get(0);
                    if (typeParameterNames.contains(typeSignature.getBase())) {
                        comparableRequired.add(typeSignature.toString());
                    }
                    else {
                        verifyTypeSignatureDoesNotContainAnyTypeParameters(typeSignature, typeSignature, typeParameterNames);
                    }
                }
                else if (ORDERABLE_TYPE_OPERATORS.contains(operator)) {
                    verifyOperatorSignature(operator, argumentTypes);
                    TypeSignature typeSignature = argumentTypes.get(0);
                    if (typeParameterNames.contains(typeSignature.getBase())) {
                        orderableRequired.add(typeSignature.toString());
                    }
                    else {
                        verifyTypeSignatureDoesNotContainAnyTypeParameters(typeSignature, typeSignature, typeParameterNames);
                    }
                }
                else {
                    throw new IllegalArgumentException("Operator dependency on " + operator + " is not allowed");
                }
            }
            else if (dependency instanceof CastImplementationDependency) {
                CastImplementationDependency castImplementationDependency = (CastImplementationDependency) dependency;

                TypeSignature fromType = castImplementationDependency.getFromType();
                TypeSignature toType = castImplementationDependency.getToType();
                if (typeParameterNames.contains(fromType.getBase())) {
                    // fromType is a type parameter, so it must be castable to the toType, which might also be a type parameter
                    castableTo.put(fromType.toString(), toType.toString());
                }
                else if (typeParameterNames.contains(toType.getBase())) {
                    // toType is a type parameter, so it must be castable from the toType, which is not a type parameter
                    castableFrom.put(toType.toString(), fromType.toString());
                }
                else {
                    verifyTypeSignatureDoesNotContainAnyTypeParameters(fromType, fromType, typeParameterNames);
                    verifyTypeSignatureDoesNotContainAnyTypeParameters(toType, toType, typeParameterNames);
                }
            }
        }

        ImmutableList.Builder<TypeVariableConstraint> typeVariableConstraints = ImmutableList.builder();
        for (String name : typeParameterNames) {
            typeVariableConstraints.add(new TypeVariableConstraint(
                    name,
                    comparableRequired.contains(name),
                    orderableRequired.contains(name),
                    null,
                    castableTo.get(name).stream()
                            .map(type -> parseTypeSignature(type, typeParameterNames))
                            .collect(toImmutableSet()),
                    castableFrom.get(name).stream()
                            .map(type -> parseTypeSignature(type, typeParameterNames))
                            .collect(toImmutableSet())));
        }
        return typeVariableConstraints.build();
    }