PSI2IR: support SAM conversion to substituted types

i.e. in arguments to `f(T x)` where `T` is a type parameter bound to a
SAM type.
This commit is contained in:
pyos
2020-04-29 13:20:17 +02:00
committed by Dmitry Petrov
parent d9fd51c608
commit df4f1365ec
6 changed files with 45 additions and 3 deletions
@@ -14588,6 +14588,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/javaInterop/protectedField.kt"); runTest("compiler/testData/codegen/box/javaInterop/protectedField.kt");
} }
@TestMetadata("samTypeParameter.kt")
public void testSamTypeParameter() throws Exception {
runTest("compiler/testData/codegen/box/javaInterop/samTypeParameter.kt");
}
@TestMetadata("samUnboundTypeParameter.kt") @TestMetadata("samUnboundTypeParameter.kt")
public void testSamUnboundTypeParameter() throws Exception { public void testSamUnboundTypeParameter() throws Exception {
runTest("compiler/testData/codegen/box/javaInterop/samUnboundTypeParameter.kt"); runTest("compiler/testData/codegen/box/javaInterop/samUnboundTypeParameter.kt");
@@ -620,14 +620,18 @@ fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: Ca
for (i in underlyingValueParameters.indices) { for (i in underlyingValueParameters.indices) {
val underlyingValueParameter = underlyingValueParameters[i] val underlyingValueParameter = underlyingValueParameters[i]
val originalUnderlyingParameterType = underlyingValueParameter.original.type
if (expectSamConvertedArgumentToBeAvailableInResolvedCall && resolvedCall is NewResolvedCallImpl<*>) { if (expectSamConvertedArgumentToBeAvailableInResolvedCall && resolvedCall is NewResolvedCallImpl<*>) {
// TODO support SAM conversion of varargs // TODO support SAM conversion of varargs
val argument = resolvedCall.valueArguments[originalValueParameters[i]]?.arguments?.singleOrNull() ?: continue val argument = resolvedCall.valueArguments[originalValueParameters[i]]?.arguments?.singleOrNull() ?: continue
resolvedCall.getExpectedTypeForSamConvertedArgument(argument) ?: continue resolvedCall.getExpectedTypeForSamConvertedArgument(argument) ?: continue
} else { } else {
if (!context.extensions.samConversion.isSamType(originalUnderlyingParameterType)) continue // When the method is `f(T)` with `T` = a SAM type, the substituted type is a SAM while the original is not;
// when the method is `f(X<T>)` with `T` = `out V` where `X` is a SAM type, the substituted type is `Nothing`
// while the original is a SAM interface. Thus, if *either* of those is a SAM type then it's fine.
if (!samConversion.isSamType(underlyingValueParameter.type) &&
!samConversion.isSamType(underlyingValueParameter.original.type)
) continue
if (!originalValueParameters[i].type.isFunctionTypeOrSubtype) continue if (!originalValueParameters[i].type.isFunctionTypeOrSubtype) continue
} }
@@ -640,7 +644,7 @@ fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: Ca
val substitutedSamType = typeSubstitutor.substitute(samKotlinType, Variance.INVARIANT) val substitutedSamType = typeSubstitutor.substitute(samKotlinType, Variance.INVARIANT)
?: throw AssertionError( ?: throw AssertionError(
"Failed to substitute value argument type in SAM conversion: " + "Failed to substitute value argument type in SAM conversion: " +
"underlyingParameterType=$originalUnderlyingParameterType, " + "underlyingParameterType=${underlyingValueParameter.type}, " +
"substitutionContext=$substitutionContext" "substitutionContext=$substitutionContext"
) )
@@ -0,0 +1,18 @@
// TODO: new inference doesn't do SAM conversion in this case. KT-37149
// !LANGUAGE: -NewInference
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// FILE: Generic.java
class Generic<T> {
T id(T x) { return x; }
}
// FILE: Specialized.java
class Specialized extends Generic<Runnable> {}
// FILE: use.kt
fun box(): String {
var result = "fail"
Specialized().id { result = "OK" }.run()
return result
}
@@ -15803,6 +15803,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/javaInterop/protectedField.kt"); runTest("compiler/testData/codegen/box/javaInterop/protectedField.kt");
} }
@TestMetadata("samTypeParameter.kt")
public void testSamTypeParameter() throws Exception {
runTest("compiler/testData/codegen/box/javaInterop/samTypeParameter.kt");
}
@TestMetadata("samUnboundTypeParameter.kt") @TestMetadata("samUnboundTypeParameter.kt")
public void testSamUnboundTypeParameter() throws Exception { public void testSamUnboundTypeParameter() throws Exception {
runTest("compiler/testData/codegen/box/javaInterop/samUnboundTypeParameter.kt"); runTest("compiler/testData/codegen/box/javaInterop/samUnboundTypeParameter.kt");
@@ -15803,6 +15803,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/javaInterop/protectedField.kt"); runTest("compiler/testData/codegen/box/javaInterop/protectedField.kt");
} }
@TestMetadata("samTypeParameter.kt")
public void testSamTypeParameter() throws Exception {
runTest("compiler/testData/codegen/box/javaInterop/samTypeParameter.kt");
}
@TestMetadata("samUnboundTypeParameter.kt") @TestMetadata("samUnboundTypeParameter.kt")
public void testSamUnboundTypeParameter() throws Exception { public void testSamUnboundTypeParameter() throws Exception {
runTest("compiler/testData/codegen/box/javaInterop/samUnboundTypeParameter.kt"); runTest("compiler/testData/codegen/box/javaInterop/samUnboundTypeParameter.kt");
@@ -14588,6 +14588,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/javaInterop/protectedField.kt"); runTest("compiler/testData/codegen/box/javaInterop/protectedField.kt");
} }
@TestMetadata("samTypeParameter.kt")
public void testSamTypeParameter() throws Exception {
runTest("compiler/testData/codegen/box/javaInterop/samTypeParameter.kt");
}
@TestMetadata("samUnboundTypeParameter.kt") @TestMetadata("samUnboundTypeParameter.kt")
public void testSamUnboundTypeParameter() throws Exception { public void testSamUnboundTypeParameter() throws Exception {
runTest("compiler/testData/codegen/box/javaInterop/samUnboundTypeParameter.kt"); runTest("compiler/testData/codegen/box/javaInterop/samUnboundTypeParameter.kt");