Skip to content

Commit 736377f

Browse files
cypressiousSpace Team
authored andcommitted
[FIR] Fix CONTEXTUAL_OVERLOAD_SHADOWED checks
We need to reuse the constraint system from the value parameter checks because contradictions can occur from the combination of constraints from value parameters and context parameters. The context parameter checks run in transactions that get rolled back if they introduce contradictions. #KT-79139 Fixed
1 parent 948fdab commit 736377f

File tree

4 files changed

+64
-55
lines changed

4 files changed

+64
-55
lines changed
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
// RUN_PIPELINE_TILL: FRONTEND
1+
// RUN_PIPELINE_TILL: BACKEND
22
// WITH_STDLIB
33
// LANGUAGE: +ContextParameters
44

55
interface I<X, Y>
66

77
context(c: I<T1, T2>)
8-
<!CONFLICTING_OVERLOADS!>fun <T1, T2> foo(left: T2, right: T1)<!> {}
8+
fun <T1, T2> foo(left: T2, right: T1) {}
99

1010
@JvmName("foo2")
1111
context(c: I<T3, T4>)
12-
<!CONFLICTING_OVERLOADS!>fun <T3, T4> foo(left: T3, right: T4)<!> {}
12+
fun <T3, T4> foo(left: T3, right: T4) {}
13+
14+
@JvmName("foo3")
15+
context(c: I<T5, T6>, _: Map<T5, T6>)
16+
<!CONTEXTUAL_OVERLOAD_SHADOWED!>fun <T5, T6> foo(left: T5, right: T6)<!> {}
1317

1418
/* GENERATED_FIR_TAGS: functionDeclaration, functionDeclarationWithContext, interfaceDeclaration, nullableType,
1519
typeParameter */

compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ private fun FirDeclarationCollector<*>.getConflictState(
551551

552552
return if (session.languageVersionSettings.supportsFeature(LanguageFeature.ContextParameters)) {
553553
overloadabilityHelper.getConflictStateWithContextParameters(declaration, conflicting)
554-
} else if (overloadabilityHelper.isConflicting(declaration, conflicting, ignoreContextParameters = false)) {
554+
} else if (overloadabilityHelper.isConflicting(declaration, conflicting)) {
555555
ConflictState.Conflict
556556
} else {
557557
ConflictState.NoConflict
@@ -562,10 +562,6 @@ private fun FirDeclarationOverloadabilityHelper.getConflictStateWithContextParam
562562
declaration: FirCallableSymbol<*>,
563563
conflicting: FirCallableSymbol<*>,
564564
): ConflictState {
565-
if (!isConflicting(declaration, conflicting, ignoreContextParameters = true)) {
566-
return ConflictState.NoConflict
567-
}
568-
569565
return when (getContextParameterShadowing(declaration, conflicting)) {
570566
BothWays -> ConflictState.Conflict
571567
Shadowing -> ConflictState.ContextParameterShadowing

compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationOverloadabilityHelper.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
1111
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature
1212

1313
interface FirDeclarationOverloadabilityHelper : FirSessionComponent {
14-
fun isConflicting(a: FirCallableSymbol<*>, b: FirCallableSymbol<*>, ignoreContextParameters: Boolean): Boolean
14+
fun isConflicting(a: FirCallableSymbol<*>, b: FirCallableSymbol<*>): Boolean
1515

1616
enum class ContextParameterShadowing {
1717
None,

compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/overloads/FirDeclarationOverloadabilityHelperImpl.kt

Lines changed: 55 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -8,96 +8,91 @@ package org.jetbrains.kotlin.fir.resolve.calls.overloads
88
import org.jetbrains.kotlin.fir.FirSession
99
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
1010
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOverloadabilityHelper
11+
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOverloadabilityHelper.ContextParameterShadowing
1112
import org.jetbrains.kotlin.fir.declarations.typeSpecificityComparatorProvider
1213
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
1314
import org.jetbrains.kotlin.fir.resolve.inference.inferenceLogger
1415
import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents
1516
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
1617
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
17-
import org.jetbrains.kotlin.fir.types.ConeKotlinType
18+
import org.jetbrains.kotlin.resolve.calls.inference.runTransaction
1819
import org.jetbrains.kotlin.resolve.calls.results.*
1920
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
2021

2122
// 16 is enough to compare two CP lists with 4 types each.
2223
private const val MAX_COMPLEXITY_FOR_CONTEXT_PARAMETERS = 16
2324

2425
class FirDeclarationOverloadabilityHelperImpl(val session: FirSession) : FirDeclarationOverloadabilityHelper {
25-
override fun isConflicting(a: FirCallableSymbol<*>, b: FirCallableSymbol<*>, ignoreContextParameters: Boolean): Boolean {
26-
val sigA = createSignature(a, ignoreContextParameters)
27-
val sigB = createSignature(b, ignoreContextParameters)
26+
override fun isConflicting(a: FirCallableSymbol<*>, b: FirCallableSymbol<*>): Boolean {
27+
val sigA = createSignature(a, ignoreContextParameters = false)
28+
val sigB = createSignature(b, ignoreContextParameters = false)
2829

2930
return isEquallyOrMoreSpecific(sigA, sigB) && isEquallyOrMoreSpecific(sigB, sigA)
3031
}
3132

3233
override fun getContextParameterShadowing(
3334
a: FirCallableSymbol<*>,
3435
b: FirCallableSymbol<*>,
35-
): FirDeclarationOverloadabilityHelper.ContextParameterShadowing {
36+
): ContextParameterShadowing {
37+
// Fast-path when either symbol has no context parameters.
38+
if (a.contextParameterSymbols.none() || b.contextParameterSymbols.none()) {
39+
return if (isConflicting(a, b)) ContextParameterShadowing.BothWays else ContextParameterShadowing.None
40+
}
41+
42+
val sigA = createSignature(a, ignoreContextParameters = true)
43+
val sigB = createSignature(b, ignoreContextParameters = true)
44+
45+
val csB = createEmptyConstraintSystem()
46+
val stateB = csB.signatureComparisonStateIfEquallyOrMoreSpecific(sigA, sigB) ?: return ContextParameterShadowing.None
47+
48+
val csA = createEmptyConstraintSystem()
49+
val stateA = csA.signatureComparisonStateIfEquallyOrMoreSpecific(sigB, sigA) ?: return ContextParameterShadowing.None
50+
51+
// The complexity of this check is O(a.contextParameterSymbols.size * b.contextParameterSymbols.size),
52+
// to limit quadratic explosion, we only check below a certain threshold.
53+
if (a.contextParameterSymbols.size * b.contextParameterSymbols.size > MAX_COMPLEXITY_FOR_CONTEXT_PARAMETERS) {
54+
return ContextParameterShadowing.None
55+
}
56+
3657
// bShadowsA && aShadowsB => BothWays
3758
// bShadowsA && !aShadowsB => Shadowing
3859
// else => None
3960

40-
val bShadowsA = isShadowingContextParameters(b, a)
61+
val bShadowsA = isShadowingContextParameters(b, a, csB, stateB)
4162
// Early return to skip needless computation of aShadowsB
42-
if (!bShadowsA) return FirDeclarationOverloadabilityHelper.ContextParameterShadowing.None
63+
if (!bShadowsA) return ContextParameterShadowing.None
4364

44-
val aShadowsB = isShadowingContextParameters(a, b)
65+
val aShadowsB = isShadowingContextParameters(a, b, csA, stateA)
4566

4667
return if (aShadowsB) {
47-
FirDeclarationOverloadabilityHelper.ContextParameterShadowing.BothWays
68+
ContextParameterShadowing.BothWays
4869
} else {
49-
FirDeclarationOverloadabilityHelper.ContextParameterShadowing.Shadowing
70+
ContextParameterShadowing.Shadowing
5071
}
5172
}
5273

5374
private fun isShadowingContextParameters(
5475
a: FirCallableSymbol<*>,
5576
b: FirCallableSymbol<*>,
77+
cs: ConeSimpleConstraintSystemImpl,
78+
state: FlatSignatureComparisonState,
5679
): Boolean {
57-
// The complexity of this check is O(a.contextParameterSymbols.size * b.contextParameterSymbols.size),
58-
// to limit quadratic explosion, we only check below a certain threshold.
59-
if (a.contextParameterSymbols.size * b.contextParameterSymbols.size > MAX_COMPLEXITY_FOR_CONTEXT_PARAMETERS) {
60-
return false
61-
}
62-
6380
// A is shadowing B if for every type in A's context parameter list, there is a type in B's context parameter list
6481
// that is equally or more specific.
6582

66-
fun singleTypeSignature(type: ConeKotlinType, symbol: FirCallableSymbol<*>): FlatSignature<FirCallableSymbol<*>> {
67-
return FlatSignature(
68-
origin = symbol,
69-
typeParameters = symbol.typeParameterSymbols.map { it.toLookupTag() },
70-
valueParameterTypes = listOf(type),
71-
hasExtensionReceiver = false,
72-
contextReceiverCount = 0,
73-
hasVarargs = false,
74-
numDefaults = 0,
75-
isExpect = false,
76-
isSyntheticMember = false
77-
)
78-
}
79-
80-
val bSingleTypeSignatures = b.contextParameterSymbols.map { singleTypeSignature(it.resolvedReturnType, b) }
81-
82-
return a.contextParameterSymbols.all {
83-
val aType = singleTypeSignature(it.resolvedReturnType, a)
84-
bSingleTypeSignatures.any { bType ->
85-
isEquallyOrMoreSpecific(bType, aType)
83+
return a.contextParameterSymbols.all { cpA ->
84+
b.contextParameterSymbols.any { cpB ->
85+
cs.system.runTransaction {
86+
!state.isLessSpecific(cpB.resolvedReturnType, cpA.resolvedReturnType)
87+
}
8688
}
8789
}
8890
}
8991

9092
override fun isEquallyOrMoreSpecific(
9193
sigA: FlatSignature<FirCallableSymbol<*>>,
9294
sigB: FlatSignature<FirCallableSymbol<*>>,
93-
): Boolean = createEmptyConstraintSystem().also {
94-
session.inferenceLogger?.logStage("Some isEquallyOrMoreSpecific() call", it.constraintSystemMarker)
95-
}.isSignatureEquallyOrMoreSpecific(
96-
sigA,
97-
sigB,
98-
OverloadabilitySpecificityCallbacks,
99-
session.typeSpecificityComparatorProvider?.typeSpecificityComparator ?: TypeSpecificityComparator.NONE,
100-
)
95+
): Boolean = createEmptyConstraintSystem().signatureComparisonStateIfEquallyOrMoreSpecific(sigA, sigB) != null
10196

10297
override fun createSignature(declaration: FirCallableSymbol<*>, ignoreContextParameters: Boolean): FlatSignature<FirCallableSymbol<*>> {
10398
val valueParameters = (declaration as? FirFunctionSymbol<*>)?.valueParameterSymbols.orEmpty()
@@ -143,7 +138,21 @@ class FirDeclarationOverloadabilityHelperImpl(val session: FirSession) : FirDecl
143138
)
144139
}
145140

146-
private fun createEmptyConstraintSystem(): SimpleConstraintSystem {
147-
return ConeSimpleConstraintSystemImpl(session.inferenceComponents.createConstraintSystem(), session)
141+
private fun createEmptyConstraintSystem(): ConeSimpleConstraintSystemImpl {
142+
return ConeSimpleConstraintSystemImpl(session.inferenceComponents.createConstraintSystem(), session).also {
143+
session.inferenceLogger?.logStage("Some isEquallyOrMoreSpecific() call", it.constraintSystemMarker)
144+
}
145+
}
146+
147+
private fun ConeSimpleConstraintSystemImpl.signatureComparisonStateIfEquallyOrMoreSpecific(
148+
sigA: FlatSignature<FirCallableSymbol<*>>,
149+
sigB: FlatSignature<FirCallableSymbol<*>>,
150+
): FlatSignatureComparisonState? {
151+
return signatureComparisonStateIfEquallyOrMoreSpecific(
152+
sigA,
153+
sigB,
154+
OverloadabilitySpecificityCallbacks,
155+
session.typeSpecificityComparatorProvider?.typeSpecificityComparator ?: TypeSpecificityComparator.NONE
156+
)
148157
}
149158
}

0 commit comments

Comments
 (0)