From ea4ab4676505beaefd8f0f7bc66fdfc5e058dcf3 Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Wed, 14 Jul 2021 17:40:58 +0300 Subject: [PATCH] Report implicit inferred Nothing only for own type parameters and in delegation resolve ^KT-47724 Fixed --- ...irOldFrontendDiagnosticsTestGenerated.java | 6 +++++ ...DiagnosticsWithLightTreeTestGenerated.java | 6 +++++ ...plicitNothingAsTypeParameterCallChecker.kt | 24 ++++++++++++++----- ...icitNothingOnlyForOwnTypeParameters.fir.kt | 11 +++++++++ ...ImplicitNothingOnlyForOwnTypeParameters.kt | 11 +++++++++ ...mplicitNothingOnlyForOwnTypeParameters.txt | 12 ++++++++++ .../implicitNothingInReturnPosition.kt | 2 +- .../test/runners/DiagnosticTestGenerated.java | 6 +++++ ...CompilerTestFE10TestdataTestGenerated.java | 6 +++++ 9 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.kt create mode 100644 compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.txt diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index ccf73dba559..2a0137e0ec8 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -14228,6 +14228,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/inference/nothingType/reifiedParameterWithRecursiveBound.kt"); } + @Test + @TestMetadata("reportImplicitNothingOnlyForOwnTypeParameters.kt") + public void testReportImplicitNothingOnlyForOwnTypeParameters() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.kt"); + } + @Test @TestMetadata("specialCallWithMaterializeAndExpectedType.kt") public void testSpecialCallWithMaterializeAndExpectedType() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index b473146e4cd..1e6311ea7bc 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -14228,6 +14228,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/inference/nothingType/reifiedParameterWithRecursiveBound.kt"); } + @Test + @TestMetadata("reportImplicitNothingOnlyForOwnTypeParameters.kt") + public void testReportImplicitNothingOnlyForOwnTypeParameters() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.kt"); + } + @Test @TestMetadata("specialCallWithMaterializeAndExpectedType.kt") public void testSpecialCallWithMaterializeAndExpectedType() throws Exception { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ImplicitNothingAsTypeParameterCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ImplicitNothingAsTypeParameterCallChecker.kt index 90cbba19020..973227f4276 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ImplicitNothingAsTypeParameterCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ImplicitNothingAsTypeParameterCallChecker.kt @@ -8,6 +8,8 @@ package org.jetbrains.kotlin.resolve.calls.checkers import com.intellij.psi.PsiElement import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType import org.jetbrains.kotlin.builtins.isFunctionOrSuspendFunctionType +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnceWrtDiagnosticFactoryList import org.jetbrains.kotlin.resolve.BindingContext @@ -19,6 +21,7 @@ import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl import org.jetbrains.kotlin.resolve.calls.tower.psiExpression import org.jetbrains.kotlin.resolve.calls.tower.psiKotlinCall +import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind import org.jetbrains.kotlin.types.DeferredType import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils @@ -51,7 +54,7 @@ object ImplicitNothingAsTypeParameterCallChecker : CallChecker { ): Boolean { val resultingDescriptor = resolvedCall.resultingDescriptor val expectedType = context.resolutionContext.expectedType - val inferredReturnType = resultingDescriptor.returnType + val inferredReturnType = resultingDescriptor.returnType ?: return false val isBuiltinFunctionalType = resolvedCall.resultingDescriptor.dispatchReceiverParameter?.value?.type?.isBuiltinFunctionalType == true @@ -61,12 +64,13 @@ object ImplicitNothingAsTypeParameterCallChecker : CallChecker { val lambdasFromArgumentsReturnTypes = resolvedCall.candidateDescriptor.valueParameters.filter { it.type.isFunctionOrSuspendFunctionType } .map { it.returnType?.arguments?.last()?.type }.toSet() - val unsubstitutedReturnType = resultingDescriptor.original.returnType - val hasImplicitNothing = inferredReturnType?.isNothingOrNullableNothing() == true && - unsubstitutedReturnType?.isTypeParameter() == true && - (TypeUtils.noExpectedType(expectedType) || !expectedType.isNothing()) + val unsubstitutedReturnType = resultingDescriptor.original.returnType ?: return false + val hasImplicitNothing = inferredReturnType.isNothingOrNullableNothing() + && unsubstitutedReturnType.isTypeParameter() + && (isOwnTypeParameter(unsubstitutedReturnType, resultingDescriptor.original) || isDelegationContext(context)) + && (TypeUtils.noExpectedType(expectedType) || !expectedType.isNothing()) - if (inferredReturnType?.isNullableNothing() == true && unsubstitutedReturnType?.isMarkedNullable == false) { + if (inferredReturnType.isNullableNothing() && !unsubstitutedReturnType.isMarkedNullable) { return false } @@ -81,6 +85,14 @@ object ImplicitNothingAsTypeParameterCallChecker : CallChecker { return false } + private fun isOwnTypeParameter(type: KotlinType, declaration: CallableDescriptor): Boolean { + val typeParameter = type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return false + return typeParameter.containingDeclaration == declaration + } + + private fun isDelegationContext(context: CallCheckerContext) = + context.resolutionContext.scope.kind == LexicalScopeKind.PROPERTY_DELEGATE_METHOD + private fun ResolvedAtom.getResolvedCallAtom(bindingContext: BindingContext): ResolvedCallAtom? { if (this is SingleCallResolutionResult) return resultCallAtom diff --git a/compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.fir.kt b/compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.fir.kt new file mode 100644 index 00000000000..e1451fc7e96 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.fir.kt @@ -0,0 +1,11 @@ +fun runCatching(block: () -> R) = null as Result + +class Result { + fun getOrNull(): T? = null +} + +fun main() { + runCatching { + null + }.getOrNull() // don't report IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION +} diff --git a/compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.kt b/compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.kt new file mode 100644 index 00000000000..578b4129f24 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.kt @@ -0,0 +1,11 @@ +fun runCatching(block: () -> R) = null as Result + +class Result { + fun getOrNull(): T? = null +} + +fun main() { + runCatching { + null + }.getOrNull() // don't report IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION +} diff --git a/compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.txt b/compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.txt new file mode 100644 index 00000000000..47743c7709f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.txt @@ -0,0 +1,12 @@ +package + +public fun main(): kotlin.Unit +public fun runCatching(/*0*/ block: () -> R): Result + +public final class Result { + public constructor Result() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun getOrNull(): T? + 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/typeParameters/implicitNothingInReturnPosition.kt b/compiler/testData/diagnostics/tests/typeParameters/implicitNothingInReturnPosition.kt index ebbb5d1c5af..350f7a3afda 100644 --- a/compiler/testData/diagnostics/tests/typeParameters/implicitNothingInReturnPosition.kt +++ b/compiler/testData/diagnostics/tests/typeParameters/implicitNothingInReturnPosition.kt @@ -90,7 +90,7 @@ interface Worker interface RenderContext val emptyOrNull: List? = null -val x = emptyOrNull?.get(0) +val x = emptyOrNull?.get(0) val errorCompletion = { e: Throwable -> throw Exception() } diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 68d307b3f8f..f907571d495 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -14234,6 +14234,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inference/nothingType/reifiedParameterWithRecursiveBound.kt"); } + @Test + @TestMetadata("reportImplicitNothingOnlyForOwnTypeParameters.kt") + public void testReportImplicitNothingOnlyForOwnTypeParameters() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.kt"); + } + @Test @TestMetadata("specialCallWithMaterializeAndExpectedType.kt") public void testSpecialCallWithMaterializeAndExpectedType() throws Exception { diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 84c0dc830aa..8c8232286fc 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -14228,6 +14228,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/inference/nothingType/reifiedParameterWithRecursiveBound.kt"); } + @Test + @TestMetadata("reportImplicitNothingOnlyForOwnTypeParameters.kt") + public void testReportImplicitNothingOnlyForOwnTypeParameters() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/nothingType/reportImplicitNothingOnlyForOwnTypeParameters.kt"); + } + @Test @TestMetadata("specialCallWithMaterializeAndExpectedType.kt") public void testSpecialCallWithMaterializeAndExpectedType() throws Exception {