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
This commit is contained in:
+14
-6
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScope
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.findCorrespondingSupertype
|
||||
import java.util.*
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
@@ -58,10 +59,8 @@ class SamAdapterFunctionsScope(
|
||||
override fun getSyntheticMemberFunctions(receiverTypes: Collection<KotlinType>, name: Name, location: LookupLocation): Collection<FunctionDescriptor> {
|
||||
var result: SmartList<FunctionDescriptor>? = null
|
||||
for (type in receiverTypes) {
|
||||
val substitutorForType by lazy { buildMemberScopeSubstitutorForType(type) }
|
||||
|
||||
for (function in type.memberScope.getContributedFunctions(name, location)) {
|
||||
val extension = extensionForFunction(function.original)?.substitute(substitutorForType)
|
||||
val extension = extensionForFunction(function.original)?.substituteForReceiverType(type)
|
||||
if (extension != null) {
|
||||
if (result == null) {
|
||||
result = SmartList()
|
||||
@@ -77,15 +76,24 @@ class SamAdapterFunctionsScope(
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildMemberScopeSubstitutorForType(type: KotlinType) =
|
||||
TypeConstructorSubstitution.create(type).wrapWithCapturingSubstitution(needApproximation = true).buildSubstitutor()
|
||||
private fun FunctionDescriptor.substituteForReceiverType(receiverType: KotlinType): FunctionDescriptor? {
|
||||
val containingClass = containingDeclaration as? ClassDescriptor ?: return null
|
||||
val correspondingSupertype = findCorrespondingSupertype(receiverType, containingClass.defaultType) ?: return null
|
||||
|
||||
return substitute(
|
||||
TypeConstructorSubstitution
|
||||
.create(correspondingSupertype)
|
||||
.wrapWithCapturingSubstitution(needApproximation = true)
|
||||
.buildSubstitutor()
|
||||
)
|
||||
}
|
||||
|
||||
override fun getSyntheticMemberFunctions(receiverTypes: Collection<KotlinType>): Collection<FunctionDescriptor> {
|
||||
return receiverTypes.flatMapTo(LinkedHashSet<FunctionDescriptor>()) { type ->
|
||||
type.memberScope.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)
|
||||
.filterIsInstance<FunctionDescriptor>()
|
||||
.mapNotNull {
|
||||
extensionForFunction(it.original)?.substitute(buildMemberScopeSubstitutorForType(type))
|
||||
extensionForFunction(it.original)?.substituteForReceiverType(type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// FILE: FormFieldValidatorPresenterTest.java
|
||||
public class FormFieldValidatorPresenterTest<V extends String> {
|
||||
|
||||
public void setValidationListenerTest(ValidationListenerTest validationListener) {
|
||||
}
|
||||
|
||||
public interface ValidationListenerTest {
|
||||
void onValidityChanged(boolean valid);
|
||||
}
|
||||
}
|
||||
// FILE: main.kt
|
||||
fun <P : FormFieldValidatorPresenterTest<String>> setValidationListener(
|
||||
presenter: P,
|
||||
validationListener: (Boolean) -> Unit
|
||||
) {
|
||||
presenter.setValidationListenerTest(validationListener) // Error: Type mismatch: inferred type is (Boolean) -> Unit but FormFieldValidatorPresenterTest.ValidationListenerTest! was expected
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ P : FormFieldValidatorPresenterTest<kotlin.String>> setValidationListener(/*0*/ presenter: P, /*1*/ validationListener: (kotlin.Boolean) -> kotlin.Unit): kotlin.Unit
|
||||
|
||||
public open class FormFieldValidatorPresenterTest</*0*/ V : kotlin.String!> {
|
||||
public constructor FormFieldValidatorPresenterTest</*0*/ V : kotlin.String!>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open fun setValidationListenerTest(/*0*/ validationListener: FormFieldValidatorPresenterTest.ValidationListenerTest!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
public interface ValidationListenerTest {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public abstract fun onValidityChanged(/*0*/ valid: kotlin.Boolean): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
// Static members
|
||||
public final /*synthesized*/ fun ValidationListenerTest(/*0*/ function: (valid: kotlin.Boolean) -> kotlin.Unit): FormFieldValidatorPresenterTest.ValidationListenerTest
|
||||
}
|
||||
@@ -12234,6 +12234,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("samOnTypeParameter.kt")
|
||||
public void testSamOnTypeParameter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/sam/samOnTypeParameter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("typeInferenceOnSamAdapters.kt")
|
||||
public void testTypeInferenceOnSamAdapters() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/sam/typeInferenceOnSamAdapters.kt");
|
||||
|
||||
@@ -27,7 +27,7 @@ private class SubtypePathNode(val type: KotlinType, val previous: SubtypePathNod
|
||||
|
||||
fun findCorrespondingSupertype(
|
||||
subtype: KotlinType, supertype: KotlinType,
|
||||
typeCheckingProcedureCallbacks: TypeCheckingProcedureCallbacks
|
||||
typeCheckingProcedureCallbacks: TypeCheckingProcedureCallbacks = TypeCheckerProcedureCallbacksImpl()
|
||||
): KotlinType? {
|
||||
val queue = ArrayDeque<SubtypePathNode>()
|
||||
queue.add(SubtypePathNode(subtype, null))
|
||||
@@ -99,4 +99,4 @@ private fun TypeConstructor.debugInfo() = buildString {
|
||||
|
||||
declarationDescriptor = declarationDescriptor.containingDeclaration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user