Fixed handling of default params in declaration (KT-23239)

This commit is contained in:
Roman Artemev
2018-03-16 20:45:08 +03:00
parent a121a4a6b2
commit 0d0adbbc05
3 changed files with 44 additions and 16 deletions
@@ -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(
@@ -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
@@ -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