diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ArgumentsUtils.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ArgumentsUtils.kt index fa6c6b9ed43..5c79a011f0e 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ArgumentsUtils.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ArgumentsUtils.kt @@ -25,7 +25,6 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.resolve.calls.model.CollectionLiteralKotlinCallArgument import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument -import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor import org.jetbrains.kotlin.resolve.descriptorUtil.isParameterOfAnnotation import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver @@ -70,20 +69,44 @@ fun ValueParameterDescriptor.hasDefaultValue(): Boolean { return DFS.ifAny( listOf(this), { current -> current.overriddenDescriptors.map(ValueParameterDescriptor::getOriginal) }, - { it.declaresDefaultValue() || it.isActualParameterWithExpectedDefault } + { it.declaresDefaultValue() || it.isActualParameterWithAnyExpectedDefault } ) } -val ValueParameterDescriptor.isActualParameterWithExpectedDefault: Boolean - get() { - val function = containingDeclaration - if (function is FunctionDescriptor && function.isActual) { - with(ExpectedActualResolver) { - val expected = function.findCompatibleExpectedForActual(function.module).firstOrNull() - return expected is FunctionDescriptor && expected.valueParameters[index].hasDefaultValue() - } +fun ValueParameterDescriptor.checkExpectedParameter(checker: (ValueParameterDescriptor) -> Boolean) : Boolean { + val function = containingDeclaration + if (function is FunctionDescriptor && function.isActual) { + with(ExpectedActualResolver) { + val expected = function.findCompatibleExpectedForActual(function.module).firstOrNull() + return expected is FunctionDescriptor && checker(expected.valueParameters[index]) } - return false + } + return false +} + +/** + * The following two properties describe two different situations: + * + * Consider hierarchy: + * expect open class A { foo(p = 1) } + * expect open class B : A { foo(p) } + * + * actual open class A { foo(p) } + * actual open class B : A { foo(p) } + * + * For parameter `p` of method `foo`: + * `Any` property returns `true` for both actual A and B + * `Corresponding` property returns `true` only for `actual A` because `expect B` declaration doesn't have an default value + */ + +val ValueParameterDescriptor.isActualParameterWithAnyExpectedDefault: Boolean + get() { + return checkExpectedParameter { it.hasDefaultValue() } + } + +val ValueParameterDescriptor.isActualParameterWithCorrespondingExpectedDefault: Boolean + get() { + return checkExpectedParameter { it.declaresDefaultValue() } } private fun KotlinCallArgument.isArrayAssignedAsNamedArgumentInAnnotation( diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt index 7da2def49f7..dc5f02bd583 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry import org.jetbrains.kotlin.resolve.MemberComparator import org.jetbrains.kotlin.resolve.RequireKotlinNames -import org.jetbrains.kotlin.resolve.calls.components.isActualParameterWithExpectedDefault +import org.jetbrains.kotlin.resolve.calls.components.isActualParameterWithAnyExpectedDefault import org.jetbrains.kotlin.resolve.checkers.KotlinVersionStringAnnotationValueChecker import org.jetbrains.kotlin.resolve.constants.EnumValue import org.jetbrains.kotlin.resolve.constants.IntValue @@ -408,7 +408,7 @@ class DescriptorSerializer private constructor( private fun valueParameter(descriptor: ValueParameterDescriptor): ProtoBuf.ValueParameter.Builder { val builder = ProtoBuf.ValueParameter.newBuilder() - val declaresDefaultValue = descriptor.declaresDefaultValue() || descriptor.isActualParameterWithExpectedDefault + val declaresDefaultValue = descriptor.declaresDefaultValue() || descriptor.isActualParameterWithAnyExpectedDefault val flags = Flags.getValueParameterFlags( hasAnnotations(descriptor), declaresDefaultValue, descriptor.isCrossinline, descriptor.isNoinline diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt index abc52b3fb3c..01a3cb59b04 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt @@ -28,7 +28,8 @@ import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getClassDescriptor import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getSupertypesWithoutFakes import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.resolve.descriptorUtil.hasOrInheritsParametersWithDefaultValue +import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue +import org.jetbrains.kotlin.resolve.calls.components.isActualParameterWithCorrespondingExpectedDefault import org.jetbrains.kotlin.resolve.descriptorUtil.hasOwnParametersWithDefaultValue class DeclarationBodyVisitor( @@ -110,8 +111,12 @@ class DeclarationBodyVisitor( initializerStatements.add(statement) } + private fun hasParametersWithDefaultValue(descriptor: FunctionDescriptor) = descriptor.valueParameters.any { it.hasDefaultValue() } + private fun hasCorrespondingExpectParametersWithDefaultValue(descriptor: FunctionDescriptor) = + descriptor.valueParameters.any { it.isActualParameterWithCorrespondingExpectedDefault } + override fun addFunction(descriptor: FunctionDescriptor, expression: JsExpression?, psi: KtElement?) { - if (!descriptor.hasOrInheritsParametersWithDefaultValue() || !descriptor.isOverridableOrOverrides) { + if (!hasParametersWithDefaultValue(descriptor) || !descriptor.isOverridableOrOverrides) { if (expression != null) { context.addDeclarationStatement(context.addFunctionToPrototype(containingClass, descriptor, expression)) } @@ -125,7 +130,7 @@ class DeclarationBodyVisitor( context.addDeclarationStatement(JsAstUtils.assignment(functionRef, expression).makeStmt()) } - if (descriptor.hasOwnParametersWithDefaultValue()) { + if (descriptor.hasOwnParametersWithDefaultValue() || hasCorrespondingExpectParametersWithDefaultValue(descriptor)) { val caller = JsFunction(context.getScopeForDescriptor(containingClass), JsBlock(), "") caller.source = psi?.finalElement val callerContext = context