Skip to content

Commit 415c3d5

Browse files
committed
Fix substitutor for synthetic SAM adapters
When synthetic member comes not from the receiver type itself, but from one of its supertypes it doesn't make sense to subsitute the member with receiver type, we should obtain relevant supertype and use it instead. #KT-16578 Fixed
1 parent 9e5ecc1 commit 415c3d5

File tree

5 files changed

+60
-8
lines changed

5 files changed

+60
-8
lines changed

compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
3131
import org.jetbrains.kotlin.resolve.scopes.SyntheticScope
3232
import org.jetbrains.kotlin.storage.StorageManager
3333
import org.jetbrains.kotlin.types.*
34+
import org.jetbrains.kotlin.types.checker.findCorrespondingSupertype
3435
import java.util.*
3536
import kotlin.properties.Delegates
3637

@@ -58,10 +59,8 @@ class SamAdapterFunctionsScope(
5859
override fun getSyntheticMemberFunctions(receiverTypes: Collection<KotlinType>, name: Name, location: LookupLocation): Collection<FunctionDescriptor> {
5960
var result: SmartList<FunctionDescriptor>? = null
6061
for (type in receiverTypes) {
61-
val substitutorForType by lazy { buildMemberScopeSubstitutorForType(type) }
62-
6362
for (function in type.memberScope.getContributedFunctions(name, location)) {
64-
val extension = extensionForFunction(function.original)?.substitute(substitutorForType)
63+
val extension = extensionForFunction(function.original)?.substituteForReceiverType(type)
6564
if (extension != null) {
6665
if (result == null) {
6766
result = SmartList()
@@ -77,15 +76,24 @@ class SamAdapterFunctionsScope(
7776
}
7877
}
7978

80-
private fun buildMemberScopeSubstitutorForType(type: KotlinType) =
81-
TypeConstructorSubstitution.create(type).wrapWithCapturingSubstitution(needApproximation = true).buildSubstitutor()
79+
private fun FunctionDescriptor.substituteForReceiverType(receiverType: KotlinType): FunctionDescriptor? {
80+
val containingClass = containingDeclaration as? ClassDescriptor ?: return null
81+
val correspondingSupertype = findCorrespondingSupertype(receiverType, containingClass.defaultType) ?: return null
82+
83+
return substitute(
84+
TypeConstructorSubstitution
85+
.create(correspondingSupertype)
86+
.wrapWithCapturingSubstitution(needApproximation = true)
87+
.buildSubstitutor()
88+
)
89+
}
8290

8391
override fun getSyntheticMemberFunctions(receiverTypes: Collection<KotlinType>): Collection<FunctionDescriptor> {
8492
return receiverTypes.flatMapTo(LinkedHashSet<FunctionDescriptor>()) { type ->
8593
type.memberScope.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)
8694
.filterIsInstance<FunctionDescriptor>()
8795
.mapNotNull {
88-
extensionForFunction(it.original)?.substitute(buildMemberScopeSubstitutorForType(type))
96+
extensionForFunction(it.original)?.substituteForReceiverType(type)
8997
}
9098
}
9199
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// FILE: FormFieldValidatorPresenterTest.java
2+
public class FormFieldValidatorPresenterTest<V extends String> {
3+
4+
public void setValidationListenerTest(ValidationListenerTest validationListener) {
5+
}
6+
7+
public interface ValidationListenerTest {
8+
void onValidityChanged(boolean valid);
9+
}
10+
}
11+
// FILE: main.kt
12+
fun <P : FormFieldValidatorPresenterTest<String>> setValidationListener(
13+
presenter: P,
14+
validationListener: (Boolean) -> Unit
15+
) {
16+
presenter.setValidationListenerTest(validationListener) // Error: Type mismatch: inferred type is (Boolean) -> Unit but FormFieldValidatorPresenterTest.ValidationListenerTest! was expected
17+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package
2+
3+
public fun </*0*/ P : FormFieldValidatorPresenterTest<kotlin.String>> setValidationListener(/*0*/ presenter: P, /*1*/ validationListener: (kotlin.Boolean) -> kotlin.Unit): kotlin.Unit
4+
5+
public open class FormFieldValidatorPresenterTest</*0*/ V : kotlin.String!> {
6+
public constructor FormFieldValidatorPresenterTest</*0*/ V : kotlin.String!>()
7+
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
8+
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
9+
public open fun setValidationListenerTest(/*0*/ validationListener: FormFieldValidatorPresenterTest.ValidationListenerTest!): kotlin.Unit
10+
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
11+
12+
public interface ValidationListenerTest {
13+
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
14+
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
15+
public abstract fun onValidityChanged(/*0*/ valid: kotlin.Boolean): kotlin.Unit
16+
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
17+
}
18+
19+
// Static members
20+
public final /*synthesized*/ fun ValidationListenerTest(/*0*/ function: (valid: kotlin.Boolean) -> kotlin.Unit): FormFieldValidatorPresenterTest.ValidationListenerTest
21+
}

compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12234,6 +12234,12 @@ public void testEnhancedSamConstructor() throws Exception {
1223412234
doTest(fileName);
1223512235
}
1223612236

12237+
@TestMetadata("samOnTypeParameter.kt")
12238+
public void testSamOnTypeParameter() throws Exception {
12239+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/sam/samOnTypeParameter.kt");
12240+
doTest(fileName);
12241+
}
12242+
1223712243
@TestMetadata("typeInferenceOnSamAdapters.kt")
1223812244
public void testTypeInferenceOnSamAdapters() throws Exception {
1223912245
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/sam/typeInferenceOnSamAdapters.kt");

core/descriptors/src/org/jetbrains/kotlin/types/checker/utils.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ private class SubtypePathNode(val type: KotlinType, val previous: SubtypePathNod
2727

2828
fun findCorrespondingSupertype(
2929
subtype: KotlinType, supertype: KotlinType,
30-
typeCheckingProcedureCallbacks: TypeCheckingProcedureCallbacks
30+
typeCheckingProcedureCallbacks: TypeCheckingProcedureCallbacks = TypeCheckerProcedureCallbacksImpl()
3131
): KotlinType? {
3232
val queue = ArrayDeque<SubtypePathNode>()
3333
queue.add(SubtypePathNode(subtype, null))
@@ -99,4 +99,4 @@ private fun TypeConstructor.debugInfo() = buildString {
9999

100100
declarationDescriptor = declarationDescriptor.containingDeclaration
101101
}
102-
}
102+
}

0 commit comments

Comments
 (0)