FIR: permit * as FunctionN type argument

`() -> *` is not valid, but `F<*>` where `typealias F<T> = () -> T` is.
This commit is contained in:
pyos
2021-02-02 14:08:31 +01:00
committed by TeamCityServer
parent 32dacc37c0
commit 354acc1fd5
13 changed files with 79 additions and 67 deletions
@@ -17022,6 +17022,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/inference/kt42130.kt");
}
@Test
@TestMetadata("lambdaWithStarReturn.kt")
public void testLambdaWithStarReturn() throws Exception {
runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt");
}
@Test
@TestMetadata("lambdasWithExtensionFunctionType.kt")
public void testLambdasWithExtensionFunctionType() throws Exception {
@@ -508,7 +508,7 @@ fun FirExpression.isFunctional(
session, scopeSession, classLikeExpectedFunctionType, shouldCalculateReturnTypesOfFakeOverrides = false
) ?: return false
// Make sure the contributed `invoke` is indeed a wanted functional type by checking if types are compatible.
val expectedReturnType = classLikeExpectedFunctionType.returnType(session)!!.lowerBoundIfFlexible()
val expectedReturnType = classLikeExpectedFunctionType.returnType(session).lowerBoundIfFlexible()
val returnTypeCompatible =
expectedReturnType is ConeTypeParameterType ||
AbstractTypeChecker.isSubtypeOf(
@@ -529,7 +529,7 @@ fun FirExpression.isFunctional(
val parameterPairs =
invokeSymbol.fir.valueParameters.zip(classLikeExpectedFunctionType.valueParameterTypesIncludingReceiver(session))
return parameterPairs.all { (invokeParameter, expectedParameter) ->
val expectedParameterType = expectedParameter!!.lowerBoundIfFlexible()
val expectedParameterType = expectedParameter.lowerBoundIfFlexible()
expectedParameterType is ConeTypeParameterType ||
AbstractTypeChecker.isSubtypeOf(
session.inferenceComponents.ctx.newBaseTypeCheckerContext(
@@ -202,22 +202,28 @@ fun ConeKotlinType.isKClassType(): Boolean {
}
fun ConeKotlinType.receiverType(session: FirSession): ConeKotlinType? {
if (isBuiltinFunctionalType(session) && isExtensionFunctionType(session)) {
return (this.fullyExpandedType(session).typeArguments.first() as ConeKotlinTypeProjection).type
if (!isBuiltinFunctionalType(session) || !isExtensionFunctionType(session)) return null
return when (val projection = fullyExpandedType(session).typeArguments.first()) {
is ConeKotlinTypeProjection -> projection.type
is ConeStarProjection -> session.builtinTypes.nothingType.type
}
return null
}
fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType? {
fun ConeKotlinType.returnType(session: FirSession): ConeKotlinType {
require(this is ConeClassLikeType)
val projection = fullyExpandedType(session).typeArguments.last()
return (projection as? ConeKotlinTypeProjection)?.type
return when (val projection = fullyExpandedType(session).typeArguments.last()) {
is ConeKotlinTypeProjection -> projection.type
is ConeStarProjection -> session.builtinTypes.nullableAnyType.type
}
}
fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List<ConeKotlinType?> {
fun ConeKotlinType.valueParameterTypesIncludingReceiver(session: FirSession): List<ConeKotlinType> {
require(this is ConeClassLikeType)
return fullyExpandedType(session).typeArguments.dropLast(1).map {
(it as? ConeKotlinTypeProjection)?.type
when (it) {
is ConeKotlinTypeProjection -> it.type
is ConeStarProjection -> session.builtinTypes.nothingType.type
}
}
}
@@ -252,11 +258,22 @@ fun extractLambdaInfoFromFunctionalType(
// Simply { }, i.e., function literals without body. Raw FIR added an implicit return with an implicit unit type ref.
if (lastStatement?.source?.kind is FirFakeSourceElementKind.ImplicitReturn &&
(lastStatement as? FirReturnExpression)?.result?.source?.kind is FirFakeSourceElementKind.ImplicitUnit
) {
)
session.builtinTypes.unitType.type
} else
argument.returnType ?: expectedType.returnType(session) ?: return null
val parameters = extractLambdaParameters(expectedType, argument, expectedType.isExtensionFunctionType(session), session)
else
argument.returnType ?: expectedType.returnType(session)
val expectedParameters = expectedType.valueParameterTypesIncludingReceiver(session).let {
if (expectedType.isExtensionFunctionType(session)) it.drop(1) else it
}
val parameters = if (argument.valueParameters.isEmpty()) {
expectedParameters
} else {
// TODO: `(A) -> B` is permitted as `A.() -> B` if it's an anonymous function, not a lambda;
// e.g. `fun (x: Any?) = x` can be used as `Any?.() -> Any?`, but `{ it -> it }` cannot.
argument.valueParameters.mapIndexed { index, parameter ->
parameter.returnTypeRef.coneTypeSafe() ?: expectedParameters.getOrNull(index) ?: session.builtinTypes.nothingType.type
}
}
return ResolvedLambdaAtom(
argument,
@@ -269,35 +286,3 @@ fun extractLambdaInfoFromFunctionalType(
candidate
)
}
private fun extractLambdaParameters(
expectedType: ConeKotlinType,
argument: FirAnonymousFunction,
expectedTypeIsExtensionFunctionType: Boolean,
session: FirSession
): List<ConeKotlinType> {
val parameters = argument.valueParameters
val expectedParameters = expectedType.extractParametersForFunctionalType(expectedTypeIsExtensionFunctionType, session)
val nullableAnyType = argument.session.builtinTypes.nullableAnyType.type
if (parameters.isEmpty()) {
return expectedParameters.map { it?.type ?: nullableAnyType }
}
return parameters.mapIndexed { index, parameter ->
parameter.returnTypeRef.coneTypeSafe() ?: expectedParameters.getOrNull(index) ?: nullableAnyType
}
}
private fun ConeKotlinType.extractParametersForFunctionalType(
isExtensionFunctionType: Boolean,
session: FirSession
): List<ConeKotlinType?> {
return valueParameterTypesIncludingReceiver(session).let {
if (isExtensionFunctionType) {
it.drop(1)
} else {
it
}
}
}
@@ -164,7 +164,7 @@ internal fun extractInputOutputTypesFromCallableReferenceExpectedType(
return when {
expectedType.isBuiltinFunctionalType(session) ->
extractInputOutputTypesFromFunctionType(expectedType, session)
InputOutputTypes(expectedType.valueParameterTypesIncludingReceiver(session), expectedType.returnType(session))
// ReflectionTypes.isBaseTypeForNumberedReferenceTypes(expectedType) ->
// InputOutputTypes(emptyList(), expectedType.arguments.single().type.unwrap())
@@ -187,22 +187,3 @@ internal fun extractInputOutputTypesFromCallableReferenceExpectedType(
else -> null
}
}
private fun extractInputOutputTypesFromFunctionType(
functionType: ConeKotlinType,
session: FirSession
): InputOutputTypes {
val parameters = functionType.valueParameterTypesIncludingReceiver(session).map {
it ?: ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(StandardClassIds.Nothing), emptyArray(),
isNullable = false
)
}
val outputType = functionType.returnType(session) ?: ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(StandardClassIds.Any), emptyArray(),
isNullable = true
)
return InputOutputTypes(parameters, outputType)
}
@@ -0,0 +1,3 @@
fun invoke(f: Function1<Any?, *>) = f("OK")
fun box() = invoke { it } as String
@@ -228,7 +228,7 @@ fun main() {
val x70: (Int) -> Unit = selectNumber(id(fun (it) { }), id {}, id {})
val x71: String.() -> Unit = select(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.String, kotlin.Unit>")!>id(fun String.() { })<!>, <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.String, kotlin.Unit>")!>id(fun(x: String) {})<!>)
val x72: String.() -> Unit = select(fun String.() { }, fun(x: String) {}) // must be error
select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), fun (x, y) { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>x<!>;<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>y<!> })
select(id(fun String.(x: String) {}), id(fun(x: String, y: String) { }), fun (x, y) { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>x<!>;<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!>y<!> })
select(id<Int.(String) -> Unit>(fun (x, y) {}), { x: Int, y: String -> x }) // receiver of anonymous function must be specified explicitly
select(id<Int.(String) -> Unit>(fun Int.(y) {}), { x: Int, y: String -> x })
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.Number, java.io.Serializable>")!>select(A3(), fun (x) = "", { a -> <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number")!>a<!> })<!>
@@ -17004,6 +17004,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/inference/kt42130.kt");
}
@Test
@TestMetadata("lambdaWithStarReturn.kt")
public void testLambdaWithStarReturn() throws Exception {
runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt");
}
@Test
@TestMetadata("lambdasWithExtensionFunctionType.kt")
public void testLambdasWithExtensionFunctionType() throws Exception {
@@ -17022,6 +17022,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/inference/kt42130.kt");
}
@Test
@TestMetadata("lambdaWithStarReturn.kt")
public void testLambdaWithStarReturn() throws Exception {
runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt");
}
@Test
@TestMetadata("lambdasWithExtensionFunctionType.kt")
public void testLambdasWithExtensionFunctionType() throws Exception {
@@ -14086,6 +14086,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/inference/kt42130.kt");
}
@TestMetadata("lambdaWithStarReturn.kt")
public void testLambdaWithStarReturn() throws Exception {
runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt");
}
@TestMetadata("lambdasWithExtensionFunctionType.kt")
public void testLambdasWithExtensionFunctionType() throws Exception {
runTest("compiler/testData/codegen/box/inference/lambdasWithExtensionFunctionType.kt");
@@ -12370,6 +12370,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/inference/kt42130.kt");
}
@TestMetadata("lambdaWithStarReturn.kt")
public void testLambdaWithStarReturn() throws Exception {
runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt");
}
@TestMetadata("lambdasWithExtensionFunctionType.kt")
public void testLambdasWithExtensionFunctionType() throws Exception {
runTest("compiler/testData/codegen/box/inference/lambdasWithExtensionFunctionType.kt");
@@ -11791,6 +11791,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inference/kt42130.kt");
}
@TestMetadata("lambdaWithStarReturn.kt")
public void testLambdaWithStarReturn() throws Exception {
runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt");
}
@TestMetadata("lambdasWithExtensionFunctionType.kt")
public void testLambdasWithExtensionFunctionType() throws Exception {
runTest("compiler/testData/codegen/box/inference/lambdasWithExtensionFunctionType.kt");
@@ -11856,6 +11856,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inference/kt42130.kt");
}
@TestMetadata("lambdaWithStarReturn.kt")
public void testLambdaWithStarReturn() throws Exception {
runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt");
}
@TestMetadata("lambdasWithExtensionFunctionType.kt")
public void testLambdasWithExtensionFunctionType() throws Exception {
runTest("compiler/testData/codegen/box/inference/lambdasWithExtensionFunctionType.kt");
@@ -6256,6 +6256,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/inference/kt42130.kt");
}
@TestMetadata("lambdaWithStarReturn.kt")
public void testLambdaWithStarReturn() throws Exception {
runTest("compiler/testData/codegen/box/inference/lambdaWithStarReturn.kt");
}
@TestMetadata("lambdasWithExtensionFunctionType.kt")
public void testLambdasWithExtensionFunctionType() throws Exception {
runTest("compiler/testData/codegen/box/inference/lambdasWithExtensionFunctionType.kt");