private List<Substitution<ReferenceType>> collectSubstitutions(List<TypeVariable> typeParameters,Substitution<ReferenceType> substitution){
  List<TypeVariable> genericParameters=new ArrayList<>();
  List<TypeVariable> nongenericParameters=new ArrayList<>();
  List<TypeVariable> captureParameters=new ArrayList<>();
  for (  TypeVariable variable : typeParameters) {
    if (variable.hasGenericBound()) {
      genericParameters.add(variable);
    }
 else {
      if (variable.isCaptureVariable()) {
        captureParameters.add(variable);
      }
 else {
        nongenericParameters.add(variable);
      }
    }
  }
  List<Substitution<ReferenceType>> substitutionList=new ArrayList<>();
  if (!genericParameters.isEmpty()) {
    TypeCheck typeCheck=TypeCheck.forParameters(genericParameters);
    if (!nongenericParameters.isEmpty()) {
      List<List<ReferenceType>> nonGenCandidates=getCandidateTypeLists(nongenericParameters);
      if (nonGenCandidates.isEmpty()) {
        return new ArrayList<>();
      }
      ListEnumerator<ReferenceType> enumerator=new ListEnumerator<>(nonGenCandidates);
      while (enumerator.hasNext()) {
        Substitution<ReferenceType> initialSubstitution=substitution.extend(Substitution.forArgs(nongenericParameters,enumerator.next()));
        List<TypeVariable> parameters=new ArrayList<>();
        for (        TypeVariable variable : genericParameters) {
          TypeVariable param=(TypeVariable)variable.apply(initialSubstitution);
          parameters.add(param);
        }
        substitutionList.addAll(collectSubstitutions(parameters,initialSubstitution));
      }
    }
 else {
      substitutionList=getInstantiations(genericParameters,substitution,typeCheck);
    }
    if (substitutionList.isEmpty()) {
      return substitutionList;
    }
  }
 else   if (!nongenericParameters.isEmpty()) {
    substitution=selectAndExtend(nongenericParameters,substitution);
    if (substitution == null) {
      return new ArrayList<>();
    }
    substitutionList.add(substitution);
  }
  if (!captureParameters.isEmpty()) {
    List<Substitution<ReferenceType>> substList=new ArrayList<>();
    if (substitutionList.isEmpty()) {
      substList.add(selectAndExtend(captureParameters,substitution));
    }
 else {
      for (      Substitution<ReferenceType> s : substitutionList) {
        substList.add(selectAndExtend(captureParameters,s));
      }
    }
    substitutionList=substList;
  }
  return substitutionList;
}

private List < Substitution < ReferenceType > > collectSubstitutions ( List < TypeVariable > typeParameters , Substitution < ReferenceType > substitution ) { List < TypeVariable > genericParameters = new ArrayList < > ( ) ; List < TypeVariable > nongenericParameters = new ArrayList < > ( ) ; List < TypeVariable > captureParameters = new ArrayList < > ( ) ; for ( TypeVariable variable : typeParameters ) { if ( variable . hasGenericBound ( ) ) { genericParameters . add ( variable ) ; } else { if ( variable . isCaptureVariable ( ) ) { captureParameters . add ( variable ) ; } else { nongenericParameters . add ( variable ) ; } } } List < Substitution < ReferenceType > > substitutionList = new ArrayList < > ( ) ; if ( ! genericParameters . isEmpty ( ) ) { TypeCheck typeCheck = TypeCheck . forParameters ( genericParameters ) ; if ( ! nongenericParameters . isEmpty ( ) ) { List < List < ReferenceType > > nonGenCandidates = getCandidateTypeLists ( nongenericParameters ) ; if ( nonGenCandidates . isEmpty ( ) ) { return new ArrayList < > ( ) ; } ListEnumerator < ReferenceType > enumerator = new ListEnumerator < > ( nonGenCandidates ) ; while ( enumerator . hasNext ( ) ) { Substitution < ReferenceType > initialSubstitution = substitution . extend ( Substitution . forArgs ( nongenericParameters , enumerator . next ( ) ) ) ; List < TypeVariable > parameters = new ArrayList < > ( ) ; for ( TypeVariable variable : genericParameters ) { TypeVariable param = ( TypeVariable ) variable . apply ( initialSubstitution ) ; parameters . add ( param ) ; } substitutionList . addAll ( collectSubstitutions ( parameters , initialSubstitution ) ) ; } } else { substitutionList = getInstantiations ( genericParameters , substitution , typeCheck ) ; } if ( substitutionList . isEmpty ( ) ) { return substitutionList ; } } else if ( ! nongenericParameters . isEmpty ( ) ) { substitution = selectAndExtend ( nongenericParameters , substitution ) ; if ( substitution == null ) { return new ArrayList < > ( ) ; } substitutionList . add ( substitution ) ; } if ( ! captureParameters . isEmpty ( ) ) { List < Substitution < ReferenceType > > substList = new ArrayList < > ( ) ; if ( substitutionList . isEmpty ( ) ) { substList . add ( selectAndExtend ( captureParameters , substitution ) ) ; } else { for ( Substitution < ReferenceType > s : substitutionList ) { substList . add ( selectAndExtend ( captureParameters , s ) ) ; } } substitutionList = substList ; } return substitutionList ; }
recursive function to collect the list of substitutions that extend a substitution for the given type parameters .
