J2K: Fix type parameters in LHS of callable reference

This commit is contained in:
Simon Ogorodnik
2020-07-17 17:22:39 +03:00
parent 96d0b1c47a
commit 468af0bb85
8 changed files with 69 additions and 7 deletions
@@ -450,13 +450,20 @@ class JavaToJKTreeBuilder constructor(
} }
return JKMethodReferenceExpression( return JKMethodReferenceExpression(
qualifierExpression?.toJK() ?: JKStubExpression(), methodReferenceQualifier(),
symbol, symbol,
functionalType(), functionalType(),
isConstructor isConstructor
) )
} }
fun PsiMethodReferenceExpression.methodReferenceQualifier(): JKExpression {
val qualifierType = qualifierType
if (qualifierType != null) return JKTypeQualifierExpression(typeFactory.fromPsiType(qualifierType.type))
return qualifierExpression?.toJK() ?: JKStubExpression()
}
fun PsiReferenceExpression.toJK(): JKExpression { fun PsiReferenceExpression.toJK(): JKExpression {
if (this is PsiMethodReferenceExpression) return toJK() if (this is PsiMethodReferenceExpression) return toJK()
val target = resolve() val target = resolve()
@@ -476,6 +483,7 @@ class JavaToJKTreeBuilder constructor(
is JKFieldSymbol -> JKFieldAccessExpression(symbol) is JKFieldSymbol -> JKFieldAccessExpression(symbol)
is JKPackageSymbol -> JKPackageAccessExpression(symbol) is JKPackageSymbol -> JKPackageAccessExpression(symbol)
is JKMethodSymbol -> JKMethodAccessExpression(symbol) is JKMethodSymbol -> JKMethodAccessExpression(symbol)
is JKTypeParameterSymbol -> JKTypeQualifierExpression(JKTypeParameterType(symbol))
else -> throwCanNotConvertError("unexpected symbol ${symbol::class}") else -> throwCanNotConvertError("unexpected symbol ${symbol::class}")
}.qualified(qualifierExpression?.toJK()).also { }.qualified(qualifierExpression?.toJK()).also {
it.withFormattingFrom(this) it.withFormattingFrom(this)
@@ -32,19 +32,25 @@ class MethodReferenceToLambdaConversion(context: NewJ2kConverterContext) : Recur
.safeAs<JKClassType>() .safeAs<JKClassType>()
?.singleFunctionParameterTypes() ?.singleFunctionParameterTypes()
val receiverParameter = element.qualifier val qualifierExpression = element.qualifier
.nullIfStubExpression() .nullIfStubExpression()
?.safeAs<JKClassAccessExpression>()
?.takeIf { symbol.safeAs<JKMethodSymbol>()?.isStatic == false && !element.isConstructorCall } val receiverParameter = if (symbol.safeAs<JKMethodSymbol>()?.isStatic == false && !element.isConstructorCall) {
?.let { classAccessExpression -> val type = when (qualifierExpression) {
is JKTypeQualifierExpression -> qualifierExpression.type
is JKClassAccessExpression -> JKClassType(qualifierExpression.identifier)
else -> null
}
if (type != null) {
JKParameter( JKParameter(
JKTypeElement( JKTypeElement(
parametersTypesByFunctionalInterface?.firstOrNull() ?: JKClassType(classAccessExpression.identifier) parametersTypesByFunctionalInterface?.firstOrNull() ?: type
), ),
JKNameIdentifier(RECEIVER_NAME), JKNameIdentifier(RECEIVER_NAME),
isVarArgs = false isVarArgs = false
) )
} } else null
} else null
val explicitParameterTypesByFunctionalInterface = val explicitParameterTypesByFunctionalInterface =
if (receiverParameter != null) parametersTypesByFunctionalInterface?.drop(1) if (receiverParameter != null) parametersTypesByFunctionalInterface?.drop(1)
@@ -146,6 +146,10 @@ internal class JKCodeBuilder(context: NewJ2kConverterContext) {
printer.renderSymbol(methodAccessExpression.identifier, methodAccessExpression) printer.renderSymbol(methodAccessExpression.identifier, methodAccessExpression)
} }
override fun visitTypeQualifierExpression(typeQualifierExpression: JKTypeQualifierExpression) {
printer.renderType(typeQualifierExpression.type, typeQualifierExpression)
}
override fun visitFileRaw(file: JKFile) { override fun visitFileRaw(file: JKFile) {
if (file.packageDeclaration.name.value.isNotEmpty()) { if (file.packageDeclaration.name.value.isNotEmpty()) {
file.packageDeclaration.accept(this) file.packageDeclaration.accept(this)
@@ -201,6 +201,11 @@ class JKMethodAccessExpression(val identifier: JKMethodSymbol) : JKExpression()
override fun accept(visitor: JKVisitor) = visitor.visitMethodAccessExpression(this) override fun accept(visitor: JKVisitor) = visitor.visitMethodAccessExpression(this)
} }
class JKTypeQualifierExpression(val type: JKType) : JKExpression() {
override fun calculateType(typeFactory: JKTypeFactory): JKType? = null
override fun accept(visitor: JKVisitor) = visitor.visitTypeQualifierExpression(this)
}
class JKMethodReferenceExpression( class JKMethodReferenceExpression(
qualifier: JKExpression, qualifier: JKExpression,
val identifier: JKSymbol, val identifier: JKSymbol,
@@ -84,6 +84,7 @@ abstract class JKVisitor {
open fun visitPackageAccessExpression(packageAccessExpression: JKPackageAccessExpression) = visitExpression(packageAccessExpression) open fun visitPackageAccessExpression(packageAccessExpression: JKPackageAccessExpression) = visitExpression(packageAccessExpression)
open fun visitClassAccessExpression(classAccessExpression: JKClassAccessExpression) = visitExpression(classAccessExpression) open fun visitClassAccessExpression(classAccessExpression: JKClassAccessExpression) = visitExpression(classAccessExpression)
open fun visitMethodAccessExpression(methodAccessExpression: JKMethodAccessExpression) = visitExpression(methodAccessExpression) open fun visitMethodAccessExpression(methodAccessExpression: JKMethodAccessExpression) = visitExpression(methodAccessExpression)
open fun visitTypeQualifierExpression(typeQualifierExpression: JKTypeQualifierExpression) = visitExpression(typeQualifierExpression)
open fun visitMethodReferenceExpression(methodReferenceExpression: JKMethodReferenceExpression) = open fun visitMethodReferenceExpression(methodReferenceExpression: JKMethodReferenceExpression) =
visitExpression(methodReferenceExpression) visitExpression(methodReferenceExpression)
@@ -0,0 +1,21 @@
// RUNTIME_WITH_FULL_JDK
import java.util.List;
public class TestLambda<T> {
public static class Box<Q> {
private Q value;
public Q unbox() {
return value;
}
public Box(Q q) {
value = q;
}
}
public String toStringAllBox(List<Box<T>> list) {
return list.stream().map(Box<T>::unbox).map(T::toString).reduce((s1,s2) -> s1 + ", " + s2 ).orElse("");
}
}
@@ -0,0 +1,12 @@
class TestLambda<T> {
class Box<Q>(private val value: Q) {
fun unbox(): Q {
return value
}
}
fun toStringAllBox(list: List<Box<T>>): String {
return list.stream().map { obj: Box<T> -> obj.unbox() }.map { obj: T -> obj.toString() }
.reduce { s1: String, s2: String -> "$s1, $s2" }.orElse("")
}
}
@@ -2422,6 +2422,11 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew
runTest("nj2k/testData/newJ2k/function/functionInFinalClass.java"); runTest("nj2k/testData/newJ2k/function/functionInFinalClass.java");
} }
@TestMetadata("genericMemberFunctionRef.java")
public void testGenericMemberFunctionRef() throws Exception {
runTest("nj2k/testData/newJ2k/function/genericMemberFunctionRef.java");
}
@TestMetadata("internal.java") @TestMetadata("internal.java")
public void testInternal() throws Exception { public void testInternal() throws Exception {
runTest("nj2k/testData/newJ2k/function/internal.java"); runTest("nj2k/testData/newJ2k/function/internal.java");