Support default arguments for expected declarations

#KT-21913 Fixed
This commit is contained in:
Alexander Udalov
2018-01-12 20:50:24 +01:00
parent d356f52873
commit db4ce703a6
36 changed files with 794 additions and 77 deletions
@@ -19,16 +19,19 @@ package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
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.declaresOrInheritsDefaultValue
import org.jetbrains.kotlin.resolve.descriptorUtil.isParameterOfAnnotation
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal fun unexpectedArgument(argument: KotlinCallArgument): Nothing =
@@ -59,12 +62,29 @@ val ValueParameterDescriptor.isVararg: Boolean get() = varargElementType != null
val ParameterDescriptor.isVararg: Boolean get() = this.safeAs<ValueParameterDescriptor>()?.isVararg ?: false
/**
* @return `true` iff the parameter has a default value, i.e. declares it or inherits by overriding a parameter which has a default value.
* @return `true` iff the parameter has a default value, i.e. declares it, inherits it by overriding a parameter which has a default value,
* or is a parameter of an 'actual' declaration, such that the corresponding 'expect' parameter has a default value.
*/
fun ValueParameterDescriptor.hasDefaultValue(): Boolean {
return declaresOrInheritsDefaultValue()
return DFS.ifAny(
listOf(this),
{ current -> current.overriddenDescriptors.map(ValueParameterDescriptor::getOriginal) },
{ it.declaresDefaultValue() || it.isActualParameterWithExpectedDefault }
)
}
private 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()
}
}
return false
}
private fun KotlinCallArgument.isArrayAssignedAsNamedArgumentInAnnotation(
parameter: ParameterDescriptor,
languageVersionSettings: LanguageVersionSettings
@@ -172,7 +172,6 @@ object ExpectedActualResolver {
object ParameterNames : Incompatible("parameter names are different")
object TypeParameterNames : Incompatible("names of type parameters are different")
object ValueParameterHasDefault : Incompatible("some parameters have default values")
object ValueParameterVararg : Incompatible("some value parameter is vararg in one declaration and non-vararg in the other")
object ValueParameterNoinline : Incompatible("some value parameter is noinline in one declaration and not noinline in the other")
object ValueParameterCrossinline : Incompatible("some value parameter is crossinline in one declaration and not crossinline in the other")
@@ -257,7 +256,6 @@ object ExpectedActualResolver {
areCompatibleTypeParameters(aTypeParams, bTypeParams, platformModule, substitutor).let { if (it != Compatible) return it }
if (!equalsBy(aParams, bParams, ValueParameterDescriptor::declaresDefaultValue)) return Incompatible.ValueParameterHasDefault
if (!equalsBy(aParams, bParams, { p -> listOf(p.varargElementType != null) })) return Incompatible.ValueParameterVararg
// Adding noinline/crossinline to parameters is disallowed, except if the expected declaration was not inline at all