From 70030b208d94ea3b3e7a7e2a336c2f60a11d05a5 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Mon, 18 Feb 2013 19:41:01 +0400 Subject: [PATCH] Extracted PropagationHeuristics utility class. --- .../PropagationHeuristics.java | 119 ++++++++++++++++++ .../SignaturesPropagationData.java | 82 +----------- 2 files changed, 125 insertions(+), 76 deletions(-) create mode 100644 compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/PropagationHeuristics.java diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/PropagationHeuristics.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/PropagationHeuristics.java new file mode 100644 index 00000000000..b1ad4c91786 --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/PropagationHeuristics.java @@ -0,0 +1,119 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.java.kotlinSignature; + +import com.google.common.collect.Lists; +import com.intellij.openapi.util.Condition; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.JetTypeImpl; +import org.jetbrains.jet.lang.types.TypeProjection; +import org.jetbrains.jet.lang.types.Variance; +import org.jetbrains.jet.lang.types.checker.JetTypeChecker; +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; +import org.jetbrains.jet.renderer.DescriptorRenderer; + +import java.util.Arrays; +import java.util.List; + +// This class contains heuristics for processing corner cases in propagation +class PropagationHeuristics { + // Checks for case when method returning Super[] is overridden with method returning Sub[] + static void checkArrayInReturnTypeType( + @NotNull SignaturesPropagationData data, + @NotNull JetType type, + @NotNull List typesFromSuper + ) { + List arrayTypesFromSuper = ContainerUtil + .filter(typesFromSuper, new Condition() { + @Override + public boolean value(SignaturesPropagationData.TypeAndVariance typeAndVariance) { + return typeAndVariance.type.getConstructor().getDeclarationDescriptor() == KotlinBuiltIns.getInstance().getArray(); + } + }); + if (KotlinBuiltIns.getInstance().getArray() == type.getConstructor().getDeclarationDescriptor() && !arrayTypesFromSuper.isEmpty()) { + assert type.getArguments().size() == 1; + if (type.getArguments().get(0).getProjectionKind() == Variance.INVARIANT) { + for (SignaturesPropagationData.TypeAndVariance typeAndVariance : arrayTypesFromSuper) { + JetType arrayTypeFromSuper = typeAndVariance.type; + assert arrayTypeFromSuper.getArguments().size() == 1; + JetType elementTypeInSuper = arrayTypeFromSuper.getArguments().get(0).getType(); + JetType elementType = type.getArguments().get(0).getType(); + + if (JetTypeChecker.INSTANCE.isSubtypeOf(elementType, elementTypeInSuper) + && !JetTypeChecker.INSTANCE.equalTypes(elementType, elementTypeInSuper)) { + JetTypeImpl betterTypeInSuper = new JetTypeImpl( + arrayTypeFromSuper.getAnnotations(), + arrayTypeFromSuper.getConstructor(), + arrayTypeFromSuper.isNullable(), + Arrays.asList(new TypeProjection(Variance.OUT_VARIANCE, elementTypeInSuper)), + JetScope.EMPTY); + + data.reportError("Return type is not a subtype of overridden method. " + + "To fix it, add annotation with Kotlin signature to super method with type " + + DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(arrayTypeFromSuper) + " replaced with " + + DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(betterTypeInSuper) + " in return type"); + } + } + } + } + } + + // Weird workaround for weird case. The sample code below is compiled by javac. + // In this case, we try to replace "Any" parameter type with "T" to fix substitution principle. + // + // public interface Super { + // void foo(T t); + // } + // + // public interface Sub extends Super { + // void foo(Object o); + // } + // + // This method is called from SignaturesPropagationData. + @Nullable + static ClassifierDescriptor tryToFixOverridingTWithRawType( + @NotNull SignaturesPropagationData data, + @NotNull List typesFromSuper + ) { + List typeParameterClassifiersFromSuper = Lists.newArrayList(); + for (SignaturesPropagationData.TypeAndVariance typeFromSuper : typesFromSuper) { + ClassifierDescriptor classifierFromSuper = typeFromSuper.type.getConstructor().getDeclarationDescriptor(); + if (classifierFromSuper instanceof TypeParameterDescriptor) { + typeParameterClassifiersFromSuper.add((TypeParameterDescriptor) classifierFromSuper); + } + } + + if (!typeParameterClassifiersFromSuper.isEmpty() && typeParameterClassifiersFromSuper.size() == typesFromSuper.size()) { + for (TypeParameterDescriptor typeParameter : typeParameterClassifiersFromSuper) { + if (typeParameter.getContainingDeclaration() == data.containingClass) { + return typeParameter; + } + } + } + + return null; + } + + private PropagationHeuristics() { + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java index 14bfea69af9..74d03c61a46 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java @@ -22,7 +22,6 @@ import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.SystemInfo; import com.intellij.psi.HierarchicalMethodSignature; import com.intellij.psi.PsiClass; @@ -42,9 +41,7 @@ import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.*; -import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; -import org.jetbrains.jet.renderer.DescriptorRenderer; import java.util.*; @@ -62,7 +59,7 @@ public class SignaturesPropagationData { private final List signatureErrors = Lists.newArrayList(); private final List superFunctions; private final Map autoTypeParameterToModified; - private final ClassDescriptor containingClass; + final ClassDescriptor containingClass; public SignaturesPropagationData( @NotNull ClassDescriptor containingClass, @@ -102,7 +99,7 @@ public class SignaturesPropagationData { return superFunctions; } - private void reportError(String error) { + void reportError(String error) { signatureErrors.add(error); } @@ -331,47 +328,10 @@ public class SignaturesPropagationData { resultArguments, resultScope); - checkArrayInReturnTypeType(type, typesFromSuper); - + PropagationHeuristics.checkArrayInReturnTypeType(this, type, typesFromSuper); return type; } - // Checks for case when method returning Super[] is overridden with method returning Sub[] - private void checkArrayInReturnTypeType(JetType type, List typesFromSuper) { - List arrayTypesFromSuper = ContainerUtil.filter(typesFromSuper, new Condition() { - @Override - public boolean value(TypeAndVariance typeAndVariance) { - return typeAndVariance.type.getConstructor().getDeclarationDescriptor() == KotlinBuiltIns.getInstance().getArray(); - } - }); - if (KotlinBuiltIns.getInstance().getArray() == type.getConstructor().getDeclarationDescriptor() && !arrayTypesFromSuper.isEmpty()) { - assert type.getArguments().size() == 1; - if (type.getArguments().get(0).getProjectionKind() == Variance.INVARIANT) { - for (TypeAndVariance typeAndVariance : arrayTypesFromSuper) { - JetType arrayTypeFromSuper = typeAndVariance.type; - assert arrayTypeFromSuper.getArguments().size() == 1; - JetType elementTypeInSuper = arrayTypeFromSuper.getArguments().get(0).getType(); - JetType elementType = type.getArguments().get(0).getType(); - - if (JetTypeChecker.INSTANCE.isSubtypeOf(elementType, elementTypeInSuper) - && !JetTypeChecker.INSTANCE.equalTypes(elementType, elementTypeInSuper)) { - JetTypeImpl betterTypeInSuper = new JetTypeImpl( - arrayTypeFromSuper.getAnnotations(), - arrayTypeFromSuper.getConstructor(), - arrayTypeFromSuper.isNullable(), - Arrays.asList(new TypeProjection(Variance.OUT_VARIANCE, elementTypeInSuper)), - JetScope.EMPTY); - - reportError("Return type is not a subtype of overridden method. " + - "To fix it, add annotation with Kotlin signature to super method with type " - + DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(arrayTypeFromSuper) + " replaced with " - + DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(betterTypeInSuper) + " in return type"); - } - } - } - } - } - @NotNull private List getTypeArgsOfType( @NotNull JetType autoType, @@ -611,38 +571,8 @@ public class SignaturesPropagationData { } } - // Weird workaround for weird case. The sample code below is compiled by javac. - // In this case, we try to replace "Any" parameter type with "T" to fix substitution principle. - // - // public interface Super { - // void foo(T t); - // } - // - // public interface Sub extends Super { - // void foo(Object o); - // } - - List typeParameterClassifiersFromSuper = Lists.newArrayList(); - for (TypeAndVariance typeFromSuper : typesFromSuper) { - ClassifierDescriptor classifierFromSuper = typeFromSuper.type.getConstructor().getDeclarationDescriptor(); - if (classifierFromSuper instanceof TypeParameterDescriptor) { - typeParameterClassifiersFromSuper.add((TypeParameterDescriptor) classifierFromSuper); - } - } - - if (!typeParameterClassifiersFromSuper.isEmpty() && typeParameterClassifiersFromSuper.size() == typesFromSuper.size()) { - for (TypeParameterDescriptor typeParameter : typeParameterClassifiersFromSuper) { - if (typeParameter.getContainingDeclaration() != containingClass) { - continue; - } - - return autoTypeParameterToModified.containsKey(typeParameter) ? autoTypeParameterToModified - .get(typeParameter) : typeParameter; - - } - } - - return classifier; + ClassifierDescriptor fixed = PropagationHeuristics.tryToFixOverridingTWithRawType(this, typesFromSuper); + return fixed != null ? fixed : classifier; } private static Map getSuperclassToSupertypeMap(ClassDescriptor containingClass) { @@ -717,7 +647,7 @@ public class SignaturesPropagationData { } } - private static class TypeAndVariance { + static class TypeAndVariance { public final JetType type; public final Variance varianceOfPosition;