<commit_before>package me.tomassetti.symbolsolver.logic;

import javaslang.Tuple2;
import me.tomassetti.symbolsolver.model.typesystem.ReferenceTypeUsage;
import me.tomassetti.symbolsolver.model.typesystem.TypeUsage;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GenericTypeInferenceLogic {

    public static Map<String, TypeUsage> inferGenericTypes(List<Tuple2<TypeUsage, TypeUsage>> formalActualTypePairs) {
        Map<String, TypeUsage> map = new HashMap<>();

        for (Tuple2<TypeUsage, TypeUsage> formalActualTypePair : formalActualTypePairs) {
            TypeUsage formalType = formalActualTypePair._1;
            TypeUsage actualType = formalActualTypePair._2;
            consider(map, formalType, actualType);
            // we can infer also in the other direction
            consider(map, actualType, formalType);
        }

        return map;
    }

    private static void consider(Map<String, TypeUsage> map, TypeUsage formalType, TypeUsage actualType) {
        if (formalType == null) {
            throw new IllegalArgumentException();
        }
        if (actualType == null) {
            throw new IllegalArgumentException();
        }
        if (formalType.isTypeVariable()) {
            if (map.containsKey(formalType.asTypeParameter().getName())) {
                if (!actualType.equals(map.get(formalType.asTypeParameter().getName()))) {
                    throw new UnsupportedOperationException("Map already contains " + formalType);
                }
            }
            map.put(formalType.asTypeParameter().getName(), actualType);
        } else if (formalType.isReferenceType()) {
            ReferenceTypeUsage formalTypeAsReference = formalType.asReferenceTypeUsage();
            if (actualType.isReferenceType()) {
                if (formalTypeAsReference.getQualifiedName().equals(actualType.asReferenceTypeUsage().getQualifiedName())) {
                	int i = 0;
	                for (TypeUsage formalTypeParameter : formalTypeAsReference.parameters()) {
	                    if (!actualType.isReferenceType()) {
	                        throw new UnsupportedOperationException(actualType.describe() + " " + formalTypeAsReference.describe());
	                    }
	                    consider(map, formalTypeParameter, actualType.asReferenceTypeUsage().parameters().get(i));
	                    i++;
                	}
                }
                // TODO: consider cases where the actual type extends or implements the formal type. Here the number and order of type parameters can be different.
            } else if (actualType.isTypeVariable()) {
                // nothing to do
            } else if (actualType.isWildcard()) {
                // nothing to do
            } else if (actualType.isPrimitive()) {
                // nothing to do
            } else {
                throw new UnsupportedOperationException(actualType.getClass().getCanonicalName());
            }
        } else if (formalType.isWildcard()) {
            if (actualType.isWildcard()) {
                if (actualType.asWildcard().isExtends() && formalType.asWildcard().isExtends()) {
                    consider(map, formalType.asWildcard().getBoundedType(), actualType.asWildcard().getBoundedType());
                } else if (actualType.asWildcard().isSuper() && formalType.asWildcard().isSuper()) {
                    consider(map, formalType.asWildcard().getBoundedType(), actualType.asWildcard().getBoundedType());
                }
            }
        } else if (formalType.isPrimitive()) {
            // nothing to do<commit_msg>implemented considering array type while inferring generic types<commit_after>package me.tomassetti.symbolsolver.logic;

import javaslang.Tuple2;
import me.tomassetti.symbolsolver.model.typesystem.ReferenceTypeUsage;
import me.tomassetti.symbolsolver.model.typesystem.TypeUsage;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GenericTypeInferenceLogic {

    public static Map<String, TypeUsage> inferGenericTypes(List<Tuple2<TypeUsage, TypeUsage>> formalActualTypePairs) {
        Map<String, TypeUsage> map = new HashMap<>();

        for (Tuple2<TypeUsage, TypeUsage> formalActualTypePair : formalActualTypePairs) {
            TypeUsage formalType = formalActualTypePair._1;
            TypeUsage actualType = formalActualTypePair._2;
            consider(map, formalType, actualType);
            // we can infer also in the other direction
            consider(map, actualType, formalType);
        }

        return map;
    }

    private static void consider(Map<String, TypeUsage> map, TypeUsage formalType, TypeUsage actualType) {
        if (formalType == null) {
            throw new IllegalArgumentException();
        }
        if (actualType == null) {
            throw new IllegalArgumentException();
        }
        if (formalType.isTypeVariable()) {
            if (map.containsKey(formalType.asTypeParameter().getName())) {
                if (!actualType.equals(map.get(formalType.asTypeParameter().getName()))) {
                    throw new UnsupportedOperationException("Map already contains " + formalType);
                }
            }
            map.put(formalType.asTypeParameter().getName(), actualType);
        } else if (formalType.isReferenceType()) {
            ReferenceTypeUsage formalTypeAsReference = formalType.asReferenceTypeUsage();
            if (actualType.isReferenceType()) {
                if (formalTypeAsReference.getQualifiedName().equals(actualType.asReferenceTypeUsage().getQualifiedName())) {
                	int i = 0;
	                for (TypeUsage formalTypeParameter : formalTypeAsReference.parameters()) {
	                    if (!actualType.isReferenceType()) {
	                        throw new UnsupportedOperationException(actualType.describe() + " " + formalTypeAsReference.describe());
	                    }
	                    consider(map, formalTypeParameter, actualType.asReferenceTypeUsage().parameters().get(i));
	                    i++;
                	}
                }
                // TODO: consider cases where the actual type extends or implements the formal type. Here the number and order of type parameters can be different.
            } else if (actualType.isTypeVariable()) {
                // nothing to do
            } else if (actualType.isWildcard()) {
                // nothing to do
            } else if (actualType.isPrimitive()) {
                // nothing to do
            } else {
                throw new UnsupportedOperationException(actualType.getClass().getCanonicalName());
            }
        } else if (formalType.isWildcard()) {
            if (actualType.isWildcard()) {
                if (actualType.asWildcard().isExtends() && formalType.asWildcard().isExtends()) {
                    consider(map, formalType.asWildcard().getBoundedType(), actualType.asWildcard().getBoundedType());
                } else if (actualType.asWildcard().isSuper() && formalType.asWildcard().isSuper()) {
                    consider(map, formalType.asWildcard().getBoundedType(), actualType.asWildcard().getBoundedType());
                }
            }
        } else if (formalType.isPrimitive()) {
            // nothing to do
        } else if (formalType.isArray()) {
            if (actualType.isArray()) {
                consider(map, formalType.asArrayTypeUsage().getComponentType(), actualType.asArrayTypeUsage().getComponentType());
            }
{'fraction_non_alphanumeric': 0.1039597404317309, 'fraction_numerical': 0.0015891934843067143, 'mean_word_length': 2.3035870516185475, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1379388', 'n_tokens_mistral': 1939, 'n_tokens_neox': 1834, 'n_words': 392}