// allowedFinalSupertypes typically contains a enum type of which supertypeOwner is an entry private void checkSupertypeList( @NotNull MutableClassDescriptor supertypeOwner, @NotNull Map<JetTypeReference, JetType> supertypes, Set<TypeConstructor> allowedFinalSupertypes) { Set<TypeConstructor> typeConstructors = Sets.newHashSet(); boolean classAppeared = false; for (Map.Entry<JetTypeReference, JetType> entry : supertypes.entrySet()) { JetTypeReference typeReference = entry.getKey(); JetType supertype = entry.getValue(); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); if (classDescriptor != null) { if (classDescriptor.getKind() != ClassKind.TRAIT) { if (classAppeared) { trace.report(MANY_CLASSES_IN_SUPERTYPE_LIST.on(typeReference)); } else { classAppeared = true; } } } else { trace.report(SUPERTYPE_NOT_A_CLASS_OR_TRAIT.on(typeReference)); } TypeConstructor constructor = supertype.getConstructor(); if (!typeConstructors.add(constructor)) { trace.report(SUPERTYPE_APPEARS_TWICE.on(typeReference)); } if (constructor.isSealed() && !allowedFinalSupertypes.contains(constructor)) { trace.report(FINAL_SUPERTYPE.on(typeReference)); } } }
@NotNull private String renderTypeName(@NotNull TypeConstructor typeConstructor) { ClassifierDescriptor cd = typeConstructor.getDeclarationDescriptor(); if (cd instanceof TypeParameterDescriptor) { return renderName(cd.getName()); } else if (cd instanceof ClassDescriptor) { return renderClassName((ClassDescriptor) cd); } else { assert cd == null : "Unexpected classifier: " + cd.getClass(); return typeConstructor.toString(); } }
@NotNull public static KotlinType makeUnsubstitutedType( ClassDescriptor classDescriptor, MemberScope unsubstitutedMemberScope) { if (ErrorUtils.isError(classDescriptor)) { return ErrorUtils.createErrorType("Unsubstituted type for " + classDescriptor); } TypeConstructor typeConstructor = classDescriptor.getTypeConstructor(); List<TypeProjection> arguments = getDefaultTypeProjections(typeConstructor.getParameters()); return KotlinTypeImpl.create( Annotations.Companion.getEMPTY(), typeConstructor, false, arguments, unsubstitutedMemberScope); }
/** * 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); }
@NotNull public static ClassDescriptor getClassDescriptorForTypeConstructor( @NotNull TypeConstructor typeConstructor) { ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor(); assert descriptor instanceof ClassDescriptor : "Classifier descriptor of a type should be of type ClassDescriptor: " + typeConstructor; return (ClassDescriptor) descriptor; }
@Override public String toString() { return constructor.toString(); }
private void checkSupertypeList( @NotNull ClassDescriptor supertypeOwner, @NotNull Map<JetTypeReference, JetType> supertypes, @NotNull JetClassOrObject jetClass) { Set<TypeConstructor> allowedFinalSupertypes = getAllowedFinalSupertypes(supertypeOwner, jetClass); Set<TypeConstructor> typeConstructors = Sets.newHashSet(); boolean classAppeared = false; for (Map.Entry<JetTypeReference, JetType> entry : supertypes.entrySet()) { JetTypeReference typeReference = entry.getKey(); JetType supertype = entry.getValue(); boolean addSupertype = true; ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); if (classDescriptor != null) { if (ErrorUtils.isError(classDescriptor)) continue; if (classDescriptor.getKind() != ClassKind.INTERFACE) { if (supertypeOwner.getKind() == ClassKind.ENUM_CLASS) { trace.report(CLASS_IN_SUPERTYPE_FOR_ENUM.on(typeReference)); addSupertype = false; } else if (supertypeOwner.getKind() == ClassKind.INTERFACE && !classAppeared && !TypesPackage.isDynamic(supertype) /* avoid duplicate diagnostics */) { trace.report(TRAIT_WITH_SUPERCLASS.on(typeReference)); addSupertype = false; } if (classAppeared) { trace.report(MANY_CLASSES_IN_SUPERTYPE_LIST.on(typeReference)); } else { classAppeared = true; } } } else { trace.report(SUPERTYPE_NOT_A_CLASS_OR_TRAIT.on(typeReference)); } TypeConstructor constructor = supertype.getConstructor(); if (addSupertype && !typeConstructors.add(constructor)) { trace.report(SUPERTYPE_APPEARS_TWICE.on(typeReference)); } if (DescriptorUtils.isSingleton(classDescriptor)) { trace.report(SINGLETON_IN_SUPERTYPE.on(typeReference)); } else if (constructor.isFinal() && !allowedFinalSupertypes.contains(constructor)) { if (classDescriptor.getModality() == Modality.SEALED) { DeclarationDescriptor containingDescriptor = supertypeOwner.getContainingDeclaration(); while (containingDescriptor != null && containingDescriptor != classDescriptor) { containingDescriptor = containingDescriptor.getContainingDeclaration(); } if (containingDescriptor == null) { trace.report(SEALED_SUPERTYPE.on(typeReference)); } else { trace.report(SEALED_SUPERTYPE_IN_LOCAL_CLASS.on(typeReference)); } } else { trace.report(FINAL_SUPERTYPE.on(typeReference)); } } } }
@NotNull @Override public Annotations getAnnotations() { return errorTypeConstructor.getAnnotations(); }
@Nullable @Override public ClassifierDescriptor getDeclarationDescriptor() { return errorTypeConstructor.getDeclarationDescriptor(); }
@Override public boolean isDenotable() { return errorTypeConstructor.isDenotable(); }
@Override public boolean isFinal() { return errorTypeConstructor.isFinal(); }
@NotNull @Override public Collection<JetType> getSupertypes() { return errorTypeConstructor.getSupertypes(); }
@NotNull @Override public List<TypeParameterDescriptor> getParameters() { return errorTypeConstructor.getParameters(); }
private void addConstraint( @NotNull ConstraintKind constraintKind, @NotNull JetType subjectType, @Nullable JetType constrainingType, @NotNull ConstraintPosition constraintPosition) { if (constrainingType == TypeUtils.NO_EXPECTED_TYPE || constrainingType == DONT_CARE || constrainingType == CANT_INFER) { return; } if (constrainingType == null || (ErrorUtils.isErrorType(constrainingType) && constrainingType != PLACEHOLDER_FUNCTION_TYPE)) { hasErrorInConstrainingTypes = true; return; } assert subjectType != TypeUtils.NO_EXPECTED_TYPE : "Subject type shouldn't be NO_EXPECTED_TYPE (in position " + constraintPosition + " )"; if (ErrorUtils.isErrorType(subjectType)) return; DeclarationDescriptor subjectTypeDescriptor = subjectType.getConstructor().getDeclarationDescriptor(); KotlinBuiltIns kotlinBuiltIns = KotlinBuiltIns.getInstance(); if (constrainingType == PLACEHOLDER_FUNCTION_TYPE) { if (!kotlinBuiltIns.isFunctionOrExtensionFunctionType(subjectType)) { if (subjectTypeDescriptor instanceof TypeParameterDescriptor && typeParameterConstraints.get(subjectTypeDescriptor) != null) { // a constraint binds type parameter and any function type, so there is no new info and no // error return; } errorConstraintPositions.add(constraintPosition); } return; } // todo temporary hack // function literal without declaring receiver type { x -> ... } // can be considered as extension function if one is expected // (special type constructor for function/ extension function should be introduced like // PLACEHOLDER_FUNCTION_TYPE) if (constraintKind == SUB_TYPE && kotlinBuiltIns.isFunctionType(constrainingType) && kotlinBuiltIns.isExtensionFunctionType(subjectType)) { constrainingType = createCorrespondingExtensionFunctionType(constrainingType, DONT_CARE); } DeclarationDescriptor constrainingTypeDescriptor = constrainingType.getConstructor().getDeclarationDescriptor(); if (subjectTypeDescriptor instanceof TypeParameterDescriptor) { TypeParameterDescriptor typeParameter = (TypeParameterDescriptor) subjectTypeDescriptor; TypeConstraintsImpl typeConstraints = typeParameterConstraints.get(typeParameter); if (typeConstraints != null) { if (TypeUtils.dependsOnTypeParameterConstructors( constrainingType, Collections.singleton(DONT_CARE.getConstructor()))) { return; } if (subjectType.isNullable() && constrainingType.isNullable()) { constrainingType = TypeUtils.makeNotNullable(constrainingType); } typeConstraints.addBound(constraintKind, constrainingType); return; } } if (constrainingTypeDescriptor instanceof TypeParameterDescriptor) { assert typeParameterConstraints.get(constrainingTypeDescriptor) == null : "Constraining type contains type variable " + constrainingTypeDescriptor.getName(); } if (constraintKind == SUB_TYPE && kotlinBuiltIns.isNothingOrNullableNothing(constrainingType)) { // following constraints are always true: // 'Nothing' is a subtype of any type if (!constrainingType.isNullable()) return; // 'Nothing?' is a subtype of nullable type if (subjectType.isNullable()) return; } if (!(constrainingTypeDescriptor instanceof ClassDescriptor) || !(subjectTypeDescriptor instanceof ClassDescriptor)) { errorConstraintPositions.add(constraintPosition); return; } switch (constraintKind) { case SUB_TYPE: { if (kotlinBuiltIns.isNothingOrNullableNothing(constrainingType)) break; JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(constrainingType, subjectType); if (correspondingSupertype != null) { constrainingType = correspondingSupertype; } break; } case SUPER_TYPE: { if (kotlinBuiltIns.isNothingOrNullableNothing(subjectType)) break; JetType correspondingSupertype = TypeCheckingProcedure.findCorrespondingSupertype(subjectType, constrainingType); if (correspondingSupertype != null) { subjectType = correspondingSupertype; } } case EQUAL: // nothing } if (constrainingType.getConstructor() != subjectType.getConstructor()) { errorConstraintPositions.add(constraintPosition); return; } TypeConstructor typeConstructor = subjectType.getConstructor(); List<TypeProjection> subjectArguments = subjectType.getArguments(); List<TypeProjection> constrainingArguments = constrainingType.getArguments(); List<TypeParameterDescriptor> parameters = typeConstructor.getParameters(); for (int i = 0; i < subjectArguments.size(); i++) { Variance typeParameterVariance = parameters.get(i).getVariance(); TypeProjection subjectArgument = subjectArguments.get(i); TypeProjection constrainingArgument = constrainingArguments.get(i); ConstraintKind typeParameterConstraintKind = getTypeParameterConstraintKind( typeParameterVariance, subjectArgument, constrainingArgument, constraintKind); addConstraint( typeParameterConstraintKind, subjectArgument.getType(), constrainingArgument.getType(), constraintPosition); } }