private List<TypeProjection> substituteTypeArguments( List<TypeParameterDescriptor> typeParameters, List<TypeProjection> typeArguments, int recursionDepth) throws SubstitutionException { List<TypeProjection> substitutedArguments = new ArrayList<TypeProjection>(typeParameters.size()); for (int i = 0; i < typeParameters.size(); i++) { TypeParameterDescriptor typeParameter = typeParameters.get(i); TypeProjection typeArgument = typeArguments.get(i); TypeProjection substitutedTypeArgument = unsafeSubstitute(typeArgument, recursionDepth + 1); switch (conflictType( typeParameter.getVariance(), substitutedTypeArgument.getProjectionKind())) { case NO_CONFLICT: // if the corresponding type parameter is already co/contra-variant, there's not need for // an explicit projection if (typeParameter.getVariance() != Variance.INVARIANT && !substitutedTypeArgument.isStarProjection()) { substitutedTypeArgument = new TypeProjectionImpl(Variance.INVARIANT, substitutedTypeArgument.getType()); } break; case OUT_IN_IN_POSITION: case IN_IN_OUT_POSITION: substitutedTypeArgument = TypeUtils.makeStarProjection(typeParameter); break; } substitutedArguments.add(substitutedTypeArgument); } return substitutedArguments; }