public static boolean contains( @Nullable KotlinType type, @NotNull Function1<KotlinType, Boolean> isSpecialType) { if (type == null) return false; if (isSpecialType.invoke(type)) return true; Flexibility flexibility = type.getCapability(Flexibility.class); if (flexibility != null && (contains(flexibility.getLowerBound(), isSpecialType) || contains(flexibility.getUpperBound(), isSpecialType))) { return true; } for (TypeProjection projection : type.getArguments()) { if (!projection.isStarProjection() && contains(projection.getType(), isSpecialType)) return true; } return false; }
@NotNull private TypeProjection unsafeSubstitute( @NotNull TypeProjection originalProjection, int recursionDepth) throws SubstitutionException { assertRecursionDepth(recursionDepth, originalProjection, substitution); if (originalProjection.isStarProjection()) return originalProjection; // The type is within the substitution range, i.e. T or T? JetType type = originalProjection.getType(); TypeProjection replacement = substitution.get(type); Variance originalProjectionKind = originalProjection.getProjectionKind(); if (replacement == null && FlexibleTypesKt.isFlexible(type) && !TypeCapabilitiesKt.isCustomTypeVariable(type)) { Flexibility flexibility = FlexibleTypesKt.flexibility(type); TypeProjection substitutedLower = unsafeSubstitute( new TypeProjectionImpl(originalProjectionKind, flexibility.getLowerBound()), recursionDepth + 1); TypeProjection substitutedUpper = unsafeSubstitute( new TypeProjectionImpl(originalProjectionKind, flexibility.getUpperBound()), recursionDepth + 1); Variance substitutedProjectionKind = substitutedLower.getProjectionKind(); assert (substitutedProjectionKind == substitutedUpper.getProjectionKind()) && originalProjectionKind == Variance.INVARIANT || originalProjectionKind == substitutedProjectionKind : "Unexpected substituted projection kind: " + substitutedProjectionKind + "; original: " + originalProjectionKind; JetType substitutedFlexibleType = DelegatingFlexibleType.create( substitutedLower.getType(), substitutedUpper.getType(), flexibility.getExtraCapabilities()); return new TypeProjectionImpl(substitutedProjectionKind, substitutedFlexibleType); } if (KotlinBuiltIns.isNothing(type) || type.isError()) return originalProjection; if (replacement != null) { VarianceConflictType varianceConflict = conflictType(originalProjectionKind, replacement.getProjectionKind()); // Captured type might be substituted in an opposite projection: // out 'Captured (in Int)' = out Int // in 'Captured (out Int)' = in Int boolean allowVarianceConflict = CapturedTypeConstructorKt.isCaptured(type); if (!allowVarianceConflict) { //noinspection EnumSwitchStatementWhichMissesCases switch (varianceConflict) { case OUT_IN_IN_POSITION: throw new SubstitutionException("Out-projection in in-position"); case IN_IN_OUT_POSITION: // todo use the right type parameter variance and upper bound return new TypeProjectionImpl( Variance.OUT_VARIANCE, type.getConstructor().getBuiltIns().getNullableAnyType()); } } JetType substitutedType; CustomTypeVariable typeVariable = TypeCapabilitiesKt.getCustomTypeVariable(type); if (replacement.isStarProjection()) { return replacement; } else if (typeVariable != null) { substitutedType = typeVariable.substitutionResult(replacement.getType()); } else { // this is a simple type T or T?: if it's T, we should just take replacement, if T? - we // make replacement nullable substitutedType = TypeUtils.makeNullableIfNeeded(replacement.getType(), type.isMarkedNullable()); } // substitutionType.annotations = replacement.annotations ++ type.annotations if (!type.getAnnotations().isEmpty()) { Annotations typeAnnotations = filterOutUnsafeVariance(type.getAnnotations()); substitutedType = TypeUtilsKt.replaceAnnotations( substitutedType, new CompositeAnnotations(substitutedType.getAnnotations(), typeAnnotations)); } Variance resultingProjectionKind = varianceConflict == VarianceConflictType.NO_CONFLICT ? combine(originalProjectionKind, replacement.getProjectionKind()) : originalProjectionKind; return new TypeProjectionImpl(resultingProjectionKind, substitutedType); } // The type is not within the substitution range, i.e. Foo, Bar<T> etc. return substituteCompoundType(originalProjection, recursionDepth); }