diff --git a/compiler/frontend/src/org/jetbrains/kotlin/config/LanguageFeatureSettings.kt b/compiler/frontend/src/org/jetbrains/kotlin/config/LanguageFeatureSettings.kt index 386ec99533b..2caa1910388 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/config/LanguageFeatureSettings.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/config/LanguageFeatureSettings.kt @@ -18,12 +18,13 @@ package org.jetbrains.kotlin.config import org.jetbrains.kotlin.config.LanguageVersion.KOTLIN_1_1 - enum class LanguageFeature(val sinceVersion: LanguageVersion) { // Note: names of these entries are also used in diagnostic tests TypeAliases(KOTLIN_1_1), + BoundCallableReferences(KOTLIN_1_1), LocalDelegatedProperties(KOTLIN_1_1), - TopLevelSealedInheritance(KOTLIN_1_1); + TopLevelSealedInheritance(KOTLIN_1_1), + ; companion object { @JvmStatic 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 49dd6492f30..2ce9d08b0ac 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -18,6 +18,8 @@ package org.jetbrains.kotlin.types.expressions import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.ReflectionTypes +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageFeatureSettings import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor @@ -40,9 +42,6 @@ import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo import javax.inject.Inject -// TODO: use a language level option -val BOUND_REFERENCES_ENABLED by lazy { System.getProperty("kotlin.lang.enable.bound.references") == "true" } - sealed class DoubleColonLHS(val type: KotlinType) { class Expression(val typeInfo: KotlinTypeInfo) : DoubleColonLHS(typeInfo.type!!) @@ -58,7 +57,8 @@ class DoubleColonExpressionResolver( val qualifiedExpressionResolver: QualifiedExpressionResolver, val dataFlowAnalyzer: DataFlowAnalyzer, val reflectionTypes: ReflectionTypes, - val typeResolver: TypeResolver + val typeResolver: TypeResolver, + val languageFeatureSettings: LanguageFeatureSettings ) { private lateinit var expressionTypingServices: ExpressionTypingServices @@ -120,13 +120,20 @@ class DoubleColonExpressionResolver( } } + private fun shouldTryResolveLHSAsExpression(expression: KtDoubleColonExpression): Boolean { + // TODO: improve diagnostic when bound callable references are disabled + if (!languageFeatureSettings.supportsFeature(LanguageFeature.BoundCallableReferences)) return false + + val lhs = expression.receiverExpression ?: return false + return lhs.canBeConsideredProperExpression() && !expression.hasQuestionMarks /* TODO: test this */ + } + private fun resolveDoubleColonLHS( expression: KtExpression, doubleColonExpression: KtDoubleColonExpression, c: ExpressionTypingContext ): DoubleColonLHS? { // First, try resolving the LHS as expression, if possible - if (BOUND_REFERENCES_ENABLED && expression.canBeConsideredProperExpression() && - !doubleColonExpression.hasQuestionMarks /* TODO: test this */) { + if (shouldTryResolveLHSAsExpression(doubleColonExpression)) { val traceForExpr = TemporaryTraceAndCache.create(c, "resolve '::' LHS as expression", expression) val contextForExpr = c.replaceTraceAndCache(traceForExpr) val typeInfo = expressionTypingServices.getTypeInfo(expression, contextForExpr) diff --git a/compiler/testData/diagnostics/tests/callableReference/ea81649_errorPropertyLHS.kt b/compiler/testData/diagnostics/tests/callableReference/ea81649_errorPropertyLHS.kt index 9eda16b6015..16b4f2a174e 100644 --- a/compiler/testData/diagnostics/tests/callableReference/ea81649_errorPropertyLHS.kt +++ b/compiler/testData/diagnostics/tests/callableReference/ea81649_errorPropertyLHS.kt @@ -15,6 +15,6 @@ data class User(val surname: String) fun foo() { bar { - User::surname + User::surname } } diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassLiteralInKClassExtension.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassLiteralInKClassExtension.kt new file mode 100644 index 00000000000..a315491b898 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassLiteralInKClassExtension.kt @@ -0,0 +1,11 @@ +// !LANGUAGE: -BoundCallableReferences +// !DIAGNOSTICS: -CAST_NEVER_SUCCEEDS + +import kotlin.reflect.KClass + +val KClass.java: Class get() = null!! + +val KClass.javaObjectType: Class + get() { + return java.lang.Class::class.java as Class + } diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassLiteralInKClassExtension.txt b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassLiteralInKClassExtension.txt new file mode 100644 index 00000000000..5c0427da0d0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassLiteralInKClassExtension.txt @@ -0,0 +1,4 @@ +package + +public val kotlin.reflect.KClass.java: java.lang.Class +public val kotlin.reflect.KClass.javaObjectType: java.lang.Class diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassReferenceInKClassExtension.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassReferenceInKClassExtension.kt new file mode 100644 index 00000000000..7cac985a352 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassReferenceInKClassExtension.kt @@ -0,0 +1,10 @@ +// !LANGUAGE: -BoundCallableReferences + +import kotlin.reflect.KClass + +val KClass.java: Class get() = null!! + +val KClass.foo: Any? + get() { + return java.lang.Integer::hashCode + } diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassReferenceInKClassExtension.txt b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassReferenceInKClassExtension.txt new file mode 100644 index 00000000000..6c320b6cdad --- /dev/null +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassReferenceInKClassExtension.txt @@ -0,0 +1,4 @@ +package + +public val kotlin.reflect.KClass.foo: kotlin.Any? +public val kotlin.reflect.KClass.java: java.lang.Class diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 5009fa5bdde..2657360b612 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -18383,6 +18383,27 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/noTopLevelSealedInheritance.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class NoBoundCallableReferences extends AbstractDiagnosticsTest { + public void testAllFilesPresentInNoBoundCallableReferences() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("qualifiedJavaClassLiteralInKClassExtension.kt") + public void testQualifiedJavaClassLiteralInKClassExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassLiteralInKClassExtension.kt"); + doTest(fileName); + } + + @TestMetadata("qualifiedJavaClassReferenceInKClassExtension.kt") + public void testQualifiedJavaClassReferenceInKClassExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/noBoundCallableReferences/qualifiedJavaClassReferenceInKClassExtension.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/diagnostics/tests/substitutions")