[FIR] Unwrap captured types in target type of SAM conversion

^KT-66256 Fixed
This commit is contained in:
Dmitriy Novozhilov
2024-03-01 14:06:27 +02:00
committed by Space Team
parent 690f39b91c
commit b875ae774e
28 changed files with 185 additions and 26 deletions
@@ -53936,6 +53936,12 @@ public class LLFirBlackBoxCodegenBasedTestGenerated extends AbstractLLFirBlackBo
runTest("compiler/testData/codegen/box/sam/fieldInJavaSamInterface.kt");
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("inlinedSamWrapper.kt")
public void testInlinedSamWrapper() {
@@ -53936,6 +53936,12 @@ public class LLFirReversedBlackBoxCodegenBasedTestGenerated extends AbstractLLFi
runTest("compiler/testData/codegen/box/sam/fieldInJavaSamInterface.kt");
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("inlinedSamWrapper.kt")
public void testInlinedSamWrapper() {
@@ -549,7 +549,7 @@ internal class AdapterGenerator(
}
internal fun getFunctionTypeForPossibleSamType(parameterType: ConeKotlinType): ConeKotlinType? {
return samResolver.getFunctionTypeForPossibleSamType(parameterType)
return samResolver.getSamInfoForPossibleSamType(parameterType)?.functionalType
}
/**
@@ -53661,6 +53661,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/sam/fieldInJavaSamInterface.kt");
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("inlinedSamWrapper.kt")
public void testInlinedSamWrapper() {
@@ -53661,6 +53661,12 @@ public class FirLightTreeBlackBoxCodegenWithFir2IrFakeOverrideGeneratorTestGener
runTest("compiler/testData/codegen/box/sam/fieldInJavaSamInterface.kt");
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("inlinedSamWrapper.kt")
public void testInlinedSamWrapper() {
@@ -53661,6 +53661,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/sam/fieldInJavaSamInterface.kt");
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("inlinedSamWrapper.kt")
public void testInlinedSamWrapper() {
@@ -45,7 +45,6 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.addToStdlib.runIf
import org.jetbrains.kotlin.utils.addToStdlib.unreachableBranch
private val SAM_PARAMETER_NAME = Name.identifier("function")
@@ -71,27 +70,42 @@ class FirSamResolver(
else -> false
}
fun getFunctionTypeForPossibleSamType(type: ConeKotlinType): ConeKotlinType? {
/**
* fun interface Foo {
* fun bar(x: Int): String
* }
*
* [functionalType] is `(Int) -> String`
* [samType] is `Foo`
*/
data class SamConversionInfo(val functionalType: ConeKotlinType, val samType: ConeKotlinType)
fun getSamInfoForPossibleSamType(type: ConeKotlinType): SamConversionInfo? {
return when (type) {
is ConeClassLikeType -> getFunctionTypeForPossibleSamType(type.fullyExpandedType(session))
is ConeClassLikeType -> SamConversionInfo(
functionalType = getFunctionTypeForPossibleSamType(type.fullyExpandedType(session)) ?: return null,
samType = type
)
is ConeFlexibleType -> {
val lowerType = getFunctionTypeForPossibleSamType(type.lowerBound) ?: return null
val upperType = getFunctionTypeForPossibleSamType(type.upperBound) ?: return null
ConeFlexibleType(lowerType.lowerBoundIfFlexible(), upperType.upperBoundIfFlexible())
val lowerType = getSamInfoForPossibleSamType(type.lowerBound)?.functionalType ?: return null
val upperType = getSamInfoForPossibleSamType(type.upperBound)?.functionalType ?: return null
SamConversionInfo(
functionalType = ConeFlexibleType(lowerType.lowerBoundIfFlexible(), upperType.upperBoundIfFlexible()),
samType = type
)
}
is ConeStubType, is ConeTypeParameterType, is ConeTypeVariableType,
is ConeDefinitelyNotNullType, is ConeIntersectionType, is ConeIntegerLiteralType,
-> null
is ConeCapturedType -> type.lowerType?.let { getFunctionTypeForPossibleSamType(it) }
is ConeCapturedType -> type.lowerType?.let { getSamInfoForPossibleSamType(it) }
is ConeLookupTagBasedType -> unreachableBranch(type)
}
}
private fun getFunctionTypeForPossibleSamType(type: ConeClassLikeType): ConeLookupTagBasedType? {
@OptIn(LookupTagInternals::class)
val firRegularClass = type.lookupTag.toFirRegularClass(session) ?: return null
val (_, unsubstitutedFunctionType) = resolveFunctionTypeIfSamInterface(firRegularClass) ?: return null
@@ -222,7 +222,7 @@ abstract class AbstractConeCallConflictResolver(
private fun FirValueParameter.toFunctionTypeForSamOrNull(call: Candidate): ConeKotlinType? {
val functionTypesOfSamConversions = call.functionTypesOfSamConversions ?: return null
return call.argumentMapping?.entries?.firstNotNullOfOrNull {
runIf(it.value == this) { functionTypesOfSamConversions[it.key.unwrapArgument()] }
runIf(it.value == this) { functionTypesOfSamConversions[it.key.unwrapArgument()]?.functionalType }
}
}
@@ -505,8 +505,9 @@ private fun Candidate.getExpectedTypeWithSAMConversion(
): ConeKotlinType? {
if (candidateExpectedType.isSomeFunctionType(session)) return null
val expectedFunctionType = context.bodyResolveComponents.samResolver.getFunctionTypeForPossibleSamType(candidateExpectedType)
val samConversionInfo = context.bodyResolveComponents.samResolver.getSamInfoForPossibleSamType(candidateExpectedType)
?: return null
val expectedFunctionType = samConversionInfo.functionalType
if (!argument.shouldUseSamConversion(
session,
@@ -520,9 +521,9 @@ private fun Candidate.getExpectedTypeWithSAMConversion(
}
val samConversions = functionTypesOfSamConversions
?: hashMapOf<FirExpression, ConeKotlinType>().also { functionTypesOfSamConversions = it }
?: hashMapOf<FirExpression, FirSamResolver.SamConversionInfo>().also { functionTypesOfSamConversions = it }
samConversions[argument.unwrapArgument()] = expectedFunctionType
samConversions[argument.unwrapArgument()] = samConversionInfo
return expectedFunctionType
}
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.buildThisReceiverExpressionCopy
import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub
import org.jetbrains.kotlin.fir.resolve.FirSamResolver
import org.jetbrains.kotlin.fir.resolve.inference.FirInferenceSession
import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents
import org.jetbrains.kotlin.fir.resolve.inference.PostponedResolvedAtom
@@ -112,7 +113,7 @@ class Candidate(
var argumentMapping: LinkedHashMap<FirExpression, FirValueParameter>? = null
var numDefaults: Int = 0
var functionTypesOfSamConversions: HashMap<FirExpression, ConeKotlinType>? = null
var functionTypesOfSamConversions: HashMap<FirExpression, FirSamResolver.SamConversionInfo>? = null
lateinit var typeArgumentMapping: TypeArgumentMapping
val postponedAtoms = mutableListOf<PostponedResolvedAtom>()
@@ -414,10 +414,9 @@ class FirCallCompletionResultsWriterTransformer(
// Finally, the result can be wrapped in a SAM conversion if necessary.
if (transformed is FirExpression) {
val key = (element as? FirAnonymousFunctionExpression)?.anonymousFunction ?: element
if (expectedArgumentsTypeMapping?.samFunctionTypes?.get(key) != null) {
val expectedArgumentType = expectedArgumentsTypeMapping.getExpectedType(key)
expectedArgumentsTypeMapping?.samConversions?.get(key)?.let { samInfo ->
@Suppress("UNCHECKED_CAST")
expectedArgumentType?.let { return transformed.wrapInSamExpression(it) as E }
return transformed.wrapInSamExpression(samInfo.samType) as E
}
}
@@ -436,7 +435,6 @@ class FirCallCompletionResultsWriterTransformer(
source = this@wrapInSamExpression.source?.fakeElement(KtFakeSourceElementKind.SamConversion)
}
}
private val FirBasedSymbol<*>.isArrayConstructorWithLambda: Boolean
get() {
val constructor = (this as? FirConstructorSymbol)?.fir ?: return false
@@ -639,7 +637,7 @@ class FirCallCompletionResultsWriterTransformer(
val isIntegerOperator = symbol.isWrappedIntegerOperator()
var samConversions: MutableMap<FirElement, ConeKotlinType>? = null
var samConversions: MutableMap<FirElement, FirSamResolver.SamConversionInfo>? = null
val arguments = argumentMapping?.flatMap { (argument, valueParameter) ->
val expectedType = when {
isIntegerOperator -> ConeIntegerConstantOperatorTypeImpl(
@@ -652,10 +650,12 @@ class FirCallCompletionResultsWriterTransformer(
argument.unwrapAndFlattenArgument(flattenArrays = false).map {
val element: FirElement = (it as? FirAnonymousFunctionExpression)?.anonymousFunction ?: it
val samFunctionType = functionTypesOfSamConversions?.get(it)
if (samFunctionType != null) {
functionTypesOfSamConversions?.get(it)?.let { samInfo ->
if (samConversions == null) samConversions = mutableMapOf()
samConversions!![element] = samFunctionType.substitute(this)
samConversions!![element] = FirSamResolver.SamConversionInfo(
functionalType = samInfo.functionalType.substituteType(this),
samType = samInfo.samType.substituteType(this)
)
}
element to expectedType
}
@@ -771,9 +771,9 @@ class FirCallCompletionResultsWriterTransformer(
expectedArgumentType.isSomeFunctionType(session) -> expectedArgumentType
// fun interface (a.k.a. SAM), then unwrap it and build a functional type from that interface function
else -> {
val samFunctionType = (data as? ExpectedArgumentType.ArgumentsMap)?.samFunctionTypes?.get(anonymousFunction)
?: samResolver.getFunctionTypeForPossibleSamType(expectedArgumentType)
samFunctionType?.lowerBoundIfFlexible()
val samInfo = (data as? ExpectedArgumentType.ArgumentsMap)?.samConversions?.get(anonymousFunction)
?: samResolver.getSamInfoForPossibleSamType(expectedArgumentType)
samInfo?.functionalType?.lowerBoundIfFlexible()
}
}
}
@@ -1062,7 +1062,7 @@ sealed class ExpectedArgumentType {
class ArgumentsMap(
val map: Map<FirElement, ConeKotlinType>,
val lambdasReturnTypes: Map<FirAnonymousFunction, ConeKotlinType>,
val samFunctionTypes: Map<FirElement, ConeKotlinType>,
val samConversions: Map<FirElement, FirSamResolver.SamConversionInfo>,
) : ExpectedArgumentType()
class ExpectedType(val type: ConeKotlinType) : ExpectedArgumentType()
+18
View File
@@ -0,0 +1,18 @@
// ISSUE: KT-66256
fun interface Element {
fun invoke()
}
class Container<T> {
fun add(arg: T) {}
}
fun test(c: Container<in Element>) {
c.add({})
}
fun box(): String {
test(Container())
return "OK"
}
@@ -52959,6 +52959,12 @@ public class JvmAbiConsistencyTestBoxGenerated extends AbstractJvmAbiConsistency
runTest("compiler/testData/codegen/box/sam/fieldInJavaSamInterface.kt");
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("inlinedSamWrapper.kt")
public void testInlinedSamWrapper() {
@@ -49821,6 +49821,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/sam/fieldInJavaSamInterface.kt");
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("inlinedSamWrapper.kt")
public void testInlinedSamWrapper() {
@@ -52959,6 +52959,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/sam/fieldInJavaSamInterface.kt");
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("inlinedSamWrapper.kt")
public void testInlinedSamWrapper() {
@@ -52959,6 +52959,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
runTest("compiler/testData/codegen/box/sam/fieldInJavaSamInterface.kt");
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("inlinedSamWrapper.kt")
public void testInlinedSamWrapper() {
@@ -52959,6 +52959,12 @@ public class FirBlackBoxCodegenTestWithInlineScopesGenerated extends AbstractFir
runTest("compiler/testData/codegen/box/sam/fieldInJavaSamInterface.kt");
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("inlinedSamWrapper.kt")
public void testInlinedSamWrapper() {
@@ -42746,6 +42746,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/sam/fieldInJavaSamInterface.kt");
}
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@TestMetadata("inlinedSamWrapper.kt")
public void testInlinedSamWrapper() {
runTest("compiler/testData/codegen/box/sam/inlinedSamWrapper.kt");
@@ -38319,6 +38319,12 @@ public class FirJsCodegenBoxTestGenerated extends AbstractFirJsCodegenBoxTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("kt51821.kt")
public void testKt51821() {
@@ -38319,6 +38319,12 @@ public class FirJsES6CodegenBoxTestGenerated extends AbstractFirJsES6CodegenBoxT
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("kt51821.kt")
public void testKt51821() {
@@ -37743,6 +37743,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("kt51821.kt")
public void testKt51821() {
@@ -37743,6 +37743,12 @@ public class IrJsES6CodegenBoxTestGenerated extends AbstractIrJsES6CodegenBoxTes
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("kt51821.kt")
public void testKt51821() {
@@ -41786,6 +41786,12 @@ public class FirNativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTe
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("kt51821.kt")
public void testKt51821() {
@@ -42826,6 +42826,12 @@ public class FirNativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenB
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("kt51821.kt")
public void testKt51821() {
@@ -40158,6 +40158,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("kt51821.kt")
public void testKt51821() {
@@ -41187,6 +41187,12 @@ public class NativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenBoxT
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("kt51821.kt")
public void testKt51821() {
@@ -38193,6 +38193,12 @@ public class FirWasmJsCodegenBoxTestGenerated extends AbstractFirWasmJsCodegenBo
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("kt51821.kt")
public void testKt51821() {
@@ -37617,6 +37617,12 @@ public class K1WasmCodegenBoxTestGenerated extends AbstractK1WasmCodegenBoxTest
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
}
@Test
@TestMetadata("inProjectedSam.kt")
public void testInProjectedSam() {
runTest("compiler/testData/codegen/box/sam/inProjectedSam.kt");
}
@Test
@TestMetadata("kt51821.kt")
public void testKt51821() {