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:
Denis Zharkov
2017-03-01 20:02:51 +03:00
parent 9e5ecc11b7
commit 415c3d57af
5 changed files with 60 additions and 8 deletions
@@ -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
}
}
}