/** * Differs from `isNullableType` only by treating type parameters: acceptsNullable(T) <=> T has * nullable lower bound Semantics should be the same as `isSubtype(Nothing?, T)` * * @return true if `null` can be assigned to storage of this type */ public static boolean acceptsNullable(@NotNull KotlinType type) { if (type.isMarkedNullable()) { return true; } if (FlexibleTypesKt.isFlexible(type) && acceptsNullable(FlexibleTypesKt.flexibility(type).getUpperBound())) { return true; } return false; }
@Nullable public static KotlinType createSubstitutedSupertype( @NotNull KotlinType subType, @NotNull KotlinType superType, @NotNull TypeSubstitutor substitutor) { KotlinType substitutedType = substitutor.substitute(superType, Variance.INVARIANT); if (substitutedType != null) { return makeNullableIfNeeded(substitutedType, subType.isMarkedNullable()); } return null; }
public static boolean hasNullableSuperType(@NotNull KotlinType type) { if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) { // A class/trait cannot have a nullable supertype return false; } for (KotlinType supertype : getImmediateSupertypes(type)) { if (supertype.isMarkedNullable()) return true; if (hasNullableSuperType(supertype)) return true; } return false; }
/** * A work-around of the generic nullability problem in the type checker Semantics should be the * same as `!isSubtype(T, Any)` * * @return true if a value of this type can be null */ public static boolean isNullableType(@NotNull KotlinType type) { if (type.isMarkedNullable()) { return true; } if (FlexibleTypesKt.isFlexible(type) && isNullableType(FlexibleTypesKt.flexibility(type).getUpperBound())) { return true; } if (isTypeParameter(type)) { return hasNullableSuperType(type); } return false; }
@NotNull public static KotlinType makeNullableAsSpecified(@NotNull KotlinType type, boolean nullable) { Flexibility flexibility = type.getCapability(Flexibility.class); if (flexibility != null) { return flexibility.makeNullableAsSpecified(nullable); } // Wrapping serves two purposes here // 1. It's requires less memory than copying with a changed nullability flag: a copy has many // fields, while a wrapper has only one // 2. It preserves laziness of types // Unwrap to avoid long delegation call chains if (type instanceof AbstractTypeWithKnownNullability) { return makeNullableAsSpecified(((AbstractTypeWithKnownNullability) type).delegate, nullable); } // checking to preserve laziness if (!(type instanceof LazyType) && type.isMarkedNullable() == nullable) { return type; } return nullable ? new NullableType(type) : new NotNullType(type); }
private static boolean isNotNullConstructedFromGivenClass( @NotNull KotlinType type, @NotNull FqNameUnsafe fqName) { return !type.isMarkedNullable() && isConstructedFromGivenClass(type, fqName); }
public static boolean isPrimitiveType(@NotNull KotlinType type) { ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); return !type.isMarkedNullable() && descriptor instanceof ClassDescriptor && isPrimitiveClass((ClassDescriptor) descriptor); }
public static boolean isNullableAny(@NotNull KotlinType type) { return isAnyOrNullableAny(type) && type.isMarkedNullable(); }
public static boolean isNullableNothing(@NotNull KotlinType type) { return isNothingOrNullableNothing(type) && type.isMarkedNullable(); }
public static boolean canHaveSubtypes(KotlinTypeChecker typeChecker, @NotNull KotlinType type) { if (type.isMarkedNullable()) { return true; } if (!type.getConstructor().isFinal()) { return true; } List<TypeParameterDescriptor> parameters = type.getConstructor().getParameters(); List<TypeProjection> arguments = type.getArguments(); for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { TypeParameterDescriptor parameterDescriptor = parameters.get(i); TypeProjection typeProjection = arguments.get(i); if (typeProjection.isStarProjection()) return true; Variance projectionKind = typeProjection.getProjectionKind(); KotlinType argument = typeProjection.getType(); switch (parameterDescriptor.getVariance()) { case INVARIANT: switch (projectionKind) { case INVARIANT: if (lowerThanBound(typeChecker, argument, parameterDescriptor) || canHaveSubtypes(typeChecker, argument)) { return true; } break; case IN_VARIANCE: if (lowerThanBound(typeChecker, argument, parameterDescriptor)) { return true; } break; case OUT_VARIANCE: if (canHaveSubtypes(typeChecker, argument)) { return true; } break; } break; case IN_VARIANCE: if (projectionKind != Variance.OUT_VARIANCE) { if (lowerThanBound(typeChecker, argument, parameterDescriptor)) { return true; } } else { if (canHaveSubtypes(typeChecker, argument)) { return true; } } break; case OUT_VARIANCE: if (projectionKind != Variance.IN_VARIANCE) { if (canHaveSubtypes(typeChecker, argument)) { return true; } } else { if (lowerThanBound(typeChecker, argument, parameterDescriptor)) { return true; } } break; } } return false; }