FIR: Fix SAM conversion for raw types with non-trivial TP upper bounds
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
RawType.bar {
|
||||||
|
it.length > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: Processor.java
|
||||||
|
public interface Processor<T extends CharSequence> {
|
||||||
|
boolean process(T t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: RawType.java
|
||||||
|
public class RawType {
|
||||||
|
public static void bar(Processor x) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
FILE: main.kt
|
||||||
|
public final fun foo(): R|kotlin/Unit| {
|
||||||
|
Q|RawType|.R|/RawType.bar|(<L> = bar@fun <anonymous>(it: R|ft<kotlin/CharSequence, kotlin/CharSequence?>!|): R|kotlin/Boolean| {
|
||||||
|
^ CMP(>, R|<local>/it|.R|kotlin/CharSequence.length|.R|kotlin/Int.compareTo|(Int(0)))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
Generated
+5
@@ -358,6 +358,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/qualifierWithCompanion.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/qualifierWithCompanion.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("rawTypeSam.kt")
|
||||||
|
public void testRawTypeSam() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/rawTypeSam.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("recursiveCallOnWhenWithSealedClass.kt")
|
@TestMetadata("recursiveCallOnWhenWithSealedClass.kt")
|
||||||
public void testRecursiveCallOnWhenWithSealedClass() throws Exception {
|
public void testRecursiveCallOnWhenWithSealedClass() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/recursiveCallOnWhenWithSealedClass.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/recursiveCallOnWhenWithSealedClass.kt");
|
||||||
|
|||||||
+5
@@ -358,6 +358,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/qualifierWithCompanion.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/qualifierWithCompanion.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("rawTypeSam.kt")
|
||||||
|
public void testRawTypeSam() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/rawTypeSam.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("recursiveCallOnWhenWithSealedClass.kt")
|
@TestMetadata("recursiveCallOnWhenWithSealedClass.kt")
|
||||||
public void testRecursiveCallOnWhenWithSealedClass() throws Exception {
|
public void testRecursiveCallOnWhenWithSealedClass() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/recursiveCallOnWhenWithSealedClass.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/recursiveCallOnWhenWithSealedClass.kt");
|
||||||
|
|||||||
+5
@@ -358,6 +358,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/qualifierWithCompanion.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/qualifierWithCompanion.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("rawTypeSam.kt")
|
||||||
|
public void testRawTypeSam() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/rawTypeSam.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("recursiveCallOnWhenWithSealedClass.kt")
|
@TestMetadata("recursiveCallOnWhenWithSealedClass.kt")
|
||||||
public void testRecursiveCallOnWhenWithSealedClass() throws Exception {
|
public void testRecursiveCallOnWhenWithSealedClass() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/recursiveCallOnWhenWithSealedClass.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/recursiveCallOnWhenWithSealedClass.kt");
|
||||||
|
|||||||
@@ -77,17 +77,26 @@ class FirSamResolverImpl(
|
|||||||
?: return null
|
?: return null
|
||||||
|
|
||||||
val unsubstitutedFunctionType = resolveFunctionTypeIfSamInterface(firRegularClass) ?: return null
|
val unsubstitutedFunctionType = resolveFunctionTypeIfSamInterface(firRegularClass) ?: return null
|
||||||
|
|
||||||
|
if (firRegularClass.typeParameters.isEmpty()) {
|
||||||
|
return unsubstitutedFunctionType.withNullability(ConeNullability.create(type.isMarkedNullable), firSession.typeContext)
|
||||||
|
}
|
||||||
|
|
||||||
val substitutor =
|
val substitutor =
|
||||||
substitutorByMap(
|
substitutorByMap(
|
||||||
firRegularClass.typeParameters
|
firRegularClass.typeParameters
|
||||||
.map { it.symbol }
|
.map { it.symbol }
|
||||||
.zip(
|
.zip(
|
||||||
type.typeArguments.map {
|
type.typeArguments,
|
||||||
(it as? ConeKotlinTypeProjection)?.type
|
).map { (parameterSymbol, projection) ->
|
||||||
|
val typeArgument =
|
||||||
|
(projection as? ConeKotlinTypeProjection)?.type
|
||||||
|
// TODO: Consider using `parameterSymbol.fir.bounds.first().coneType` once sure that it won't fail with exception
|
||||||
|
?: parameterSymbol.fir.bounds.firstOrNull()?.coneTypeSafe()
|
||||||
?: firSession.builtinTypes.nullableAnyType.type
|
?: firSession.builtinTypes.nullableAnyType.type
|
||||||
//ConeClassLikeTypeImpl(ConeClassLikeLookupTagImpl(StandardClassIds.Any), emptyArray(), isNullable = true)
|
|
||||||
},
|
Pair(parameterSymbol, typeArgument)
|
||||||
)
|
}
|
||||||
.toMap(),
|
.toMap(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -147,7 +156,7 @@ class FirSamResolverImpl(
|
|||||||
|
|
||||||
for ((newTypeParameter, oldTypeParameter) in newTypeParameters.zip(firRegularClass.typeParameters)) {
|
for ((newTypeParameter, oldTypeParameter) in newTypeParameters.zip(firRegularClass.typeParameters)) {
|
||||||
val declared = oldTypeParameter.symbol.fir // TODO: or really declared?
|
val declared = oldTypeParameter.symbol.fir // TODO: or really declared?
|
||||||
newTypeParameter.bounds += declared.bounds.mapNotNull { typeRef ->
|
newTypeParameter.bounds += declared.bounds.map { typeRef ->
|
||||||
buildResolvedTypeRef {
|
buildResolvedTypeRef {
|
||||||
source = typeRef.source
|
source = typeRef.source
|
||||||
type = substitutor.substituteOrSelf(typeRef.coneType)
|
type = substitutor.substituteOrSelf(typeRef.coneType)
|
||||||
@@ -204,14 +213,14 @@ class FirSamResolverImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveFunctionTypeIfSamInterface(firRegularClass: FirRegularClass): ConeKotlinType? {
|
private fun resolveFunctionTypeIfSamInterface(firRegularClass: FirRegularClass): ConeLookupTagBasedType? {
|
||||||
return resolvedFunctionType.getOrPut(firRegularClass) {
|
return resolvedFunctionType.getOrPut(firRegularClass) {
|
||||||
if (!firRegularClass.status.isFun) return@getOrPut NULL_STUB
|
if (!firRegularClass.status.isFun) return@getOrPut NULL_STUB
|
||||||
val abstractMethod = firRegularClass.getSingleAbstractMethodOrNull(firSession, scopeSession) ?: return@getOrPut NULL_STUB
|
val abstractMethod = firRegularClass.getSingleAbstractMethodOrNull(firSession, scopeSession) ?: return@getOrPut NULL_STUB
|
||||||
// TODO: val shouldConvertFirstParameterToDescriptor = samWithReceiverResolvers.any { it.shouldConvertFirstSamParameterToReceiver(abstractMethod) }
|
// TODO: val shouldConvertFirstParameterToDescriptor = samWithReceiverResolvers.any { it.shouldConvertFirstSamParameterToReceiver(abstractMethod) }
|
||||||
|
|
||||||
abstractMethod.getFunctionTypeForAbstractMethod()
|
abstractMethod.getFunctionTypeForAbstractMethod()
|
||||||
} as? ConeKotlinType
|
} as? ConeLookupTagBasedType
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun shouldRunSamConversionForFunction(firFunction: FirFunction<*>): Boolean {
|
override fun shouldRunSamConversionForFunction(firFunction: FirFunction<*>): Boolean {
|
||||||
|
|||||||
Vendored
-33
@@ -1,33 +0,0 @@
|
|||||||
// !CHECK_TYPE
|
|
||||||
// FILE: Function.java
|
|
||||||
public interface Function<E extends java.util.Map<String, Integer>, F extends CharSequence> {
|
|
||||||
F handle(E e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FILE: A.java
|
|
||||||
public class A {
|
|
||||||
public void foo(Function<?, ?> l) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bar(Function<?, ?> l) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FILE: main.kt
|
|
||||||
fun main() {
|
|
||||||
A().foo {
|
|
||||||
x ->
|
|
||||||
x checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Map<String, Int>?>() }
|
|
||||||
""
|
|
||||||
}
|
|
||||||
|
|
||||||
A.bar {
|
|
||||||
x ->
|
|
||||||
x checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Map<String, Int>>() }
|
|
||||||
""
|
|
||||||
}
|
|
||||||
|
|
||||||
val block: (Map<String, Int>) -> CharSequence = { x -> x.toString() }
|
|
||||||
A().<!INAPPLICABLE_CANDIDATE!>foo<!>(block)
|
|
||||||
A.<!INAPPLICABLE_CANDIDATE!>bar<!>(block)
|
|
||||||
}
|
|
||||||
Vendored
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !CHECK_TYPE
|
// !CHECK_TYPE
|
||||||
// FILE: Function.java
|
// FILE: Function.java
|
||||||
public interface Function<E extends java.util.Map<String, Integer>, F extends CharSequence> {
|
public interface Function<E extends java.util.Map<String, Integer>, F extends CharSequence> {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
FILE fqName:<root> fileName:/samByProjectedType.kt
|
FILE fqName:<root> fileName:/samByProjectedType.kt
|
||||||
FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Unit
|
FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Unit
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE): /H.bar>#' type=kotlin.Unit
|
CALL 'public open fun bar (j: <root>.J<*>?): kotlin.Unit declared in <root>.H' type=kotlin.Unit origin=null
|
||||||
FUN_EXPR type=kotlin.Function1<kotlin.Any, kotlin.Any?> origin=LAMBDA
|
j: TYPE_OP type=<root>.J<*>? origin=SAM_CONVERSION typeOperand=<root>.J<*>?
|
||||||
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (x:kotlin.Any) returnType:kotlin.Any?
|
FUN_EXPR type=kotlin.Function1<kotlin.Any, kotlin.Any?> origin=LAMBDA
|
||||||
VALUE_PARAMETER name:x index:0 type:kotlin.Any
|
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (x:kotlin.Any) returnType:kotlin.Any?
|
||||||
BLOCK_BODY
|
VALUE_PARAMETER name:x index:0 type:kotlin.Any
|
||||||
RETURN type=kotlin.Nothing from='local final fun <anonymous> (x: kotlin.Any): kotlin.Any? declared in <root>.test1'
|
BLOCK_BODY
|
||||||
GET_VAR 'x: kotlin.Any declared in <root>.test1.<anonymous>' type=kotlin.Any origin=null
|
RETURN type=kotlin.Nothing from='local final fun <anonymous> (x: kotlin.Any): kotlin.Any? declared in <root>.test1'
|
||||||
|
GET_VAR 'x: kotlin.Any declared in <root>.test1.<anonymous>' type=kotlin.Any origin=null
|
||||||
|
|||||||
Reference in New Issue
Block a user