@Nullable public static TypeParameterDescriptor getTypeParameterDescriptorOrNull(@NotNull KotlinType type) { if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) { return (TypeParameterDescriptor) type.getConstructor().getDeclarationDescriptor(); } return null; }
private static boolean lowerThanBound( KotlinTypeChecker typeChecker, KotlinType argument, TypeParameterDescriptor parameterDescriptor) { for (KotlinType bound : parameterDescriptor.getUpperBounds()) { if (typeChecker.isSubtypeOf(argument, bound)) { if (!argument.getConstructor().equals(bound.getConstructor())) { return true; } } } return false; }
/** * Check if cast from supertype to subtype is erased. It is an error in "is" statement and warning * in "as". */ public static boolean isCastErased( @NotNull KotlinType supertype, @NotNull KotlinType subtype, @NotNull KotlinTypeChecker typeChecker) { // cast between T and T? is always OK if (supertype.isMarkedNullable() || subtype.isMarkedNullable()) { return isCastErased( TypeUtils.makeNotNullable(supertype), TypeUtils.makeNotNullable(subtype), typeChecker); } // if it is a upcast, it's never erased if (typeChecker.isSubtypeOf(supertype, subtype)) return false; // downcasting to a non-reified type parameter is always erased if (TypeUtils.isNonReifiedTypeParemeter(subtype)) return true; // Check that we are actually casting to a generic type // NOTE: this does not account for 'as Array<List<T>>' if (allParametersReified(subtype)) return false; KotlinType staticallyKnownSubtype = findStaticallyKnownSubtype(supertype, subtype.getConstructor()).getResultingType(); // If the substitution failed, it means that the result is an impossible type, e.g. something // like Out<in Foo> // In this case, we can't guarantee anything, so the cast is considered to be erased if (staticallyKnownSubtype == null) return true; // If the type we calculated is a subtype of the cast target, it's OK to use the cast target // instead. // If not, it's wrong to use it return !typeChecker.isSubtypeOf(staticallyKnownSubtype, subtype); }
/** * Remember that we are trying to cast something of type {@code supertype} to {@code subtype}. * * <p>Since at runtime we can only check the class (type constructor), the rest of the subtype * should be known statically, from supertype. This method reconstructs all static information * that can be obtained from supertype. * * <p>Example 1: supertype = Collection<String> subtype = List<...> result = List<String>, all * arguments are inferred * * <p>Example 2: supertype = Any subtype = List<...> result = List<*>, some arguments were not * inferred, replaced with '*' */ public static TypeReconstructionResult findStaticallyKnownSubtype( @NotNull KotlinType supertype, @NotNull TypeConstructor subtypeConstructor) { assert !supertype.isMarkedNullable() : "This method only makes sense for non-nullable types"; // Assume we are casting an expression of type Collection<Foo> to List<Bar> // First, let's make List<T>, where T is a type variable ClassifierDescriptor descriptor = subtypeConstructor.getDeclarationDescriptor(); assert descriptor != null : "Can't create default type for " + subtypeConstructor; KotlinType subtypeWithVariables = descriptor.getDefaultType(); // Now, let's find a supertype of List<T> that is a Collection of something, // in this case it will be Collection<T> KotlinType supertypeWithVariables = TypeCheckingProcedure.findCorrespondingSupertype(subtypeWithVariables, supertype); final List<TypeParameterDescriptor> variables = subtypeWithVariables.getConstructor().getParameters(); Map<TypeConstructor, TypeProjection> substitution; if (supertypeWithVariables != null) { // Now, let's try to unify Collection<T> and Collection<Foo> solution is a map from T to Foo TypeUnifier.UnificationResult solution = TypeUnifier.unify( new TypeProjectionImpl(supertype), new TypeProjectionImpl(supertypeWithVariables), new Predicate<TypeConstructor>() { @Override public boolean apply(TypeConstructor typeConstructor) { ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor(); return descriptor instanceof TypeParameterDescriptor && variables.contains(descriptor); } }); substitution = Maps.newHashMap(solution.getSubstitution()); } else { // If there's no corresponding supertype, no variables are determined // This may be OK, e.g. in case 'Any as List<*>' substitution = Maps.newHashMapWithExpectedSize(variables.size()); } // If some of the parameters are not determined by unification, it means that these parameters // are lost, // let's put stars instead, so that we can only cast to something like List<*>, e.g. (a: Any) as // List<*> boolean allArgumentsInferred = true; for (TypeParameterDescriptor variable : variables) { TypeProjection value = substitution.get(variable.getTypeConstructor()); if (value == null) { substitution.put(variable.getTypeConstructor(), TypeUtils.makeStarProjection(variable)); allArgumentsInferred = false; } } // At this point we have values for all type parameters of List // Let's make a type by substituting them: List<T> -> List<Foo> KotlinType substituted = TypeSubstitutor.create(substitution).substitute(subtypeWithVariables, Variance.INVARIANT); return new TypeReconstructionResult(substituted, allArgumentsInferred); }
@Nullable public static ClassDescriptor getClassDescriptor(@NotNull KotlinType type) { DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor(); if (declarationDescriptor instanceof ClassDescriptor) { return (ClassDescriptor) declarationDescriptor; } return null; }
public static boolean isExtensionFunctionType(@NotNull KotlinType type) { if (isExactExtensionFunctionType(type)) return true; for (KotlinType superType : type.getConstructor().getSupertypes()) { if (isExtensionFunctionType(superType)) return true; } return false; }
private static boolean isConstructedFromGivenClass( @NotNull KotlinType type, @NotNull FqNameUnsafe fqName) { ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); return descriptor != null && /* quick check to avoid creation of full FqName instance */ descriptor .getName() .equals(fqName.shortName()) && fqName.equals(getFqName(descriptor)); }
public static boolean isSubtypeOfClass( @NotNull KotlinType type, @NotNull DeclarationDescriptor superClass) { if (isSameClass(type, superClass)) return true; for (KotlinType superType : type.getConstructor().getSupertypes()) { if (isSubtypeOfClass(superType, superClass)) { return true; } } return false; }
public static boolean dependsOnTypeConstructors( @NotNull KotlinType type, @NotNull Collection<TypeConstructor> typeParameterConstructors) { if (typeParameterConstructors.contains(type.getConstructor())) return true; for (TypeProjection typeProjection : type.getArguments()) { if (!typeProjection.isStarProjection() && dependsOnTypeConstructors(typeProjection.getType(), typeParameterConstructors)) { return true; } } return false; }
@NotNull public static List<KotlinType> getImmediateSupertypes(@NotNull KotlinType type) { TypeSubstitutor substitutor = TypeSubstitutor.create(type); Collection<KotlinType> originalSupertypes = type.getConstructor().getSupertypes(); List<KotlinType> result = new ArrayList<KotlinType>(originalSupertypes.size()); for (KotlinType supertype : originalSupertypes) { KotlinType substitutedType = createSubstitutedSupertype(type, supertype, substitutor); if (substitutedType != null) { result.add(substitutedType); } } return result; }
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; }
private static boolean isSameClass( @NotNull KotlinType type, @NotNull DeclarationDescriptor other) { DeclarationDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); if (descriptor != null) { DeclarationDescriptor originalDescriptor = descriptor.getOriginal(); if (originalDescriptor instanceof ClassifierDescriptor && other instanceof ClassifierDescriptor && ((ClassifierDescriptor) other) .getTypeConstructor() .equals(((ClassifierDescriptor) originalDescriptor).getTypeConstructor())) { return true; } } return false; }
private static List<KotlinType> mapToPlatformIndependentTypes( @NotNull KotlinType type, @NotNull PlatformToKotlinClassMap platformToKotlinClassMap) { ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); if (!(descriptor instanceof ClassDescriptor)) return Collections.singletonList(type); ClassDescriptor originalClass = (ClassDescriptor) descriptor; Collection<ClassDescriptor> kotlinClasses = platformToKotlinClassMap.mapPlatformClass(originalClass); if (kotlinClasses.isEmpty()) return Collections.singletonList(type); List<KotlinType> result = Lists.newArrayListWithCapacity(2); result.add(type); for (ClassDescriptor classDescriptor : kotlinClasses) { KotlinType kotlinType = TypeUtils.substituteProjectionsForParameters(classDescriptor, type.getArguments()); result.add(kotlinType); } return result; }
public static boolean isDontCarePlaceholder(@Nullable KotlinType type) { return type != null && type.getConstructor() == DONT_CARE.getConstructor(); }
public static boolean isExactFunctionOrExtensionFunctionType(@NotNull KotlinType type) { ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); return descriptor != null && isNumberedFunctionClassFqName(getFqName(descriptor)); }
public static boolean isPrimitiveType(@NotNull KotlinType type) { ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); return !type.isMarkedNullable() && descriptor instanceof ClassDescriptor && isPrimitiveClass((ClassDescriptor) descriptor); }
public static boolean isPrimitiveArray(@NotNull KotlinType type) { ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); return descriptor != null && getPrimitiveTypeByArrayClassFqName(getFqName(descriptor)) != null; }
@NotNull public static ClassDescriptor getClassDescriptorForType(@NotNull KotlinType type) { return getClassDescriptorForTypeConstructor(type.getConstructor()); }
private static boolean allParametersReified(KotlinType subtype) { for (TypeParameterDescriptor parameterDescriptor : subtype.getConstructor().getParameters()) { if (!parameterDescriptor.isReified()) return false; } return true; }
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; }
private static boolean isTrait(@NotNull KotlinType type) { ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); return descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.INTERFACE; }
@Override @NotNull public TypeConstructor getConstructor() { return delegate.getConstructor(); }