java-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/typeinference/TypeInference.java
private BoundSet boundSetup(List<ResolvedTypeParameterDeclaration> typeParameterDeclarations, List<InferenceVariable> inferenceVariables) {
        if (typeParameterDeclarations.size() != inferenceVariables.size()) {
            throw new IllegalArgumentException();
        }

        // When inference begins, a bound set is typically generated from a list of
        // type parameter declarations P1, ..., Pp and associated inference variables α1, ..., αp.
        // Such a bound set is constructed as follows. For each l (1 ≤ l ≤ p):

        BoundSet boundSet = BoundSet.empty();

        for (int l=0;l<typeParameterDeclarations.size();l++) {
            ResolvedTypeParameterDeclaration Pl = typeParameterDeclarations.get(l);
            InferenceVariable alphaL = inferenceVariables.get(l);

            // - If Pl has no TypeBound, the bound αl <: Object appears in the set.

            if (Pl.getBounds().isEmpty()) {
                boundSet = boundSet.withBound(new SubtypeOfBound(alphaL, object));
            } else {

                // - Otherwise, for each type T delimited by & in the TypeBound, the bound αl <: T[P1:=α1, ..., Pp:=αp] appears
                // in the set; if this results in no proper upper bounds for αl (only dependencies), then the
                // bound αl <: Object also appears in the set.

                for (ResolvedTypeParameterDeclaration.Bound bound : Pl.getBounds()) {
                    ResolvedType T = bound.getType();
                    Substitution substitution = Substitution.empty();
                    for (int j=0;j<typeParameterDeclarations.size();j++) {
                        substitution = substitution.withPair(typeParameterDeclarations.get(j), inferenceVariables.get(j));
                    }
                    ResolvedType TWithSubstitutions = substitution.apply(T);

                    boundSet = boundSet.withBound(new SubtypeOfBound(alphaL, TWithSubstitutions));

                    if (boundSet.getProperUpperBoundsFor(alphaL).isEmpty()) {
                        boundSet = boundSet.withBound(new SubtypeOfBound(alphaL, object));
                    }
                }
            }
        }

        return boundSet;
    }
private BoundSet boundSetup(List<ResolvedTypeParameterDeclaration> typeParameterDeclarations, List<InferenceVariable> inferenceVariables) {
        if (typeParameterDeclarations.size() != inferenceVariables.size()) {
            throw new IllegalArgumentException();
        }

        // When inference begins, a bound set is typically generated from a list of
        // type parameter declarations P1, ..., Pp and associated inference variables α1, ..., αp.
        // Such a bound set is constructed as follows. For each l (1 ≤ l ≤ p):

        BoundSet boundSet = BoundSet.empty();

        for (int l=0;l<typeParameterDeclarations.size();l++) {
            ResolvedTypeParameterDeclaration Pl = typeParameterDeclarations.get(l);
            InferenceVariable alphaL = inferenceVariables.get(l);

            // - If Pl has no TypeBound, the bound αl <: Object appears in the set.

            if (Pl.getBounds().isEmpty()) {
                boundSet = boundSet.withBound(new SubtypeOfBound(alphaL, object));
            } else {

                // - Otherwise, for each type T delimited by & in the TypeBound, the bound αl <: T[P1:=α1, ..., Pp:=αp] appears
                // in the set; if this results in no proper upper bounds for αl (only dependencies), then the
                // bound αl <: Object also appears in the set.

                for (ResolvedTypeParameterDeclaration.Bound bound : Pl.getBounds()) {
                    ResolvedType T = bound.getType();
                    Substitution substitution = Substitution.empty();
                    for (int j=0;j<typeParameterDeclarations.size();j++) {
                        substitution = substitution.withPair(typeParameterDeclarations.get(j), inferenceVariables.get(j));
                    }
                    ResolvedType TWithSubstitutions = substitution.apply(T);

                    boundSet = boundSet.withBound(new SubtypeOfBound(alphaL, TWithSubstitutions));

                    if (boundSet.getProperUpperBoundsFor(alphaL).isEmpty()) {
                        boundSet = boundSet.withBound(new SubtypeOfBound(alphaL, object));
                    }
                }
            }
        }

        return boundSet;
    }
When inference begins, a bound set is typically generated from a list of type parameter declarations P1, ..., Pp
and associated inference variables α1, ..., αp

@param typeParameterDeclarations
@param inferenceVariables
@return