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; }
// Note: headers of member classes' members are not resolved public void resolveMemberHeaders() { ForceResolveUtil.forceResolveAllContents(getAnnotations()); ForceResolveUtil.forceResolveAllContents(getDanglingAnnotations()); getCompanionObjectDescriptor(); getDescriptorsForExtraCompanionObjects(); getConstructors(); getContainingDeclaration(); getThisAsReceiverParameter(); getKind(); getModality(); getName(); getOriginal(); getScopeForClassHeaderResolution(); getScopeForMemberDeclarationResolution(); DescriptorUtils.getAllDescriptors(getUnsubstitutedMemberScope()); getScopeForInitializerResolution(); getUnsubstitutedInnerClassesScope(); getTypeConstructor().getSupertypes(); for (TypeParameterDescriptor typeParameterDescriptor : getTypeConstructor().getParameters()) { typeParameterDescriptor.getUpperBounds(); } getUnsubstitutedPrimaryConstructor(); getVisibility(); }
/** * 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 List<TypeProjection> getDefaultTypeProjections( @NotNull List<TypeParameterDescriptor> parameters) { List<TypeProjection> result = new ArrayList<TypeProjection>(parameters.size()); for (TypeParameterDescriptor parameterDescriptor : parameters) { result.add(new TypeProjectionImpl(parameterDescriptor.getDefaultType())); } return org.jetbrains.kotlin.utils.CollectionsKt.toReadOnlyList(result); }
@Override public void setUp() throws Exception { super.setUp(); ModuleDescriptorImpl module = JetTestUtils.createEmptyModule(); builtIns = module.getBuiltIns(); typeResolver = InjectionKt.createContainerForTests(getProject(), module).getTypeResolver(); x = createTypeVariable("X"); y = createTypeVariable("Y"); variables = Sets.newHashSet(x.getTypeConstructor(), y.getTypeConstructor()); }
private void checkSupertypesForConsistency(@NotNull ClassDescriptor classDescriptor) { Multimap<TypeConstructor, TypeProjection> multimap = SubstitutionUtils.buildDeepSubstitutionMultimap(classDescriptor.getDefaultType()); for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) { Collection<TypeProjection> projections = entry.getValue(); if (projections.size() > 1) { TypeConstructor typeConstructor = entry.getKey(); DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor(); assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor; TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor; // Immediate arguments of supertypes cannot be projected Set<JetType> conflictingTypes = Sets.newLinkedHashSet(); for (TypeProjection projection : projections) { conflictingTypes.add(projection.getType()); } removeDuplicateTypes(conflictingTypes); if (conflictingTypes.size() > 1) { DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration(); assert containingDeclaration instanceof ClassDescriptor : containingDeclaration; JetClassOrObject psiElement = (JetClassOrObject) DescriptorToSourceUtils.getSourceFromDescriptor(classDescriptor); assert psiElement != null; JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList(); assert delegationSpecifierList != null; // // trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter // " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " // has inconsistent values: " + conflictingTypes); trace.report( INCONSISTENT_TYPE_PARAMETER_VALUES.on( delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration, conflictingTypes)); } } } }
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; }
// See JLS 8, 8.4.4 Generic Methods // TODO: use TypeSubstitutor instead private static boolean areTypeParametersEquivalent( @NotNull TypeParameterDescriptor superTypeParameter, @NotNull TypeParameterDescriptor subTypeParameter, @NotNull KotlinTypeChecker typeChecker) { List<KotlinType> superBounds = superTypeParameter.getUpperBounds(); List<KotlinType> subBounds = new ArrayList<KotlinType>(subTypeParameter.getUpperBounds()); if (superBounds.size() != subBounds.size()) return false; outer: for (KotlinType superBound : superBounds) { ListIterator<KotlinType> it = subBounds.listIterator(); while (it.hasNext()) { KotlinType subBound = it.next(); if (areTypesEquivalent(superBound, subBound, typeChecker)) { it.remove(); continue outer; } } return false; } return true; }
public static Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> recreateTypeParametersAndReturnMapping( @NotNull List<TypeParameterDescriptor> originalParameters, @Nullable DeclarationDescriptor newOwner) { // LinkedHashMap to save the order of type parameters Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> result = new LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptorImpl>(); for (TypeParameterDescriptor typeParameter : originalParameters) { result.put( typeParameter, TypeParameterDescriptorImpl.createForFurtherModification( newOwner == null ? typeParameter.getContainingDeclaration() : newOwner, typeParameter.getAnnotations(), typeParameter.isReified(), typeParameter.getVariance(), typeParameter.getName(), typeParameter.getIndex(), SourceElement.NO_SOURCE)); } return result; }
private static boolean allParametersReified(KotlinType subtype) { for (TypeParameterDescriptor parameterDescriptor : subtype.getConstructor().getParameters()) { if (!parameterDescriptor.isReified()) return false; } return true; }
@NotNull private OverrideCompatibilityInfo isOverridableBy( @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor, boolean checkReturnType) { if (superDescriptor instanceof FunctionDescriptor) { if (!(subDescriptor instanceof FunctionDescriptor)) return OverrideCompatibilityInfo.memberKindMismatch(); } else if (superDescriptor instanceof PropertyDescriptor) { if (!(subDescriptor instanceof PropertyDescriptor)) return OverrideCompatibilityInfo.memberKindMismatch(); } else { throw new IllegalArgumentException( "This type of CallableDescriptor cannot be checked for overridability: " + superDescriptor); } // TODO: check outside of this method if (!superDescriptor.getName().equals(subDescriptor.getName())) { return OverrideCompatibilityInfo.nameMismatch(); } OverrideCompatibilityInfo receiverAndParameterResult = checkReceiverAndParameterCount(superDescriptor, subDescriptor); if (receiverAndParameterResult != null) { return receiverAndParameterResult; } List<JetType> superValueParameters = compiledValueParameters(superDescriptor); List<JetType> subValueParameters = compiledValueParameters(subDescriptor); List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters(); List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters(); if (superTypeParameters.size() != subTypeParameters.size()) { for (int i = 0; i < superValueParameters.size(); ++i) { JetType superValueParameterType = getUpperBound(superValueParameters.get(i)); JetType subValueParameterType = getUpperBound(subValueParameters.get(i)); // TODO: compare erasure if (!JetTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType)) { return OverrideCompatibilityInfo.typeParameterNumberMismatch(); } } return OverrideCompatibilityInfo.valueParameterTypeMismatch( null, null, OverrideCompatibilityInfo.Result.CONFLICT); } final Map<TypeConstructor, TypeConstructor> matchingTypeConstructors = new HashMap<TypeConstructor, TypeConstructor>(); for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) { TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i); TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i); matchingTypeConstructors.put( superTypeParameter.getTypeConstructor(), subTypeParameter.getTypeConstructor()); } JetTypeChecker.TypeConstructorEquality localEqualityAxioms = new JetTypeChecker.TypeConstructorEquality() { @Override public boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b) { if (equalityAxioms.equals(a, b)) return true; TypeConstructor img1 = matchingTypeConstructors.get(a); TypeConstructor img2 = matchingTypeConstructors.get(b); if (!(img1 != null && img1.equals(b)) && !(img2 != null && img2.equals(a))) { return false; } return true; } }; for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) { TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i); TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i); if (!areTypesEquivalent( superTypeParameter.getUpperBoundsAsType(), subTypeParameter.getUpperBoundsAsType(), localEqualityAxioms)) { return OverrideCompatibilityInfo.boundsMismatch(superTypeParameter, subTypeParameter); } } for (int i = 0, unsubstitutedValueParametersSize = superValueParameters.size(); i < unsubstitutedValueParametersSize; i++) { JetType superValueParameter = superValueParameters.get(i); JetType subValueParameter = subValueParameters.get(i); if (!areTypesEquivalent(superValueParameter, subValueParameter, localEqualityAxioms)) { return OverrideCompatibilityInfo.valueParameterTypeMismatch( superValueParameter, subValueParameter, INCOMPATIBLE); } } if (checkReturnType) { JetType superReturnType = superDescriptor.getReturnType(); JetType subReturnType = subDescriptor.getReturnType(); if (superReturnType != null && subReturnType != null) { boolean bothErrors = subReturnType.isError() && superReturnType.isError(); if (!bothErrors && !JetTypeChecker.withAxioms(localEqualityAxioms) .isSubtypeOf(subReturnType, superReturnType)) { return OverrideCompatibilityInfo.returnTypeMismatch(superReturnType, subReturnType); } } } for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) { if (!externalCondition.isOverridable(superDescriptor, subDescriptor)) { return OverrideCompatibilityInfo.externalConditionFailed(externalCondition.getClass()); } } return OverrideCompatibilityInfo.success(); }
public static boolean isNonReifiedTypeParameter(@NotNull KotlinType type) { TypeParameterDescriptor typeParameterDescriptor = getTypeParameterDescriptorOrNull(type); return typeParameterDescriptor != null && !typeParameterDescriptor.isReified(); }
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; }