From f3385e093ee4336357e642d524a5802068c3cbed Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Mon, 30 Jan 2017 19:02:03 +0300 Subject: [PATCH] Introduce language feature for type inference on generics for callable references #KT-16061 Fixed --- .../kotlin/resolve/TargetPlatform.kt | 5 +- .../CallableReferenceCompatibilityChecker.kt | 43 ++++++++++++ ...noInferenceFeatureForCallableReferences.kt | 67 +++++++++++++++++++ ...oInferenceFeatureForCallableReferences.txt | 45 +++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 6 ++ .../kotlin/config/LanguageVersionSettings.kt | 3 +- 6 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallableReferenceCompatibilityChecker.kt create mode 100644 compiler/testData/diagnostics/tests/callableReference/generic/noInferenceFeatureForCallableReferences.kt create mode 100644 compiler/testData/diagnostics/tests/callableReference/generic/noInferenceFeatureForCallableReferences.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index 5275531ef5b..6974d011358 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 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. @@ -86,7 +86,8 @@ private val DEFAULT_CALL_CHECKERS = listOf( CapturingInClosureChecker(), InlineCheckerWrapper(), SafeCallChecker(), DeprecatedCallChecker, CallReturnsArrayOfNothingChecker(), InfixCallChecker(), OperatorCallChecker(), ConstructorHeaderCallChecker, ProtectedConstructorCallChecker, ApiVersionCallChecker, - CoroutineSuspendCallChecker, BuilderFunctionsCallChecker, DslScopeViolationCallChecker + CoroutineSuspendCallChecker, BuilderFunctionsCallChecker, DslScopeViolationCallChecker, + CallableReferenceCompatibilityChecker() ) private val DEFAULT_TYPE_CHECKERS = emptyList() private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf(DeprecatedClassifierUsageChecker(), ApiVersionClassifierUsageChecker) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallableReferenceCompatibilityChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallableReferenceCompatibilityChecker.kt new file mode 100644 index 00000000000..60789b3d1ff --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallableReferenceCompatibilityChecker.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2017 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.calls.checkers + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.psi.KtCallableReferenceExpression +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.callUtil.isCallableReference +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall + +class CallableReferenceCompatibilityChecker : CallChecker { + override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { + val typeInferenceForCallableReferencesFeature = LanguageFeature.TypeInferenceOnGenericsForCallableReferences + if (context.languageVersionSettings.supportsFeature(typeInferenceForCallableReferencesFeature)) return + + for ((_, resolvedArgument) in resolvedCall.valueArguments) { + inner@ for (argument in resolvedArgument.arguments) { + val argumentExpression = argument.getArgumentExpression() as? KtCallableReferenceExpression ?: continue@inner + val callableReferenceResolvedCall = argumentExpression.callableReference.getResolvedCall(context.trace.bindingContext) ?: continue@inner + if (callableReferenceResolvedCall.call.isCallableReference() && + callableReferenceResolvedCall.candidateDescriptor.typeParameters.isNotEmpty()) { + context.trace.report(Errors.UNSUPPORTED_FEATURE.on(argumentExpression, typeInferenceForCallableReferencesFeature)) + } + } + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/callableReference/generic/noInferenceFeatureForCallableReferences.kt b/compiler/testData/diagnostics/tests/callableReference/generic/noInferenceFeatureForCallableReferences.kt new file mode 100644 index 00000000000..522dc6191ba --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/generic/noInferenceFeatureForCallableReferences.kt @@ -0,0 +1,67 @@ +// !LANGUAGE: -TypeInferenceOnGenericsForCallableReferences +// !DIAGNOSTICS: -UNUSED_VARIABLE, -UNUSED_PARAMETER + +fun bar(s: T) {} +fun complex(t: T, f: (T) -> Unit) {} +fun simple(f: (T) -> Unit) {} + +fun test1() { + complex(1, ::bar) + simple(::bar) +} + +// --- + +fun takeFun(f: (T) -> Unit) {} +fun callFun(f: (T) -> R): R = TODO() + +fun foo(s: T) {} + +open class Wrapper(val value: T) +fun > createWrapper(s: T): R = TODO() + +fun Wrapper.baz(transform: (T) -> Unit): T = TODO() + +fun test2() { + takeFun(::foo) + + callFun>(::createWrapper) + callFun>(::createWrapper) + callFun>(::createWrapper) + + callFun>(::createWrapper).baz(::foo) +} + +// --- + +fun test3() { + val a1: Array Double> = arrayOf(Double::plus, Double::minus) + val a2: Array Double> = arrayOf(Double::plus, Double::minus) +} + +// --- + +class A1 { + fun a1(t: T): Unit {} + fun test1(): (String) -> Unit = A1()::a1 +} + +class A2 { + fun a2(key: K): V = TODO() + + fun test1(): (String) -> Unit = A2()::a2 + fun test2(): (T3) -> T3 = A2()::a2 +} + +// --- + +fun foo1(x: Int?) {} +fun foo1(y: String?) {} +fun foo1(z: Boolean) {} + +fun baz1(element: (T) -> Unit): T? = null + +fun test4() { + val a1: Int? = baz1(::foo1) + val a2: String? = baz1(::foo1) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/callableReference/generic/noInferenceFeatureForCallableReferences.txt b/compiler/testData/diagnostics/tests/callableReference/generic/noInferenceFeatureForCallableReferences.txt new file mode 100644 index 00000000000..fa95869f473 --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/generic/noInferenceFeatureForCallableReferences.txt @@ -0,0 +1,45 @@ +package + +public fun bar(/*0*/ s: T): kotlin.Unit +public fun baz1(/*0*/ element: (T) -> kotlin.Unit): T? +public fun callFun(/*0*/ f: (T) -> R): R +public fun complex(/*0*/ t: T, /*1*/ f: (T) -> kotlin.Unit): kotlin.Unit +public fun > createWrapper(/*0*/ s: T): R +public fun foo(/*0*/ s: T): kotlin.Unit +public fun foo1(/*0*/ z: kotlin.Boolean): kotlin.Unit +public fun foo1(/*0*/ x: kotlin.Int?): kotlin.Unit +public fun foo1(/*0*/ y: kotlin.String?): kotlin.Unit +public fun simple(/*0*/ f: (T) -> kotlin.Unit): kotlin.Unit +public fun takeFun(/*0*/ f: (T) -> kotlin.Unit): kotlin.Unit +public fun test1(): kotlin.Unit +public fun test2(): kotlin.Unit +public fun test3(): kotlin.Unit +public fun test4(): kotlin.Unit +public fun Wrapper.baz(/*0*/ transform: (T) -> kotlin.Unit): T + +public final class A1 { + public constructor A1() + public final fun a1(/*0*/ t: T): 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 + public final fun test1(): (kotlin.String) -> kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class A2 { + public constructor A2() + public final fun a2(/*0*/ key: K): V + 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 final fun test1(): (kotlin.String) -> kotlin.Unit + public final fun test2(): (T3) -> T3 + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class Wrapper { + public constructor Wrapper(/*0*/ value: T) + public final val value: T + 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/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 758411a8041..bf18c1cafaa 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -2298,6 +2298,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("noInferenceFeatureForCallableReferences.kt") + public void testNoInferenceFeatureForCallableReferences() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/generic/noInferenceFeatureForCallableReferences.kt"); + doTest(fileName); + } + @TestMetadata("resolutionGenericCallableWithNullableTypes.kt") public void testResolutionGenericCallableWithNullableTypes() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/generic/resolutionGenericCallableWithNullableTypes.kt"); diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 5fff6a11edb..7011be5b404 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 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. @@ -40,6 +40,7 @@ enum class LanguageFeature(val sinceVersion: LanguageVersion?, val hintUrl: Stri ShortSyntaxForPropertyGetters(KOTLIN_1_1), RefinedSamAdaptersPriority(KOTLIN_1_1), SafeCallBoundSmartCasts(KOTLIN_1_1), + TypeInferenceOnGenericsForCallableReferences(KOTLIN_1_1), // Experimental features MultiPlatformProjects(null, "https://kotlinlang.org/docs/diagnostics/experimental-multitraget-projects"),