@Nullable public static OverrideCompatibilityInfo getBasicOverridabilityProblem( @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) { if (superDescriptor instanceof FunctionDescriptor && !(subDescriptor instanceof FunctionDescriptor) || superDescriptor instanceof PropertyDescriptor && !(subDescriptor instanceof PropertyDescriptor)) { return OverrideCompatibilityInfo.incompatible("Member kind mismatch"); } if (!(superDescriptor instanceof FunctionDescriptor) && !(superDescriptor instanceof PropertyDescriptor)) { 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.incompatible("Name mismatch"); } OverrideCompatibilityInfo receiverAndParameterResult = checkReceiverAndParameterCount(superDescriptor, subDescriptor); if (receiverAndParameterResult != null) { return receiverAndParameterResult; } return null; }
private static boolean isReturnTypeMoreSpecific( @NotNull CallableDescriptor a, @NotNull KotlinType aReturnType, @NotNull CallableDescriptor b, @NotNull KotlinType bReturnType) { KotlinTypeChecker typeChecker = DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters()); return typeChecker.isSubtypeOf(aReturnType, bReturnType); }
@NotNull public OverrideCompatibilityInfo isOverridableByWithoutExternalConditions( @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor, boolean checkReturnType) { OverrideCompatibilityInfo basicOverridability = getBasicOverridabilityProblem(superDescriptor, subDescriptor); if (basicOverridability != null) return basicOverridability; List<KotlinType> superValueParameters = compiledValueParameters(superDescriptor); List<KotlinType> 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) { // TODO: compare erasure if (!KotlinTypeChecker.DEFAULT.equalTypes( superValueParameters.get(i), subValueParameters.get(i))) { return OverrideCompatibilityInfo.incompatible("Type parameter number mismatch"); } } return OverrideCompatibilityInfo.conflict("Type parameter number mismatch"); } KotlinTypeChecker typeChecker = createTypeChecker(superTypeParameters, subTypeParameters); for (int i = 0; i < superTypeParameters.size(); i++) { if (!areTypeParametersEquivalent( superTypeParameters.get(i), subTypeParameters.get(i), typeChecker)) { return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch"); } } for (int i = 0; i < superValueParameters.size(); i++) { if (!areTypesEquivalent( superValueParameters.get(i), subValueParameters.get(i), typeChecker)) { return OverrideCompatibilityInfo.incompatible("Value parameter type mismatch"); } } if (checkReturnType) { KotlinType superReturnType = superDescriptor.getReturnType(); KotlinType subReturnType = subDescriptor.getReturnType(); if (superReturnType != null && subReturnType != null) { boolean bothErrors = subReturnType.isError() && superReturnType.isError(); if (!bothErrors && !typeChecker.isSubtypeOf(subReturnType, superReturnType)) { return OverrideCompatibilityInfo.conflict("Return type mismatch"); } } } return OverrideCompatibilityInfo.success(); }
static List<KotlinType> compiledValueParameters(CallableDescriptor callableDescriptor) { ReceiverParameterDescriptor receiverParameter = callableDescriptor.getExtensionReceiverParameter(); List<KotlinType> parameters = new ArrayList<KotlinType>(); if (receiverParameter != null) { parameters.add(receiverParameter.getType()); } for (ValueParameterDescriptor valueParameterDescriptor : callableDescriptor.getValueParameters()) { parameters.add(valueParameterDescriptor.getType()); } return parameters; }
@Nullable static OverrideCompatibilityInfo checkReceiverAndParameterCount( CallableDescriptor superDescriptor, CallableDescriptor subDescriptor) { if ((superDescriptor.getExtensionReceiverParameter() == null) != (subDescriptor.getExtensionReceiverParameter() == null)) { return OverrideCompatibilityInfo.incompatible("Receiver presence mismatch"); } if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) { return OverrideCompatibilityInfo.incompatible("Value parameter number mismatch"); } return null; }
@Nullable static OverrideCompatibilityInfo checkReceiverAndParameterCount( CallableDescriptor superDescriptor, CallableDescriptor subDescriptor) { if ((superDescriptor.getExtensionReceiverParameter() == null) != (subDescriptor.getExtensionReceiverParameter() == null)) { return OverrideCompatibilityInfo.receiverPresenceMismatch(); } if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) { return OverrideCompatibilityInfo.valueParameterNumberMismatch(); } return null; }
public static boolean isMoreSpecific( @NotNull CallableDescriptor a, @NotNull CallableDescriptor b) { KotlinType aReturnType = a.getReturnType(); KotlinType bReturnType = b.getReturnType(); assert aReturnType != null : "Return type of " + a + " is null"; assert bReturnType != null : "Return type of " + b + " is null"; if (!isVisibilityMoreSpecific(a, b)) return false; if (a instanceof SimpleFunctionDescriptor) { assert b instanceof SimpleFunctionDescriptor : "b is " + b.getClass(); return isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType); } if (a instanceof PropertyDescriptor) { assert b instanceof PropertyDescriptor : "b is " + b.getClass(); PropertyDescriptor pa = (PropertyDescriptor) a; PropertyDescriptor pb = (PropertyDescriptor) b; if (!isAccessorMoreSpecific(pa.getSetter(), pb.getSetter())) return false; if (pa.isVar() && pb.isVar()) { return DEFAULT .createTypeChecker(a.getTypeParameters(), b.getTypeParameters()) .equalTypes(aReturnType, bReturnType); } else { // both vals or var vs val: val can't be more specific then var return !(!pa.isVar() && pb.isVar()) && isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType); } } throw new IllegalArgumentException("Unexpected callable: " + a.getClass()); }
@NotNull public OverrideCompatibilityInfo isOverridableByWithoutExternalConditions( @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor, boolean checkReturnType) { if (superDescriptor instanceof FunctionDescriptor && !(subDescriptor instanceof FunctionDescriptor) || superDescriptor instanceof PropertyDescriptor && !(subDescriptor instanceof PropertyDescriptor)) { return OverrideCompatibilityInfo.incompatible("Member kind mismatch"); } if (!(superDescriptor instanceof FunctionDescriptor) && !(superDescriptor instanceof PropertyDescriptor)) { 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.incompatible("Name mismatch"); } OverrideCompatibilityInfo receiverAndParameterResult = checkReceiverAndParameterCount(superDescriptor, subDescriptor); if (receiverAndParameterResult != null) { return receiverAndParameterResult; } List<KotlinType> superValueParameters = compiledValueParameters(superDescriptor); List<KotlinType> 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) { // TODO: compare erasure if (!KotlinTypeChecker.DEFAULT.equalTypes( superValueParameters.get(i), subValueParameters.get(i))) { return OverrideCompatibilityInfo.incompatible("Type parameter number mismatch"); } } return OverrideCompatibilityInfo.conflict("Type parameter number mismatch"); } KotlinTypeChecker typeChecker = createTypeChecker(superTypeParameters, subTypeParameters); for (int i = 0; i < superTypeParameters.size(); i++) { if (!areTypeParametersEquivalent( superTypeParameters.get(i), subTypeParameters.get(i), typeChecker)) { return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch"); } } for (int i = 0; i < superValueParameters.size(); i++) { if (!areTypesEquivalent( superValueParameters.get(i), subValueParameters.get(i), typeChecker)) { return OverrideCompatibilityInfo.incompatible("Value parameter type mismatch"); } } if (checkReturnType) { KotlinType superReturnType = superDescriptor.getReturnType(); KotlinType subReturnType = subDescriptor.getReturnType(); if (superReturnType != null && subReturnType != null) { boolean bothErrors = subReturnType.isError() && superReturnType.isError(); if (!bothErrors && !typeChecker.isSubtypeOf(subReturnType, superReturnType)) { return OverrideCompatibilityInfo.conflict("Return type mismatch"); } } } return OverrideCompatibilityInfo.success(); }
@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(); }