diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt index 27f5364e9ac..ef63ec120a0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -98,9 +98,12 @@ class DoubleColonExpressionResolver( } private fun checkClassLiteral(c: ExpressionTypingContext, expression: KtClassLiteralExpression, result: DoubleColonLHS) { - if (result !is DoubleColonLHS.Type) return + if (result is DoubleColonLHS.Expression) { + if (!result.isObject) reportUnsupportedIfNeeded(expression, c) + return + } - val type = result.type + val type = (result as DoubleColonLHS.Type).type val reportError: Boolean if (result.possiblyBareType.isBare) { val descriptor = type.constructor.declarationDescriptor @@ -132,7 +135,7 @@ class DoubleColonExpressionResolver( !isWithoutValueArguments is KtDotQualifiedExpression -> receiverExpression.canBeConsideredProperExpression() && - selectorExpression?.let { it.canBeConsideredProperExpression() } ?: false + selectorExpression?.canBeConsideredProperExpression() ?: false else -> true } } @@ -150,9 +153,6 @@ class DoubleColonExpressionResolver( } private fun shouldTryResolveLHSAsExpression(expression: KtDoubleColonExpression): Boolean { - // TODO: improve diagnostic when bound callable references are disabled - if (!languageVersionSettings.supportsFeature(LanguageFeature.BoundCallableReferences)) return false - val lhs = expression.receiverExpression ?: return false return lhs.canBeConsideredProperExpression() && !expression.hasQuestionMarks /* TODO: test this */ } @@ -162,6 +162,12 @@ class DoubleColonExpressionResolver( return lhs != null && lhs.canBeConsideredProperType() } + private fun reportUnsupportedIfNeeded(expression: KtDoubleColonExpression, c: ExpressionTypingContext) { + if (!languageVersionSettings.supportsFeature(LanguageFeature.BoundCallableReferences)) { + c.trace.report(UNSUPPORTED_FEATURE.on(expression.receiverExpression!!, LanguageFeature.BoundCallableReferences)) + } + } + private fun resolveDoubleColonLHS(doubleColonExpression: KtDoubleColonExpression, c: ExpressionTypingContext): DoubleColonLHS? { val resultForExpr = tryResolveLHS(doubleColonExpression, c, this::shouldTryResolveLHSAsExpression, this::resolveExpressionOnLHS) if (resultForExpr != null) { @@ -432,6 +438,10 @@ class DoubleColonExpressionResolver( if (expression.isEmptyLHS) null else resolveDoubleColonLHS(expression, context) + if (lhsResult is DoubleColonLHS.Expression) { + reportUnsupportedIfNeeded(expression, context) + } + val resolutionResults = resolveCallableReferenceRHS(expression, lhsResult, context, resolveArgumentsMode) diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundCallableReference.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundCallableReference.kt new file mode 100644 index 00000000000..901d8906ab3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundCallableReference.kt @@ -0,0 +1,14 @@ +// !LANGUAGE: -BoundCallableReferences + +class C { companion object } +val ok1 = C::hashCode +val fail1 = C.Companion::hashCode + +object O +val fail2 = O::hashCode + +fun hashCode() {} + +val fail3 = ""::hashCode +val fail4 = (C)::hashCode +val fail5 = (C.Companion)::hashCode diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundCallableReference.txt b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundCallableReference.txt new file mode 100644 index 00000000000..ffd1644c631 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundCallableReference.txt @@ -0,0 +1,30 @@ +package + +public val fail1: kotlin.reflect.KFunction0 +public val fail2: kotlin.reflect.KFunction0 +public val fail3: kotlin.reflect.KFunction0 +public val fail4: kotlin.reflect.KFunction0 +public val fail5: kotlin.reflect.KFunction0 +public val ok1: kotlin.reflect.KFunction1 +public fun hashCode(): kotlin.Unit + +public final class C { + public constructor C() + 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 override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public companion object Companion { + private constructor Companion() + 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 override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public object O { + private constructor O() + 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 override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundClassLiteral.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundClassLiteral.kt new file mode 100644 index 00000000000..80e67613c70 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundClassLiteral.kt @@ -0,0 +1,14 @@ +// !LANGUAGE: -BoundCallableReferences + +class C { companion object } +val ok1 = C::class +val ok2 = C.Companion::class + +object O +val ok3 = O::class + + +val fail1 = ""::class +val fail2 = String?::class +val fail3 = (C)::class +val fail4 = (C.Companion)::class diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundClassLiteral.txt b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundClassLiteral.txt new file mode 100644 index 00000000000..46b7daf7888 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundClassLiteral.txt @@ -0,0 +1,30 @@ +package + +public val fail1: kotlin.reflect.KClass +public val fail2: kotlin.reflect.KClass +public val fail3: kotlin.reflect.KClass +public val fail4: kotlin.reflect.KClass +public val ok1: kotlin.reflect.KClass +public val ok2: kotlin.reflect.KClass +public val ok3: kotlin.reflect.KClass + +public final class C { + public constructor C() + 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 override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public companion object Companion { + private constructor Companion() + 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 override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public object O { + private constructor O() + 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 override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassLiteralInKClassExtension.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassLiteralInKClassExtension.kt index 843819e62de..835d4f813ec 100644 --- a/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassLiteralInKClassExtension.kt +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassLiteralInKClassExtension.kt @@ -7,5 +7,5 @@ val KClass.java: Class get() = null!! val KClass.javaObjectType: Class get() { - return java.lang.Class::class.java as Class + return java.lang.Class::class.java as Class } diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassReferenceInKClassExtension.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassReferenceInKClassExtension.kt index 7cac985a352..347ab0aed63 100644 --- a/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassReferenceInKClassExtension.kt +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassReferenceInKClassExtension.kt @@ -6,5 +6,5 @@ val KClass.java: Class get() = null!! val KClass.foo: Any? get() { - return java.lang.Integer::hashCode + return java.lang.Integer::hashCode } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 43ba6bfca48..9f41d3aa4d2 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -19457,6 +19457,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("boundCallableReference.kt") + public void testBoundCallableReference() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundCallableReference.kt"); + doTest(fileName); + } + + @TestMetadata("boundClassLiteral.kt") + public void testBoundClassLiteral() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/boundClassLiteral.kt"); + doTest(fileName); + } + @TestMetadata("qualifiedJavaClassLiteralInKClassExtension.kt") public void testQualifiedJavaClassLiteralInKClassExtension() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassLiteralInKClassExtension.kt");