From 22b558110d983ca80deb8423f80171fd4fc0d0ed Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Fri, 5 Jun 2020 15:44:53 +0300 Subject: [PATCH] Don't apply Unit-conversion for expressions that return Nothing type --- .../resolve/calls/components/UnitTypeConversions.kt | 13 +++++++------ .../unitConversionDisabledForSimpleArguments.fir.kt | 10 ++++++++-- .../unitConversionDisabledForSimpleArguments.kt | 10 ++++++++-- .../unitConversionDisabledForSimpleArguments.txt | 3 ++- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/UnitTypeConversions.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/UnitTypeConversions.kt index 5f0eb6ed0f4..b9fee3061ac 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/UnitTypeConversions.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/UnitTypeConversions.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.isDynamic +import org.jetbrains.kotlin.types.typeUtil.isNothing import org.jetbrains.kotlin.types.typeUtil.isUnit object UnitTypeConversions : ParameterTypeConversion { @@ -26,8 +27,8 @@ object UnitTypeConversions : ParameterTypeConversion { if (argument !is SimpleKotlinCallArgument) return true val receiver = argument.receiver - if (receiver.receiverValue.type.hasUnitOrDynamicReturnType()) return true - if (receiver.typesFromSmartCasts.any { it.hasUnitOrDynamicReturnType() }) return true + if (receiver.receiverValue.type.hasUnitOrSubtypeReturnType()) return true + if (receiver.typesFromSmartCasts.any { it.hasUnitOrSubtypeReturnType() }) return true if ( !expectedParameterType.isBuiltinFunctionalType || @@ -37,10 +38,10 @@ object UnitTypeConversions : ParameterTypeConversion { return false } - private fun KotlinType.hasUnitOrDynamicReturnType(): Boolean = - isFunctionOrKFunctionTypeWithAnySuspendability && arguments.last().type.isUnitOrDynamic() + private fun KotlinType.hasUnitOrSubtypeReturnType(): Boolean = + isFunctionOrKFunctionTypeWithAnySuspendability && arguments.last().type.isUnitOrSubtype() - private fun KotlinType.isUnitOrDynamic(): Boolean = isUnit() || isDynamic() + private fun KotlinType.isUnitOrSubtype(): Boolean = isUnit() || isDynamic() || isNothing() override fun conversionIsNeededBeforeSubtypingCheck(argument: KotlinCallArgument): Boolean = argument is SimpleKotlinCallArgument && argument.receiver.stableType.isFunctionType @@ -51,7 +52,7 @@ object UnitTypeConversions : ParameterTypeConversion { var isFunctionTypeOrSubtype = false val hasReturnTypeInSubtypes = argument.receiver.stableType.isFunctionTypeOrSubtype { isFunctionTypeOrSubtype = true - it.getReturnTypeFromFunctionType().isUnitOrDynamic() + it.getReturnTypeFromFunctionType().isUnitOrSubtype() } if (!isFunctionTypeOrSubtype) return false diff --git a/compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.fir.kt b/compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.fir.kt index d04e50feb9b..9e6eda14483 100644 --- a/compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.fir.kt +++ b/compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.fir.kt @@ -1,4 +1,4 @@ -// !LANGUAGE: -SuspendConversion +// !LANGUAGE: -UnitConversion // !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION fun foo(f: () -> Unit) {} @@ -7,9 +7,15 @@ fun bar(): Int = 0 abstract class SubInt : () -> Int -fun test(f: () -> String, s: SubInt) { +fun T.freeze(): T = TODO() + +fun test(f: () -> String, g: () -> Nothing, h: () -> Nothing?, s: SubInt) { foo { "lambda" } foo(::bar) + foo({ TODO() }.freeze()) + foo(g) + + foo(h) foo(f) foo(s) diff --git a/compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.kt b/compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.kt index b8bf60ebd7f..81b379127c3 100644 --- a/compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.kt +++ b/compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.kt @@ -1,4 +1,4 @@ -// !LANGUAGE: -SuspendConversion +// !LANGUAGE: -UnitConversion // !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION fun foo(f: () -> Unit) {} @@ -7,9 +7,15 @@ fun bar(): Int = 0 abstract class SubInt : () -> Int -fun test(f: () -> String, s: SubInt) { +fun T.freeze(): T = TODO() + +fun test(f: () -> String, g: () -> Nothing, h: () -> Nothing?, s: SubInt) { foo { "lambda" } foo(::bar) + foo({ TODO() }.freeze()) + foo(g) + + foo(h) foo(f) foo(s) diff --git a/compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.txt b/compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.txt index 1c6a0199f7a..ecdb928e6bc 100644 --- a/compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.txt +++ b/compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.txt @@ -2,7 +2,8 @@ package public fun bar(): kotlin.Int public fun foo(/*0*/ f: () -> kotlin.Unit): kotlin.Unit -public fun test(/*0*/ f: () -> kotlin.String, /*1*/ s: SubInt): kotlin.Unit +public fun test(/*0*/ f: () -> kotlin.String, /*1*/ g: () -> kotlin.Nothing, /*2*/ h: () -> kotlin.Nothing?, /*3*/ s: SubInt): kotlin.Unit +public fun T.freeze(): T public abstract class SubInt : () -> kotlin.Int { public constructor SubInt()