diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 1fb2f6a51df..06a57e81aa7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration -import org.jetbrains.kotlin.fir.diagnostics.FirSimpleDiagnostic import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl @@ -19,6 +18,7 @@ import org.jetbrains.kotlin.fir.references.impl.FirResolvedNamedReferenceImpl import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.* +import org.jetbrains.kotlin.fir.resolve.calls.jvm.ConeEquivalentCallConflictResolver import org.jetbrains.kotlin.fir.resolve.diagnostics.FirAmbiguityError import org.jetbrains.kotlin.fir.resolve.diagnostics.FirInapplicableCandidateError import org.jetbrains.kotlin.fir.resolve.diagnostics.FirUnresolvedNameError @@ -61,7 +61,11 @@ class FirCallResolver( topLevelScopes = topLevelScopes.asReversed(), localScopes = localScopes.asReversed() ) - private val conflictResolver = ConeOverloadConflictResolver(TypeSpecificityComparator.NONE, inferenceComponents) + + private val conflictResolver = ConeCompositeConflictResolver( + ConeOverloadConflictResolver(TypeSpecificityComparator.NONE, inferenceComponents), + ConeEquivalentCallConflictResolver(TypeSpecificityComparator.NONE, inferenceComponents) + ) fun resolveCallAndSelectCandidate(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?, file: FirFile): FirFunctionCall { qualifiedResolver.reset() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/AbstractConeCallConflictResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/AbstractConeCallConflictResolver.kt new file mode 100644 index 00000000000..e06189fe364 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/AbstractConeCallConflictResolver.kt @@ -0,0 +1,139 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.resolve.calls + +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.arrayElementType +import org.jetbrains.kotlin.fir.types.coneTypeUnsafe +import org.jetbrains.kotlin.resolve.OverloadabilitySpecificityCallbacks +import org.jetbrains.kotlin.resolve.calls.results.FlatSignature +import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem +import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator +import org.jetbrains.kotlin.resolve.calls.results.isSignatureNotLessSpecific + +abstract class AbstractConeCallConflictResolver( + private val specificityComparator: TypeSpecificityComparator, + protected val inferenceComponents: InferenceComponents +) : ConeCallConflictResolver { + protected fun Collection.setIfOneOrEmpty(): Set? = when (size) { + 0 -> emptySet() + 1 -> setOf(single()) + else -> null + } + + /** + * Returns `true` if [call1] is definitely more or equally specific [call2], + * `false` otherwise. + */ + protected fun compareCallsByUsedArguments( + call1: FlatSignature, + call2: FlatSignature, + discriminateGenerics: Boolean + ): Boolean { + if (discriminateGenerics) { + val isGeneric1 = call1.isGeneric + val isGeneric2 = call2.isGeneric + // generic loses to non-generic + if (isGeneric1 && !isGeneric2) return false + if (!isGeneric1 && isGeneric2) return true + // two generics are non-comparable + if (isGeneric1 && isGeneric2) return false + } + + if (!call1.isExpect && call2.isExpect) return true + if (call1.isExpect && !call2.isExpect) return false + + return createEmptyConstraintSystem().isSignatureNotLessSpecific( + call1, + call2, + OverloadabilitySpecificityCallbacks, + specificityComparator + ) + } + + protected fun createFlatSignature(call: Candidate): FlatSignature { + return when (val declaration = call.symbol.fir) { + is FirSimpleFunction -> createFlatSignature(call, declaration) + is FirConstructor -> createFlatSignature(call, declaration) + is FirVariable<*> -> createFlatSignature(call, declaration) + is FirClass<*> -> createFlatSignature(call, declaration) + else -> error("Not supported: $declaration") + } + } + + protected fun createFlatSignature(call: Candidate, variable: FirVariable<*>): FlatSignature { + return FlatSignature( + call, + (variable as? FirProperty)?.typeParameters?.map { it.symbol }.orEmpty(), + listOfNotNull(variable.receiverTypeRef?.coneTypeUnsafe()), + variable.receiverTypeRef != null, + false, + 0, + (variable as? FirProperty)?.isExpect == true, + false // TODO + ) + } + + protected fun createFlatSignature(call: Candidate, constructor: FirConstructor): FlatSignature { + return FlatSignature( + call, + constructor.typeParameters.map { it.symbol }, + computeParameterTypes(call, constructor), + //constructor.receiverTypeRef != null, + false, + constructor.valueParameters.any { it.isVararg }, + constructor.valueParameters.count { it.defaultValue != null }, + constructor.isExpect, + false // TODO + ) + } + + protected fun createFlatSignature(call: Candidate, function: FirSimpleFunction): FlatSignature { + return FlatSignature( + call, + function.typeParameters.map { it.symbol }, + computeParameterTypes(call, function), + function.receiverTypeRef != null, + function.valueParameters.any { it.isVararg }, + function.valueParameters.count { it.defaultValue != null }, + function.isExpect, + false // TODO + ) + } + + private fun FirValueParameter.argumentType(): ConeKotlinType { + val type = returnTypeRef.coneTypeUnsafe() + if (isVararg) return type.arrayElementType(inferenceComponents.session)!! + return type + } + + private fun computeParameterTypes( + call: Candidate, + function: FirFunction<*> + ): List { + return (call.resultingTypeForCallableReference?.typeArguments?.map { it as ConeKotlinType } + ?: (listOfNotNull(function.receiverTypeRef?.coneTypeUnsafe()) + + call.argumentMapping?.map { it.value.argumentType() }.orEmpty())) + } + + private fun createFlatSignature(call: Candidate, klass: FirClass<*>): FlatSignature { + return FlatSignature( + call, + (klass as? FirRegularClass)?.typeParameters?.map { it.symbol }.orEmpty(), + valueParameterTypes = emptyList(), + hasExtensionReceiver = false, + hasVarargs = false, + numDefaults = 0, + isExpect = (klass as? FirRegularClass)?.isExpect == true, + isSyntheticMember = false + ) + } + + private fun createEmptyConstraintSystem(): SimpleConstraintSystem { + return ConeSimpleConstraintSystemImpl(inferenceComponents.createConstraintSystem()) + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCallConflictResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCallConflictResolver.kt new file mode 100644 index 00000000000..1ddaa8efcbe --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCallConflictResolver.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.resolve.calls + +interface ConeCallConflictResolver { + fun chooseMaximallySpecificCandidates( + candidates: Collection, + discriminateGenerics: Boolean + ): Set = chooseMaximallySpecificCandidates(candidates.toSet(), discriminateGenerics) + + fun chooseMaximallySpecificCandidates( + candidates: Set, + discriminateGenerics: Boolean + ): Set +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCompositeConflictResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCompositeConflictResolver.kt new file mode 100644 index 00000000000..bb8b1b5c252 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeCompositeConflictResolver.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.resolve.calls + +class ConeCompositeConflictResolver( + private vararg val conflictResolvers: AbstractConeCallConflictResolver +) : ConeCallConflictResolver { + override fun chooseMaximallySpecificCandidates(candidates: Set, discriminateGenerics: Boolean): Set { + if (candidates.size <= 1) return candidates + var currentCandidates = candidates + var index = 0 + while (currentCandidates.size > 1 && index < conflictResolvers.size) { + val conflictResolver = conflictResolvers[index++] + currentCandidates = conflictResolver.chooseMaximallySpecificCandidates(candidates, discriminateGenerics) + } + return currentCandidates + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt index 57447f80275..8d383996e60 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt @@ -5,19 +5,15 @@ package org.jetbrains.kotlin.fir.resolve.calls -import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol -import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.fir.types.arrayElementType import org.jetbrains.kotlin.fir.types.coneTypeUnsafe -import org.jetbrains.kotlin.resolve.OverloadabilitySpecificityCallbacks import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition import org.jetbrains.kotlin.resolve.calls.results.FlatSignature import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator -import org.jetbrains.kotlin.resolve.calls.results.isSignatureNotLessSpecific import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.TypeParameterMarker import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker @@ -25,154 +21,21 @@ import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext import org.jetbrains.kotlin.utils.addToStdlib.cast class ConeOverloadConflictResolver( - val specificityComparator: TypeSpecificityComparator, - val inferenceComponents: InferenceComponents + specificityComparator: TypeSpecificityComparator, + inferenceComponents: InferenceComponents +) : AbstractConeCallConflictResolver(specificityComparator, inferenceComponents) { -) { - - fun chooseMaximallySpecificCandidates( - candidates: Collection, - //checkArgumentsMode: CheckArgumentTypesMode, + override fun chooseMaximallySpecificCandidates( + candidates: Set, discriminateGenerics: Boolean ): Set { - candidates.setIfOneOrEmpty()?.let { return it } - - val candidatesSet = filterOutEquivalentCalls(candidates) - - findMaximallySpecificCall(candidatesSet, false)?.let { return setOf(it) } + findMaximallySpecificCall(candidates, false)?.let { return setOf(it) } if (discriminateGenerics) { - findMaximallySpecificCall(candidatesSet, true)?.let { return setOf(it) } + findMaximallySpecificCall(candidates, true)?.let { return setOf(it) } } - return candidatesSet - } - - private fun filterOutEquivalentCalls(candidates: Collection): Set { - val result = mutableSetOf() - outerLoop@ for (myCandidate in candidates) { - val me = myCandidate.symbol.fir - if (me is FirCallableMemberDeclaration<*> && me.symbol.callableId.className == null) { - for (otherCandidate in result) { - val other = otherCandidate.symbol.fir - if (other is FirCallableMemberDeclaration<*> && other.symbol.callableId.className == null) { - if (areEquivalentTopLevelCallables(me, myCandidate, other, otherCandidate)) { - continue@outerLoop - } - } - } - } - result += myCandidate - } - return result - } - - private fun areEquivalentTopLevelCallables( - first: FirCallableMemberDeclaration<*>, - firstCandidate: Candidate, - second: FirCallableMemberDeclaration<*>, - secondCandidate: Candidate - ): Boolean { - if (first.symbol.callableId != second.symbol.callableId) return false - if (first.isExpect != second.isExpect) return false - if (first.receiverTypeRef?.coneTypeUnsafe() != second.receiverTypeRef?.coneTypeUnsafe()) { - return false - } - val firstSignature = createFlatSignature(firstCandidate, first) - val secondSignature = createFlatSignature(secondCandidate, second) - return compareCallsByUsedArguments(firstSignature, secondSignature, false) && - compareCallsByUsedArguments(secondSignature, firstSignature, false) - } - - private fun createFlatSignature(call: Candidate): FlatSignature { - return when (val declaration = call.symbol.fir) { - is FirSimpleFunction -> createFlatSignature(call, declaration) - is FirConstructor -> createFlatSignature(call, declaration) - is FirVariable<*> -> createFlatSignature(call, declaration) - is FirClass<*> -> createFlatSignature(call, declaration) - else -> error("Not supported: $declaration") - } - } - - private fun createFlatSignature(call: Candidate, declaration: FirCallableMemberDeclaration<*>): FlatSignature { - return when (declaration) { - is FirSimpleFunction -> createFlatSignature(call, declaration) - is FirConstructor -> createFlatSignature(call, declaration) - is FirVariable<*> -> createFlatSignature(call, declaration as FirVariable<*>) - else -> error("Not supported: $declaration") - } - } - - private fun createFlatSignature(call: Candidate, constructor: FirConstructor): FlatSignature { - return FlatSignature( - call, - constructor.typeParameters.map { it.symbol }, - computeParameterTypes(call, constructor), - //constructor.receiverTypeRef != null, - false, - constructor.valueParameters.any { it.isVararg }, - constructor.valueParameters.count { it.defaultValue != null }, - constructor.isExpect, - false // TODO - ) - } - - private fun FirValueParameter.argumentType(): ConeKotlinType { - val type = returnTypeRef.coneTypeUnsafe() - if (isVararg) return type.arrayElementType(inferenceComponents.session)!! - return type - } - - private fun createFlatSignature(call: Candidate, function: FirSimpleFunction): FlatSignature { - return FlatSignature( - call, - function.typeParameters.map { it.symbol }, - computeParameterTypes(call, function), - function.receiverTypeRef != null, - function.valueParameters.any { it.isVararg }, - function.valueParameters.count { it.defaultValue != null }, - function.isExpect, - false // TODO - ) - } - - private fun computeParameterTypes( - call: Candidate, - function: FirFunction<*> - ): List { - return (call.resultingTypeForCallableReference?.typeArguments?.map { it as ConeKotlinType } - ?: (listOfNotNull(function.receiverTypeRef?.coneTypeUnsafe()) + - call.argumentMapping?.map { it.value.argumentType() }.orEmpty())) - } - - private fun createFlatSignature(call: Candidate, variable: FirVariable<*>): FlatSignature { - return FlatSignature( - call, - (variable as? FirProperty)?.typeParameters?.map { it.symbol }.orEmpty(), - listOfNotNull(variable.receiverTypeRef?.coneTypeUnsafe()), - variable.receiverTypeRef != null, - false, - 0, - (variable as? FirProperty)?.isExpect == true, - false // TODO - ) - } - - private fun createFlatSignature(call: Candidate, klass: FirClass<*>): FlatSignature { - return FlatSignature( - call, - (klass as? FirRegularClass)?.typeParameters?.map { it.symbol }.orEmpty(), - valueParameterTypes = emptyList(), - hasExtensionReceiver = false, - hasVarargs = false, - numDefaults = 0, - isExpect = (klass as? FirRegularClass)?.isExpect == true, - isSyntheticMember = false - ) - } - - private fun createEmptyConstraintSystem(): SimpleConstraintSystem { - return ConeSimpleConstraintSystemImpl(inferenceComponents.createConstraintSystem()) + return candidates } private fun findMaximallySpecificCall( @@ -180,11 +43,9 @@ class ConeOverloadConflictResolver( discriminateGenerics: Boolean//, //isDebuggerContext: Boolean ): Candidate? { - val filteredCandidates = candidates//uniquifyCandidatesSet(candidates) + if (candidates.size <= 1) return candidates.singleOrNull() - if (filteredCandidates.size <= 1) return filteredCandidates.singleOrNull() - - val conflictingCandidates = filteredCandidates.map { candidateCall -> + val conflictingCandidates = candidates.map { candidateCall -> createFlatSignature(candidateCall) } @@ -208,7 +69,7 @@ class ConeOverloadConflictResolver( } } if (result == null) return null - if (any { it != result && isNotWorse(it, result!!) }) { + if (any { it != result && isNotWorse(it, result) }) { return null } return result @@ -235,38 +96,6 @@ class ConeOverloadConflictResolver( ) } - - - /** - * Returns `true` if [call1] is definitely more or equally specific [call2], - * `false` otherwise. - */ - private fun compareCallsByUsedArguments( - call1: FlatSignature, - call2: FlatSignature, - discriminateGenerics: Boolean - ): Boolean { - if (discriminateGenerics) { - val isGeneric1 = call1.isGeneric - val isGeneric2 = call2.isGeneric - // generic loses to non-generic - if (isGeneric1 && !isGeneric2) return false - if (!isGeneric1 && isGeneric2) return true - // two generics are non-comparable - if (isGeneric1 && isGeneric2) return false - } - - if (!call1.isExpect && call2.isExpect) return true - if (call1.isExpect && !call2.isExpect) return false - - return createEmptyConstraintSystem().isSignatureNotLessSpecific( - call1, - call2, - OverloadabilitySpecificityCallbacks, - specificityComparator - ) - } - private fun isOfNotLessSpecificShape( call1: FlatSignature, call2: FlatSignature @@ -282,12 +111,6 @@ class ConeOverloadConflictResolver( return true } - - private fun Collection.setIfOneOrEmpty(): Set? = when (size) { - 0 -> emptySet() - 1 -> setOf(single()) - else -> null - } } object NoSubstitutor : TypeSubstitutorMarker @@ -295,19 +118,21 @@ object NoSubstitutor : TypeSubstitutorMarker class ConeSimpleConstraintSystemImpl(val system: NewConstraintSystemImpl) : SimpleConstraintSystem { override fun registerTypeVariables(typeParameters: Collection): TypeSubstitutorMarker = with(context) { val csBuilder = system.getBuilder() - val substitutionMap = typeParameters.associate { + val substitutionMap = typeParameters.associateWith { require(it is FirTypeParameterSymbol) val variable = TypeParameterBasedTypeVariable(it) csBuilder.registerVariable(variable) - - it to variable.defaultType + variable.defaultType } val substitutor = substitutorByMap(substitutionMap.cast()) for (typeParameter in typeParameters) { require(typeParameter is FirTypeParameterSymbol) for (upperBound in typeParameter.fir.bounds) { - addSubtypeConstraint(substitutionMap[typeParameter]!!, substitutor.substituteOrSelf(upperBound.coneTypeUnsafe())) + addSubtypeConstraint( + substitutionMap[typeParameter] ?: error("No ${typeParameter.fir.render()} in substitution map"), + substitutor.substituteOrSelf(upperBound.coneTypeUnsafe()) + ) } } return substitutor diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/jvm/ConeEquivalentCallConflictResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/jvm/ConeEquivalentCallConflictResolver.kt new file mode 100644 index 00000000000..a38e048d852 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/jvm/ConeEquivalentCallConflictResolver.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.resolve.calls.jvm + +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.resolve.calls.Candidate +import org.jetbrains.kotlin.fir.resolve.calls.AbstractConeCallConflictResolver +import org.jetbrains.kotlin.fir.resolve.calls.InferenceComponents +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.coneTypeUnsafe +import org.jetbrains.kotlin.resolve.calls.results.FlatSignature +import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator + +// This conflict resolver filters JVM equivalent top-level functions +// like emptyArray() from intrinsics and built-ins +class ConeEquivalentCallConflictResolver( + specificityComparator: TypeSpecificityComparator, + inferenceComponents: InferenceComponents +) : AbstractConeCallConflictResolver(specificityComparator, inferenceComponents) { + override fun chooseMaximallySpecificCandidates( + candidates: Set, + discriminateGenerics: Boolean + ): Set { + return filterOutEquivalentCalls(candidates) + } + + private fun filterOutEquivalentCalls(candidates: Collection): Set { + val result = mutableSetOf() + outerLoop@ for (myCandidate in candidates) { + val me = myCandidate.symbol.fir + if (me is FirCallableMemberDeclaration<*> && me.symbol.callableId.className == null) { + for (otherCandidate in result) { + val other = otherCandidate.symbol.fir + if (other is FirCallableMemberDeclaration<*> && other.symbol.callableId.className == null) { + if (areEquivalentTopLevelCallables(me, myCandidate, other, otherCandidate)) { + continue@outerLoop + } + } + } + } + result += myCandidate + } + return result + } + + private fun areEquivalentTopLevelCallables( + first: FirCallableMemberDeclaration<*>, + firstCandidate: Candidate, + second: FirCallableMemberDeclaration<*>, + secondCandidate: Candidate + ): Boolean { + if (first.symbol.callableId != second.symbol.callableId) return false + if (first.isExpect != second.isExpect) return false + if (first.receiverTypeRef?.coneTypeUnsafe() != second.receiverTypeRef?.coneTypeUnsafe()) { + return false + } + val firstSignature = createFlatSignature(firstCandidate, first) + val secondSignature = createFlatSignature(secondCandidate, second) + return compareCallsByUsedArguments(firstSignature, secondSignature, false) && + compareCallsByUsedArguments(secondSignature, firstSignature, false) + } + + private fun createFlatSignature(call: Candidate, declaration: FirCallableMemberDeclaration<*>): FlatSignature { + return when (declaration) { + is FirSimpleFunction -> createFlatSignature(call, declaration) + is FirConstructor -> createFlatSignature(call, declaration) + is FirVariable<*> -> createFlatSignature(call, declaration as FirVariable<*>) + else -> error("Not supported: $declaration") + } + } +} \ No newline at end of file