Allow Result return type and nullability operators on Result type

by default
This commit is contained in:
Ilmir Usmanov
2021-03-18 17:18:10 +01:00
committed by Space
parent 6473d2a7c8
commit 9c97f1ce35
15 changed files with 89 additions and 90 deletions
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils
class ResultTypeWithNullableOperatorsChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
if (context.languageVersionSettings.supportsFeature(LanguageFeature.AllowNullOperatorsForResult)) return
if (context.languageVersionSettings.supportsFeature(LanguageFeature.AllowNullOperatorsForResultAndResultReturnTypeByDefault)) return
val name = resolvedCall.resultingDescriptor.name
val operationNode = resolvedCall.call.callOperationNode
@@ -19,13 +19,16 @@ import org.jetbrains.kotlin.types.KotlinType
class ResultClassInReturnTypeChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
val languageVersionSettings = context.languageVersionSettings
if (
languageVersionSettings.getFlag(AnalysisFlags.allowResultReturnType) ||
(languageVersionSettings.getFeatureSupport(LanguageFeature.InlineClasses) == LanguageFeature.State.ENABLED ||
if (languageVersionSettings.getFlag(AnalysisFlags.allowResultReturnType)) return
if ((languageVersionSettings.getFeatureSupport(LanguageFeature.InlineClasses) == LanguageFeature.State.ENABLED ||
languageVersionSettings.supportsFeature(LanguageFeature.JvmInlineValueClasses)) &&
languageVersionSettings.supportsFeature(LanguageFeature.AllowResultInReturnType)
) return
if (languageVersionSettings.supportsFeature(LanguageFeature.AllowNullOperatorsForResultAndResultReturnTypeByDefault)) return
if (declaration !is KtCallableDeclaration || descriptor !is CallableMemberDescriptor) return
val returnType = descriptor.returnType ?: return
@@ -0,0 +1,5 @@
$TESTDATA_DIR$/resultInReturnType.kt
-d
$TEMP_DIR$
-language-version
1.5
@@ -0,0 +1 @@
OK
@@ -1,4 +1,6 @@
$TESTDATA_DIR$/resultInReturnType.kt
-d
$TEMP_DIR$
-Xinline-classes
-Xinline-classes
-language-version
1.4
@@ -1,4 +1,6 @@
$TESTDATA_DIR$/resultInReturnType.kt
-d
$TEMP_DIR$
-XXLanguage\:+InlineClasses
-XXLanguage\:+InlineClasses
-language-version
1.4
@@ -16,14 +16,14 @@ fun baz(r: Result<Int>) {}
fun returnsInlineClass() = Foo(1)
@JvmName("test")
fun returnsKotlinResult(a: Result<Int>): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = a
fun returnsKotlinResult(a: Result<Int>): Result<Int> = a
class C {
@JvmName("test")
fun returnsInlineClass() = Foo(1)
@JvmName("test")
fun returnsKotlinResult(a: Result<Int>): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = a
fun returnsKotlinResult(a: Result<Int>): Result<Int> = a
}
@JvmName("extensionFun")
@@ -2,6 +2,6 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION
fun test(r: Result<Int>?) {
r <!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?:<!> 0
r<!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?.<!>isFailure
r ?: 0
r?.isFailure
}
@@ -5,5 +5,5 @@ fun result(): Result<Int> = TODO()
val resultP: Result<Int> = result()
fun f(r1: Result<Int>?) {
r1 <!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?:<!> <!UNUSED_EXPRESSION!>0<!>
r1 ?: <!UNUSED_EXPRESSION!>0<!>
}
@@ -1,4 +1,4 @@
// !LANGUAGE: +InlineClasses -AllowResultInReturnType
fun result(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
val resultP: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = result()
fun result(): Result<Int> = TODO()
val resultP: Result<Int> = result()
@@ -16,105 +16,105 @@ fun params(
class CtorParams(r1: Result<Int>)
fun returnTypePublic(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
internal fun returnTypeInternal(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
private fun returnTypePrivate(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
fun returnTypeNullable(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int>?<!> = TODO()
fun returnTypeAlias(): <!RESULT_CLASS_IN_RETURN_TYPE!>ResultAlias<Int><!> = TODO()
fun <!RESULT_CLASS_IN_RETURN_TYPE!>returnInferred<!>(r1: Result<Int>, r2: ResultAlias<Int>, b: Boolean) = if (b) r1 else r2
fun returnTypePublic(): Result<Int> = TODO()
internal fun returnTypeInternal(): Result<Int> = TODO()
private fun returnTypePrivate(): Result<Int> = TODO()
fun returnTypeNullable(): Result<Int>? = TODO()
fun returnTypeAlias(): ResultAlias<Int> = TODO()
fun returnInferred(r1: Result<Int>, r2: ResultAlias<Int>, b: Boolean) = if (b) r1 else r2
fun returnTypeInline(): InlineResult<Int> = TODO()
fun returnContainer(): List<Result<Int>> = TODO()
val topLevelP: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
val <!RESULT_CLASS_IN_RETURN_TYPE!>topLevelPInferred<!> = topLevelP
internal val topLevelPInternal: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
val topLevelP: Result<Int> = TODO()
val topLevelPInferred = topLevelP
internal val topLevelPInternal: Result<Int> = TODO()
private val topLevelPPrivate: Result<Int> = TODO()
private val topLevelPPrivateInferred = topLevelP
private val topLevelPPrivateCustomGetter: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!>
private val topLevelPPrivateCustomGetter: Result<Int>
get() = TODO()
val asFunctional: () -> Result<Int> = TODO()
open class PublicCls(
val r1: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<String><!>,
val r2: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int>?<!>,
val r3: <!RESULT_CLASS_IN_RETURN_TYPE!>ResultAlias<Int><!>,
val r4: <!RESULT_CLASS_IN_RETURN_TYPE!>ResultAlias<Int>?<!>,
val r1: Result<String>,
val r2: Result<Int>?,
val r3: ResultAlias<Int>,
val r4: ResultAlias<Int>?,
val r5: InlineResult<Int>,
internal val r6: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!>,
internal val r6: Result<Int>,
private val r7: Result<Int>,
val r8: List<Result<Int>>
) {
val p1: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
var p2: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
val p3: <!RESULT_CLASS_IN_RETURN_TYPE!>ResultAlias<Int>?<!> = TODO()
val p1: Result<Int> = TODO()
var p2: Result<Int> = TODO()
val p3: ResultAlias<Int>? = TODO()
val <!RESULT_CLASS_IN_RETURN_TYPE!>p4<!> = p1
val p4 = p1
internal val p5: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
internal val p5: Result<Int> = TODO()
private var p6: Result<Int> = TODO()
internal val <!RESULT_CLASS_IN_RETURN_TYPE!>p7<!> = p1
protected val <!RESULT_CLASS_IN_RETURN_TYPE!>p8<!> = p1
internal val p7 = p1
protected val p8 = p1
fun returnInCls(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
protected fun returnInClsProtected(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
private fun returnInClsPrivate(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
fun returnInCls(): Result<Int> = TODO()
protected fun returnInClsProtected(): Result<Int> = TODO()
private fun returnInClsPrivate(): Result<Int> = TODO()
}
internal open class InternalCls(
val r1: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!>,
val r2: <!RESULT_CLASS_IN_RETURN_TYPE!>ResultAlias<Int>?<!>,
val r1: Result<Int>,
val r2: ResultAlias<Int>?,
val r3: List<Result<Int>>
) {
companion object {
val cr1: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
val cr1: Result<Int> = TODO()
private val cr2: Result<Int> = TODO()
}
val <!RESULT_CLASS_IN_RETURN_TYPE!>p1<!> = r1
val p2: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<String><!> = TODO()
val p1 = r1
val p2: Result<String> = TODO()
protected val <!RESULT_CLASS_IN_RETURN_TYPE!>p3<!> = p1
protected val p3 = p1
fun returnInInternal(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
protected fun returnInClsProtected(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
fun returnInInternal(): Result<Int> = TODO()
protected fun returnInClsProtected(): Result<Int> = TODO()
}
private class PrivateCls(
val r1: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!>,
val r2: <!RESULT_CLASS_IN_RETURN_TYPE!>ResultAlias<Int>?<!>,
val r1: Result<Int>,
val r2: ResultAlias<Int>?,
val r3: List<Result<Int>>
) {
companion object {
val cr1: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
val cr1: Result<Int> = TODO()
private val cr2: Result<Int> = TODO()
}
val <!RESULT_CLASS_IN_RETURN_TYPE!>p1<!> = r1
val p2: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<String><!> = TODO()
val p1 = r1
val p2: Result<String> = TODO()
fun returnInPrivate(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
fun returnInPrivate(): Result<Int> = TODO()
}
fun local(r: Result<Int>) {
val l1: Result<Int>? = null
val l2 = r
fun localFun(): <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = TODO()
fun localFun(): Result<Int> = TODO()
class F {
val p1: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int><!> = r
val <!RESULT_CLASS_IN_RETURN_TYPE!>p2<!> = r
val p1: Result<Int> = r
val p2 = r
}
}
@@ -4,7 +4,7 @@
fun <T> id(x: T): T = x
private val asFun: () -> Result<Int>? = TODO()
private val Int.intResult: <!RESULT_CLASS_IN_RETURN_TYPE!>Result<Int>?<!>
private val Int.intResult: Result<Int>?
get() = null
fun returnInt(): Int? = 0
@@ -12,29 +12,29 @@ fun returnInt(): Int? = 0
fun nullableOperators(r1: Result<Int>?, b: Boolean) {
if (b) {
r1<!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>!!<!>
asFun()<!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>!!<!>
returnInt()?.intResult<!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>!!<!>.toString()
r1!!
asFun()!!
returnInt()?.intResult!!.toString()
}
if (b) {
id(r1)<!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>!!<!>
id(r1)!!
}
if (b) {
r1<!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?.<!>toString()
r1<!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?.<!>let { }
returnInt()?.intResult<!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?.<!>toString()
asFun()<!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?.<!>toString()
id(r1)<!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?.<!>toString()
r1?.toString()
r1?.let { }
returnInt()?.intResult?.toString()
asFun()?.toString()
id(r1)?.toString()
}
if (b) {
r1 <!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?:<!> 0
r1 <!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?:<!> r1
asFun() <!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?:<!> r1 <!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?:<!> 0
id(asFun()) <!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?:<!> 0
r1 ?: 0
r1 ?: r1
asFun() ?: r1 ?: 0
id(asFun()) ?: 0
returnInt() ?: returnInt() ?: asFun() <!RESULT_CLASS_WITH_NULLABLE_OPERATOR!>?:<!> 0
returnInt() ?: returnInt() ?: asFun() ?: 0
}
}
@@ -706,6 +706,11 @@ public class CliTestGenerated extends AbstractCliTest {
runTest("compiler/testData/cli/jvm/progressiveModeOn.args");
}
@TestMetadata("resultInReturnTypeSupportedByDefault15.args")
public void testResultInReturnTypeSupportedByDefault15() throws Exception {
runTest("compiler/testData/cli/jvm/resultInReturnTypeSupportedByDefault15.args");
}
@TestMetadata("resultInReturnTypeUnsupportedByDefault14.args")
public void testResultInReturnTypeUnsupportedByDefault14() throws Exception {
runTest("compiler/testData/cli/jvm/resultInReturnTypeUnsupportedByDefault14.args");
@@ -239,15 +239,6 @@ class LauncherScriptTest : TestCaseWithTmpdir() {
}
fun testScriptWithXArguments() {
runProcess(
"kotlin", "$testDataDirectory/funWithResultReturn.kts",
expectedExitCode = 1,
expectedStderr = """error: 'kotlin.Result' cannot be used as a return type (funWithResultReturn.kts:2:11)
compiler/testData/launcher/funWithResultReturn.kts:2:11: error: 'kotlin.Result' cannot be used as a return type
fun f() : Result<Int> = Result.success(42)
^
"""
)
runProcess("kotlin", "-Xallow-result-return-type", "$testDataDirectory/funWithResultReturn.kts", expectedStdout = "42\n")
}
@@ -308,18 +299,6 @@ println(42)
"kotlin", "-howtorun", "script", "$testDataDirectory/funWithResultReturn.myscript",
expectedExitCode = 1, expectedStderr = "error: unrecognized script type: funWithResultReturn.myscript; Specify path to the script file as the first argument\n"
)
runProcess(
"kotlin", "-howtorun", ".kts", "$testDataDirectory/funWithResultReturn.myscript",
expectedExitCode = 1, expectedStderr = """error: unresolved reference: CompilerOptions (funWithResultReturn.myscript:1:7)
error: 'kotlin.Result' cannot be used as a return type (funWithResultReturn.myscript:3:11)
compiler/testData/launcher/funWithResultReturn.myscript:1:7: error: unresolved reference: CompilerOptions
@file:CompilerOptions("-Xallow-result-return-type")
^
compiler/testData/launcher/funWithResultReturn.myscript:3:11: error: 'kotlin.Result' cannot be used as a return type
fun f() : Result<Int> = Result.success(42)
^
"""
)
runProcess(
"kotlin", "-howtorun", ".main.kts", "$testDataDirectory/funWithResultReturn.myscript",
expectedStdout = "42\n"
@@ -116,6 +116,7 @@ enum class LanguageFeature(
AllowAssigningArrayElementsToVarargsInNamedFormForFunctions(KOTLIN_1_4),
AllowNullOperatorsForResult(KOTLIN_1_4),
AllowResultInReturnType(KOTLIN_1_4, defaultState = State.DISABLED),
AllowNullOperatorsForResultAndResultReturnTypeByDefault(KOTLIN_1_5, defaultState = State.ENABLED),
PreferJavaFieldOverload(KOTLIN_1_4),
AllowContractsForNonOverridableMembers(KOTLIN_1_4),
AllowReifiedGenericsInContracts(KOTLIN_1_4),