diff --git a/.idea/runConfigurations/Java_8_Tests.xml b/.idea/runConfigurations/Java_8_Tests.xml
index fe2a0374141..286ba437cba 100644
--- a/.idea/runConfigurations/Java_8_Tests.xml
+++ b/.idea/runConfigurations/Java_8_Tests.xml
@@ -7,9 +7,9 @@
-
+
-
+
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java
index f33a8102320..89a93da2578 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java
@@ -59,6 +59,7 @@ import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
+import org.jetbrains.kotlin.resolve.calls.CallResolverUtil;
import org.jetbrains.kotlin.resolve.calls.model.*;
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject;
@@ -2257,7 +2258,7 @@ public class ExpressionCodegen extends JetVisitor implem
@NotNull
public StackValue invokeFunction(@NotNull Call call, @NotNull ResolvedCall> resolvedCall, @NotNull StackValue receiver) {
FunctionDescriptor fd = accessibleFunctionDescriptor(resolvedCall);
- JetSuperExpression superCallExpression = getSuperCallExpression(call);
+ JetSuperExpression superCallExpression = CallResolverUtil.getSuperCallExpression(call);
boolean superCall = superCallExpression != null;
if (superCall && !isInterface(fd.getContainingDeclaration())) {
@@ -2274,18 +2275,6 @@ public class ExpressionCodegen extends JetVisitor implem
return callable.invokeMethodWithArguments(resolvedCall, receiver, this);
}
- @Nullable
- private static JetSuperExpression getSuperCallExpression(@NotNull Call call) {
- ReceiverValue explicitReceiver = call.getExplicitReceiver();
- if (explicitReceiver instanceof ExpressionReceiver) {
- JetExpression receiverExpression = ((ExpressionReceiver) explicitReceiver).getExpression();
- if (receiverExpression instanceof JetSuperExpression) {
- return (JetSuperExpression) receiverExpression;
- }
- }
- return null;
- }
-
// Find the first parent of the current context which corresponds to a subclass of a given class
@NotNull
private static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) {
diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmCheckerProvider.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmCheckerProvider.kt
index a9d965bf4da..6f0d765af11 100644
--- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmCheckerProvider.kt
+++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmCheckerProvider.kt
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability
import org.jetbrains.kotlin.resolve.jvm.calls.checkers.NeedSyntheticChecker
+import org.jetbrains.kotlin.resolve.jvm.calls.checkers.TraitDefaultMethodCallChecker
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.NullabilityInformationSource
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
@@ -52,7 +53,10 @@ public object KotlinJvmCheckerProvider : AdditionalCheckerProvider(
ReifiedTypeParameterAnnotationChecker(),
NativeFunChecker(),
OverloadsAnnotationChecker()),
- additionalCallCheckers = listOf(NeedSyntheticChecker(), JavaAnnotationCallChecker(), JavaAnnotationMethodCallChecker()),
+
+ additionalCallCheckers = listOf(NeedSyntheticChecker(), JavaAnnotationCallChecker(),
+ JavaAnnotationMethodCallChecker(), TraitDefaultMethodCallChecker()),
+
additionalTypeCheckers = listOf(JavaNullabilityWarningsChecker())
)
diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/calls/checkers/TraitDefaultMethodCallChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/calls/checkers/TraitDefaultMethodCallChecker.kt
new file mode 100644
index 00000000000..bb556a97549
--- /dev/null
+++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/calls/checkers/TraitDefaultMethodCallChecker.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2015 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.kotlin.resolve.jvm.calls.checkers
+
+import com.intellij.psi.util.PsiTreeUtil
+import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
+import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
+import org.jetbrains.kotlin.psi.JetExpression
+import org.jetbrains.kotlin.resolve.DescriptorUtils
+import org.jetbrains.kotlin.resolve.calls.CallResolverUtil
+import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
+import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
+import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
+import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
+
+public class TraitDefaultMethodCallChecker : CallChecker {
+
+ override fun check(resolvedCall: ResolvedCall, context: BasicCallResolutionContext) {
+ val jetSuperExpression = CallResolverUtil.getSuperCallExpression(resolvedCall.getCall())
+ if (jetSuperExpression == null) return
+
+ val targetDescriptor = resolvedCall.getResultingDescriptor().getOriginal()
+ val containerDescriptor = targetDescriptor.getContainingDeclaration()
+
+ if (containerDescriptor is JavaClassDescriptor && DescriptorUtils.isTrait(containerDescriptor)) {
+ //is java interface default method called from trait
+ val classifier = DescriptorUtils.getParentOfType(context.scope.getContainingDeclaration(), javaClass())
+
+ if (classifier != null && DescriptorUtils.isTrait(classifier)) {
+ context.trace.report(
+ ErrorsJvm.TRAIT_CANT_CALL_DEFAULT_METHOD_VIA_SUPER.on(
+ PsiTreeUtil.getParentOfType(resolvedCall.getCall().getCallElement(), javaClass())
+ )
+ )
+ }
+ }
+
+ }
+}
diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java
index e34ac3d291e..65c979439e2 100644
--- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java
+++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java
@@ -64,6 +64,8 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
MAP.put(ErrorsJvm.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS,
"Expected type does not accept nulls in {0}, but the value may be null in {1}", Renderers.TO_STRING, Renderers.TO_STRING);
+
+ MAP.put(ErrorsJvm.TRAIT_CANT_CALL_DEFAULT_METHOD_VIA_SUPER, "Traits can't call Java default methods via super");
}
diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java
index 733dbf8575e..9c69e64a07f 100644
--- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java
+++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java
@@ -55,6 +55,8 @@ public interface ErrorsJvm {
DiagnosticFactory0 JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0 DEPRECATED_ANNOTATION_METHOD_CALL = DiagnosticFactory0.create(WARNING);
+ DiagnosticFactory0 TRAIT_CANT_CALL_DEFAULT_METHOD_VIA_SUPER = DiagnosticFactory0.create(ERROR);
+
// TODO: make this a warning
DiagnosticFactory1 NO_REFLECTION_IN_CLASS_PATH = DiagnosticFactory1.create(ERROR);
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.java
index bbb510a9d25..904b0c54e8e 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.java
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
import org.jetbrains.kotlin.psi.Call;
import org.jetbrains.kotlin.psi.JetExpression;
import org.jetbrains.kotlin.psi.JetSimpleNameExpression;
+import org.jetbrains.kotlin.psi.JetSuperExpression;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
@@ -151,4 +152,15 @@ public class CallResolverUtil {
if (call.getCallType() != Call.CallType.INVOKE || isInvokeCallOnVariable(call)) return false;
return call.getExplicitReceiver().exists() && call.getDispatchReceiver().exists();
}
+
+ public static JetSuperExpression getSuperCallExpression(@NotNull Call call) {
+ ReceiverValue explicitReceiver = call.getExplicitReceiver();
+ if (explicitReceiver instanceof ExpressionReceiver) {
+ JetExpression receiverExpression = ((ExpressionReceiver) explicitReceiver).getExpression();
+ if (receiverExpression instanceof JetSuperExpression) {
+ return (JetSuperExpression) receiverExpression;
+ }
+ }
+ return null;
+ }
}
diff --git a/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.kt b/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.kt
new file mode 100644
index 00000000000..3ea6f225197
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.kt
@@ -0,0 +1,24 @@
+// FILE: Test.java
+public interface Test {
+ default String test() {
+ return "123";
+ }
+}
+
+// FILE: test.kt
+trait KTrait : Test {
+ fun ktest() {
+ super.test()
+
+ test()
+ }
+}
+
+
+class A : KTrait {
+ fun a() {
+ super.test()
+
+ test()
+ }
+}
diff --git a/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.txt b/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.txt
new file mode 100644
index 00000000000..5adc7c27c95
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.txt
@@ -0,0 +1,26 @@
+package
+
+internal final class A : KTrait {
+ public constructor A()
+ internal final fun a(): kotlin.Unit
+ public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+ internal open override /*1*/ /*fake_override*/ fun ktest(): kotlin.Unit
+ public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
+ public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
+
+internal trait KTrait : Test {
+ public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+ internal open fun ktest(): kotlin.Unit
+ public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
+ public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
+
+public trait Test {
+ public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+ public open fun test(): kotlin.String!
+ public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/traitSuperCall.kt b/compiler/testData/diagnostics/tests/thisAndSuper/traitSuperCall.kt
new file mode 100644
index 00000000000..297cb817b14
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/thisAndSuper/traitSuperCall.kt
@@ -0,0 +1,24 @@
+// FILE: test.kt
+
+public trait Test {
+ fun test(): String {
+ return "123";
+ }
+}
+
+trait KTrait : Test {
+ fun ktest() {
+ super.test()
+
+ test()
+ }
+}
+
+class A : KTrait {
+ fun b() {
+ super.test()
+
+ test()
+ }
+}
+
diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/traitSuperCall.txt b/compiler/testData/diagnostics/tests/thisAndSuper/traitSuperCall.txt
new file mode 100644
index 00000000000..20d88207c5b
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/thisAndSuper/traitSuperCall.txt
@@ -0,0 +1,26 @@
+package
+
+internal final class A : KTrait {
+ public constructor A()
+ internal final fun b(): kotlin.Unit
+ public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+ internal open override /*1*/ /*fake_override*/ fun ktest(): kotlin.Unit
+ internal open override /*1*/ /*fake_override*/ fun test(): kotlin.String
+ public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
+
+internal trait KTrait : Test {
+ public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+ internal open fun ktest(): kotlin.Unit
+ internal open override /*1*/ /*fake_override*/ fun test(): kotlin.String
+ public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
+
+public trait Test {
+ public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+ public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+ internal open fun test(): kotlin.String
+ public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java
index a99b4e6f200..0e3b10da63e 100644
--- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java
@@ -7347,6 +7347,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
+ @TestMetadata("traitDefaultCall.kt")
+ public void testTraitDefaultCall() throws Exception {
+ String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/traitDefaultCall.kt");
+ doTest(fileName);
+ }
+
@TestMetadata("UnboxingNulls.kt")
public void testUnboxingNulls() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/UnboxingNulls.kt");
@@ -12326,6 +12332,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/thisAndSuper/thisInToplevelFunction.kt");
doTest(fileName);
}
+
+ @TestMetadata("traitSuperCall.kt")
+ public void testTraitSuperCall() throws Exception {
+ String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/thisAndSuper/traitSuperCall.kt");
+ doTest(fileName);
+ }
}
@TestMetadata("compiler/testData/diagnostics/tests/traitWithRequired")
diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt
index 9f93a1b74c9..d8ef0840583 100644
--- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt
+++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt
@@ -313,6 +313,7 @@ fun main(args: Array) {
}
}
+
testGroup("idea/tests", "idea/testData") {
testClass(javaClass()) {