From 43c084fde3b1c2fcd7c6bfa7a5a15813657ed553 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 11 Apr 2017 16:01:27 +0300 Subject: [PATCH] Simplify coroutine generation in JS backend Stop making aliasing suspend function descriptor with reference to instance of state machine. This may cause problems in some cases, for example, when compiling recursive suspend function. See KT-17281. Instead, make alias for synthetic continuation parameter. This additionally required some refactoring, e.g. *always* generating continuation parameter during codegen. --- .../box/coroutines/recursiveSuspend.kt | 42 +++++++++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 6 +++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++ .../LightAnalysisModeTestGenerated.java | 6 +++ .../coroutine/CoroutineFunctionTransformer.kt | 38 ++++++----------- .../semantics/JsCodegenBoxTestGenerated.java | 6 +++ .../callTranslator/CallTranslator.kt | 2 +- .../translate/context/TranslationContext.java | 3 +- .../declaration/AbstractDeclarationVisitor.kt | 9 +--- .../expression/FunctionTranslator.kt | 8 ++++ .../expression/LiteralFunctionTranslator.kt | 18 +------- .../reference/CallArgumentTranslator.kt | 2 +- .../js/translate/utils/TranslationUtils.java | 29 ++----------- 13 files changed, 95 insertions(+), 80 deletions(-) create mode 100644 compiler/testData/codegen/box/coroutines/recursiveSuspend.kt diff --git a/compiler/testData/codegen/box/coroutines/recursiveSuspend.kt b/compiler/testData/codegen/box/coroutines/recursiveSuspend.kt new file mode 100644 index 00000000000..099cbb57781 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/recursiveSuspend.kt @@ -0,0 +1,42 @@ +// IGNORE_BACKEND: NATIVE +// WITH_RUNTIME +// WITH_COROUTINES +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +fun box(): String { + var result = 0 + + builder { + result = factorial(4) + } + + while (postponed != null) { + postponed!!() + } + + if (result != 24) return "fail1: $result" + if (log != "1;1;2;6;24;") return "fail2: $log" + + return "OK" +} + +suspend fun factorial(a: Int): Int = if (a > 0) suspendHere(factorial(a - 1) * a) else suspendHere(1) + +suspend fun suspendHere(value: Int): Int = suspendCoroutineOrReturn { x -> + postponed = { + log += "$value;" + x.resume(value) + } + COROUTINE_SUSPENDED +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(handleResultContinuation { + postponed = null + }) +} + +var postponed: (() -> Unit)? = { } + +var log = "" \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index b448753c750..c260ef5159c 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -5114,6 +5114,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("recursiveSuspend.kt") + public void testRecursiveSuspend() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/recursiveSuspend.kt"); + doTest(fileName); + } + @TestMetadata("returnByLabel.kt") public void testReturnByLabel() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/returnByLabel.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 6dbe21991cc..47a1415bc7d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -5114,6 +5114,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("recursiveSuspend.kt") + public void testRecursiveSuspend() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/recursiveSuspend.kt"); + doTest(fileName); + } + @TestMetadata("returnByLabel.kt") public void testReturnByLabel() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/returnByLabel.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 0e9151b72bc..d2e17b54d1e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -5114,6 +5114,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("recursiveSuspend.kt") + public void testRecursiveSuspend() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/recursiveSuspend.kt"); + doTest(fileName); + } + @TestMetadata("returnByLabel.kt") public void testReturnByLabel() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/returnByLabel.kt"); diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineFunctionTransformer.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineFunctionTransformer.kt index 0afe5aea8b2..788d5c9eaaf 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineFunctionTransformer.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineFunctionTransformer.kt @@ -28,7 +28,8 @@ class CoroutineFunctionTransformer(private val program: JsProgram, private val f private val innerFunction = function.getInnerFunction() private val functionWithBody = innerFunction ?: function private val body = functionWithBody.body - private val localVariables = (function.collectLocalVariables() + functionWithBody.collectLocalVariables()).toMutableSet() + private val localVariables = (function.collectLocalVariables() + functionWithBody.collectLocalVariables() - + functionWithBody.parameters.last().name).toMutableSet() private val className = function.scope.parent.declareFreshName("Coroutine\$${name ?: "anonymous"}") fun transform(): List { @@ -61,29 +62,20 @@ class CoroutineFunctionTransformer(private val program: JsProgram, private val f if (context.metadata.hasReceiver) { constructor.parameters += JsParameter(context.receiverFieldName) } - constructor.parameters += function.parameters.map { JsParameter(it.name) } - if (innerFunction != null) { - constructor.parameters += innerFunction.parameters.map { JsParameter(it.name) } - } - - val lastParameter = function.parameters.lastOrNull()?.name + val parameters = function.parameters + innerFunction?.parameters.orEmpty() + constructor.parameters += parameters.map { JsParameter(it.name) } + val lastParameter = parameters.lastOrNull()?.name val controllerName = if (context.metadata.hasController) { - function.scope.declareFreshName("controller").apply { constructor.parameters += JsParameter(this) } + function.scope.declareFreshName("controller").apply { + constructor.parameters.add(constructor.parameters.lastIndex, JsParameter(this)) + } } else { null } - val interceptorRef = if (context.metadata.isLambda) { - val interceptorName = function.scope.declareFreshName("interceptor") - constructor.parameters += JsParameter(interceptorName) - interceptorName.makeRef() - } - else { - lastParameter!!.makeRef() - } - + val interceptorRef = lastParameter!!.makeRef() val parameterNames = (function.parameters.map { it.name } + innerFunction?.parameters?.map { it.name }.orEmpty()).toSet() constructor.body.statements.run { @@ -156,20 +148,14 @@ class CoroutineFunctionTransformer(private val program: JsProgram, private val f if (context.metadata.hasReceiver) { instantiation.arguments += JsLiteral.THIS } - instantiation.arguments += function.parameters.map { it.name.makeRef() } - if (innerFunction != null) { - instantiation.arguments += innerFunction.parameters.map { it.name.makeRef() } - } + val parameters = function.parameters + innerFunction?.parameters.orEmpty() + instantiation.arguments += parameters.dropLast(1).map { it.name.makeRef() } if (function.coroutineMetadata!!.hasController) { instantiation.arguments += JsLiteral.THIS } - if (context.metadata.isLambda) { - val interceptorParamName = functionWithBody.scope.declareFreshName("interceptor") - functionWithBody.parameters += JsParameter(interceptorParamName) - instantiation.arguments += interceptorParamName.makeRef() - } + instantiation.arguments += parameters.last().name.makeRef() val suspendedName = functionWithBody.scope.declareFreshName("suspended") functionWithBody.parameters += JsParameter(suspendedName) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 1df82a0d024..66d0188f008 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -5829,6 +5829,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("recursiveSuspend.kt") + public void testRecursiveSuspend() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/recursiveSuspend.kt"); + doTest(fileName); + } + @TestMetadata("returnByLabel.kt") public void testReturnByLabel() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/returnByLabel.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallTranslator.kt index efc651e7bab..3293cf7182e 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallTranslator.kt @@ -137,7 +137,7 @@ private fun translateFunctionCall( if (resolvedCall.resultingDescriptor.isSuspend) { if (context.isInStateMachine) { context.currentBlock.statements += JsAstUtils.asSyntheticStatement(callExpression.apply { isSuspend = true }) - val coroutineRef = TranslationUtils.translateContinuationArgument(context, resolvedCall) + val coroutineRef = TranslationUtils.translateContinuationArgument(context) return context.defineTemporary(JsNameRef("\$\$coroutineResult\$\$", coroutineRef).apply { sideEffects = SideEffectKind.DEPENDS_ON_STATE coroutineResult = true diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index c5477aeaf04..b521dfb93ef 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -21,7 +21,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.Annotations; -import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor; import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; @@ -109,7 +108,7 @@ public class TranslationContext { } if (declarationDescriptor instanceof FunctionDescriptor) { FunctionDescriptor function = (FunctionDescriptor) declarationDescriptor; - if (function.isSuspend() && !(function instanceof AnonymousFunctionDescriptor)) { + if (function.isSuspend()) { ClassDescriptor continuationDescriptor = DescriptorUtilKt.findContinuationClassDescriptor(getCurrentModule(), NoLookupLocation.FROM_BACKEND); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/AbstractDeclarationVisitor.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/AbstractDeclarationVisitor.kt index 8ad8e0553d6..6dc77a8e09f 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/AbstractDeclarationVisitor.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/AbstractDeclarationVisitor.kt @@ -27,7 +27,6 @@ import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters import org.jetbrains.kotlin.js.translate.expression.translateFunction import org.jetbrains.kotlin.js.translate.expression.wrapWithInlineMetadata import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor -import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator import org.jetbrains.kotlin.js.translate.utils.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty @@ -99,17 +98,11 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor() { context: TranslationContext ): JsExpression { val function = context.getFunctionObject(descriptor) - var innerContext = context.newDeclaration(descriptor).translateAndAliasParameters(descriptor, function.parameters) + val innerContext = context.newDeclaration(descriptor).translateAndAliasParameters(descriptor, function.parameters) if (descriptor.isSuspend) { if (descriptor.requiresStateMachineTransformation(context)) { function.fillCoroutineMetadata(context, descriptor, hasController = false, isLambda = false) - innerContext = innerContext.innerContextWithAliased(descriptor, JsAstUtils.stateMachineReceiver()) - } - else { - val continuationRef = ReferenceTranslator.translateAsValueReference( - innerContext.continuationParameterDescriptor!!, innerContext) - innerContext = innerContext.innerContextWithAliased(descriptor, continuationRef) } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt index a56f1cc8287..02b6589c35b 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt @@ -29,6 +29,8 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator.shouldBeInlined import org.jetbrains.kotlin.js.translate.utils.BindingUtils import org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.translateFunctionBody +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils +import org.jetbrains.kotlin.js.translate.utils.requiresStateMachineTransformation import org.jetbrains.kotlin.psi.KtDeclarationWithBody import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue @@ -66,6 +68,12 @@ fun TranslationContext.translateAndAliasParameters( if (continuationDescriptor != null) { val jsParameter = JsParameter(getNameForDescriptor(continuationDescriptor)) targetList += jsParameter + aliases[continuationDescriptor] = if (!descriptor.requiresStateMachineTransformation(this)) { + JsAstUtils.pureFqn(jsParameter.name, null) + } + else { + JsAstUtils.stateMachineReceiver() + } } return this.innerContextWithDescriptorsAliased(aliases) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt index 5e434500f53..57f783d6b19 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt @@ -45,14 +45,8 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato val lambda = invokingContext.getFunctionObject(descriptor) - val aliases = mutableMapOf() - if (descriptor.isCoroutineLambda) { - aliases.put(descriptor, JsAstUtils.stateMachineReceiver()) - } - val functionContext = invokingContext .newFunctionBodyWithUsageTracker(lambda, descriptor) - .innerContextWithDescriptorsAliased(aliases) .translateAndAliasParameters(descriptor, lambda.parameters) descriptor.valueParameters.forEach { @@ -76,8 +70,7 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato } lambdaCreator.name.staticRef = lambdaCreator lambdaCreator.fillCoroutineMetadata(invokingContext, descriptor) - return lambdaCreator.withCapturedParameters(descriptor, descriptor.wrapContextForCoroutineIfNecessary(functionContext), - invokingContext) + return lambdaCreator.withCapturedParameters(descriptor, functionContext, invokingContext) } lambda.name = invokingContext.getInnerNameForDescriptor(descriptor) @@ -112,15 +105,6 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato } } -private fun CallableMemberDescriptor.wrapContextForCoroutineIfNecessary(context: TranslationContext): TranslationContext { - return if (isCoroutineLambda) { - context.innerContextWithDescriptorsAliased(mapOf(this to JsAstUtils.stateMachineReceiver())) - } - else { - context - } -} - fun JsFunction.withCapturedParameters( descriptor: CallableMemberDescriptor, context: TranslationContext, diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt index 04fce5a4d4d..24c9a99b728 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallArgumentTranslator.kt @@ -155,7 +155,7 @@ class CallArgumentTranslator private constructor( val callableDescriptor = resolvedCall.resultingDescriptor if (callableDescriptor is FunctionDescriptor && callableDescriptor.isSuspend) { val facadeName = context().getNameForDescriptor(TranslationUtils.getCoroutineProperty(context(), "facade")) - result.add(JsAstUtils.pureFqn(facadeName, TranslationUtils.translateContinuationArgument(context(), resolvedCall))) + result.add(JsAstUtils.pureFqn(facadeName, TranslationUtils.translateContinuationArgument(context()))) } removeLastUndefinedArguments(result) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java index 32eca48b59c..94e9f5d86cc 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java @@ -24,7 +24,6 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor; import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; import org.jetbrains.kotlin.js.backend.ast.*; -import org.jetbrains.kotlin.js.backend.ast.JsBinaryOperator; import org.jetbrains.kotlin.js.translate.context.Namer; import org.jetbrains.kotlin.js.translate.context.TemporaryConstVariable; import org.jetbrains.kotlin.js.translate.context.TranslationContext; @@ -38,7 +37,6 @@ import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContextUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils; -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.inline.InlineUtil; import org.jetbrains.kotlin.serialization.deserialization.FindClassInModuleKt; @@ -81,7 +79,7 @@ public final class TranslationUtils { } @NotNull - public static String getAccessorFunctionName(@NotNull FunctionDescriptor descriptor) { + private static String getAccessorFunctionName(@NotNull FunctionDescriptor descriptor) { boolean isGetter = descriptor instanceof PropertyGetterDescriptor || descriptor instanceof LocalVariableAccessorDescriptor.Getter; return isGetter ? "get" : "set"; } @@ -227,12 +225,6 @@ public final class TranslationUtils { return Translation.translateAsExpression(left, context, block); } - @NotNull - public static JsExpression translateRightExpression(@NotNull TranslationContext context, - @NotNull KtBinaryExpression expression) { - return translateRightExpression(context, expression, context.dynamicContext().jsBlock()); - } - @NotNull public static JsExpression translateRightExpression( @NotNull TranslationContext context, @@ -350,19 +342,13 @@ public final class TranslationUtils { } @NotNull - public static JsExpression translateContinuationArgument(@NotNull TranslationContext context, @NotNull ResolvedCall resolvedCall) { - CallableDescriptor continuationDescriptor = - context.bindingContext().get(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall()); - - if (continuationDescriptor == null) { - continuationDescriptor = getEnclosingContinuationParameter(context); - } - + public static JsExpression translateContinuationArgument(@NotNull TranslationContext context) { + CallableDescriptor continuationDescriptor = getEnclosingContinuationParameter(context); return ReferenceTranslator.translateAsValueReference(continuationDescriptor, context); } @NotNull - public static VariableDescriptor getEnclosingContinuationParameter(@NotNull TranslationContext context) { + private static VariableDescriptor getEnclosingContinuationParameter(@NotNull TranslationContext context) { VariableDescriptor result = context.getContinuationParameterDescriptor(); if (result == null) { assert context.getParent() != null; @@ -395,13 +381,6 @@ public final class TranslationUtils { .iterator().next(); } - @NotNull - public static FunctionDescriptor getCoroutineResumeFunction(@NotNull TranslationContext context) { - return getCoroutineBaseClass(context).getUnsubstitutedMemberScope() - .getContributedFunctions(Name.identifier("resume"), NoLookupLocation.FROM_DESERIALIZATION) - .iterator().next(); - } - public static boolean isOverridableFunctionWithDefaultParameters(@NotNull FunctionDescriptor descriptor) { return DescriptorUtilsKt.hasOrInheritsParametersWithDefaultValue(descriptor) && !(descriptor instanceof ConstructorDescriptor) &&