diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/RawTypesCheck.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/RawTypesCheck.java index bc1227d4636..dcc5ec8f888 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/RawTypesCheck.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/RawTypesCheck.java @@ -95,7 +95,8 @@ public class RawTypesCheck { } for (HierarchicalMethodSignature superSignature : method.getHierarchicalMethodSignature().getSuperSignatures()) { - if (superSignature.isRaw() || hasRawTypesInSignature(superSignature.getMethod())) { + PsiMethod superMethod = superSignature.getMethod(); + if (superSignature.isRaw() || typeParameterIsErased(method, superMethod) || hasRawTypesInSignature(superMethod)) { return true; } } @@ -103,6 +104,14 @@ public class RawTypesCheck { return false; } + private static boolean typeParameterIsErased(@NotNull PsiMethod a, @NotNull PsiMethod b) { + // Java allows you to write + // T foo(), in the superclass and then + // Foo foo(), in the subclass + // this is a valid Java override, but in fact it is an erasure + return a.getTypeParameters().length != b.getTypeParameters().length; + } + private RawTypesCheck() { } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java index 1bac2952bb3..5a1e9c525ef 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java @@ -22,6 +22,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; @@ -222,6 +223,7 @@ public class OverridingUtil { public static boolean isReturnTypeOkForOverride(@NotNull JetTypeChecker typeChecker, @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) { TypeSubstitutor typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor); + if (typeSubstitutor == null) return false; JetType superReturnType = superDescriptor.getReturnType(); assert superReturnType != null; @@ -235,11 +237,14 @@ public class OverridingUtil { return typeChecker.isSubtypeOf(subReturnType, substitutedSuperReturnType); } + @Nullable private static TypeSubstitutor prepareTypeSubstitutor(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) { List superTypeParameters = superDescriptor.getTypeParameters(); List subTypeParameters = subDescriptor.getTypeParameters(); + if (subTypeParameters.size() != superTypeParameters.size()) return null; + Map substitutionContext = Maps.newHashMap(); - for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) { + for (int i = 0; i < superTypeParameters.size(); i++) { TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i); TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i); substitutionContext.put( diff --git a/compiler/testData/diagnostics/tests/j+k/kt3307.kt b/compiler/testData/diagnostics/tests/j+k/kt3307.kt new file mode 100644 index 00000000000..340842481bc --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/kt3307.kt @@ -0,0 +1,21 @@ +// FILE: Bug.java + +public interface Bug { + RET save(); +} + +// FILE: SubBug.java + +public class SubBug implements Bug { + public SubBug save() { + return this; + } +} + +// FILE: Bug.kt + +fun TestBug() { + SubBug().save() // can resolve on subtype + val bug: Bug = SubBug() + bug.save() // can resolve on supertype +} \ No newline at end of file diff --git a/compiler/testData/loadJavaCustom/methodTypeParameterErased/MethodTypeParameterErased.java b/compiler/testData/loadJavaCustom/methodTypeParameterErased/MethodTypeParameterErased.java new file mode 100644 index 00000000000..81f54e78c18 --- /dev/null +++ b/compiler/testData/loadJavaCustom/methodTypeParameterErased/MethodTypeParameterErased.java @@ -0,0 +1,19 @@ +package test; + +public interface MethodTypeParameterErased { + + public interface Bug { + > RET save(); + void foo(); + } + + public abstract class SubBug implements Bug { + public SubBug save() { + return this; + } + + public void foo() {} + + } + +} \ No newline at end of file diff --git a/compiler/testData/loadJavaCustom/methodTypeParameterErased/MethodTypeParameterErased.txt b/compiler/testData/loadJavaCustom/methodTypeParameterErased/MethodTypeParameterErased.txt new file mode 100644 index 00000000000..ff574930690 --- /dev/null +++ b/compiler/testData/loadJavaCustom/methodTypeParameterErased/MethodTypeParameterErased.txt @@ -0,0 +1,13 @@ +package test + +public trait MethodTypeParameterErased : java.lang.Object { + + public trait Bug : java.lang.Object { + public abstract fun ?> save() : RET? + } + + public open class SubBug : test.MethodTypeParameterErased.Bug { + public constructor SubBug() + public open fun save() : test.MethodTypeParameterErased.SubBug? + } +} diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index e26e668826a..590af93ef55 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -16,16 +16,13 @@ package org.jetbrains.jet.checkers; -import junit.framework.Assert; import junit.framework.Test; import junit.framework.TestSuite; - -import java.io.File; import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.test.InnerTestClasses; import org.jetbrains.jet.test.TestMetadata; -import org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve; +import java.io.File; /** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @@ -2629,6 +2626,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/j+k/kt2890.kt"); } + @TestMetadata("kt3307.kt") + public void testKt3307() throws Exception { + doTest("compiler/testData/diagnostics/tests/j+k/kt3307.kt"); + } + @TestMetadata("mutableIterator.kt") public void testMutableIterator() throws Exception { doTest("compiler/testData/diagnostics/tests/j+k/mutableIterator.kt"); diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaCustomTest.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaCustomTest.java index 5fda5ccfaea..edd4036efe5 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaCustomTest.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaCustomTest.java @@ -161,6 +161,12 @@ public final class LoadJavaCustomTest extends KotlinTestWithEnvironment { dir + "SubclassWithRawType.java"); } + public void testMethodTypeParameterErased() throws Exception { + String dir = PATH + "/methodTypeParameterErased/"; + doTest(dir + "MethodTypeParameterErased.txt", + dir + "MethodTypeParameterErased.java"); + } + public static class SubclassingKotlinInJavaTest extends KotlinTestWithEnvironmentManagement { public void testSubclassingKotlinInJava() throws Exception { doTest(PATH + "/" + getTestName(true));