New J2K: Don't fail on captured types & don't use functional interface with captured types
Note: we have to print captured types for lambda parameters. It is needed for nullability inference as it requires explicit types specification to work. Later in post-processing we remove explicit type specifications for lambda parameters which have captured types #KT-33186 fixed
This commit is contained in:
+8
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.isNullable
|
import org.jetbrains.kotlin.types.isNullable
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isSignedOrUnsignedNumberType
|
import org.jetbrains.kotlin.types.typeUtil.isSignedOrUnsignedNumberType
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||||
@@ -56,6 +57,13 @@ val fixTypeMismatchDiagnosticBasedProcessing =
|
|||||||
val fix = NumberConversionFix(element, expectedType, disableIfAvailable = null)
|
val fix = NumberConversionFix(element, expectedType, disableIfAvailable = null)
|
||||||
fix.invoke(element.project, null, element.containingFile)
|
fix.invoke(element.project, null, element.containingFile)
|
||||||
}
|
}
|
||||||
|
element is KtLambdaExpression
|
||||||
|
&& expectedType.isNothing() -> {
|
||||||
|
for (valueParameter in element.valueParameters) {
|
||||||
|
valueParameter.typeReference?.delete()
|
||||||
|
valueParameter.colon?.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -360,9 +360,13 @@ class JavaToJKTreeBuilder constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun PsiFunctionalExpression.functionalType(): JKTypeElement =
|
fun PsiFunctionalExpression.functionalType(): JKTypeElement =
|
||||||
functionalInterfaceType?.toJK(symbolProvider)?.takeUnless { type ->
|
functionalInterfaceType
|
||||||
type.isKotlinFunctionType
|
?.takeUnless { type ->
|
||||||
}?.asTypeElement() ?: JKTypeElementImpl(JKNoTypeImpl)
|
type.safeAs<PsiClassType>()?.parameters?.any { it is PsiCapturedWildcardType } == true
|
||||||
|
}?.toJK(symbolProvider)
|
||||||
|
?.takeUnless { type ->
|
||||||
|
type.isKotlinFunctionType
|
||||||
|
}?.asTypeElement() ?: JKTypeElementImpl(JKNoTypeImpl)
|
||||||
|
|
||||||
fun PsiMethodReferenceExpression.toJK(): JKMethodReferenceExpression {
|
fun PsiMethodReferenceExpression.toJK(): JKMethodReferenceExpression {
|
||||||
val symbol = symbolProvider.provideSymbolForReference<JKSymbol>(this).let { symbol ->
|
val symbol = symbolProvider.provideSymbolForReference<JKSymbol>(this).let { symbol ->
|
||||||
|
|||||||
@@ -935,10 +935,25 @@ private class JKPrinter(
|
|||||||
private fun JKClassSymbol.needFqName(): Boolean =
|
private fun JKClassSymbol.needFqName(): Boolean =
|
||||||
fqName !in mappedToKotlinFqNames
|
fqName !in mappedToKotlinFqNames
|
||||||
|
|
||||||
|
private fun JKType.renderTypeInfo() {
|
||||||
|
print(elementInfoStorage.getOrCreateInfoForElement(this).render())
|
||||||
|
}
|
||||||
|
|
||||||
fun renderType(type: JKType, owner: JKTreeElement?) {
|
fun renderType(type: JKType, owner: JKTreeElement?) {
|
||||||
if (type is JKNoTypeImpl) return
|
if (type is JKNoTypeImpl) return
|
||||||
print(elementInfoStorage.getOrCreateInfoForElement(type).render())
|
if (type is JKCapturedType) {
|
||||||
|
when (val wildcard = type.wildcardType) {
|
||||||
|
is JKVarianceTypeParameterType -> {
|
||||||
|
renderType(wildcard.boundType, owner)
|
||||||
|
}
|
||||||
|
is JKStarProjectionType -> {
|
||||||
|
type.renderTypeInfo()
|
||||||
|
print("Any?")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
type.renderTypeInfo()
|
||||||
when (type) {
|
when (type) {
|
||||||
is JKClassType -> {
|
is JKClassType -> {
|
||||||
renderClassSymbol(type.classReference, owner)
|
renderClassSymbol(type.classReference, owner)
|
||||||
@@ -962,12 +977,11 @@ private class JKPrinter(
|
|||||||
renderList(type.parameters, renderElement = { renderType(it, null) })
|
renderList(type.parameters, renderElement = { renderType(it, null) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type.nullability == Nullability.Nullable) {
|
// we print undefined types as nullable because we need smartcast to work in nullability inference in post-processing
|
||||||
printWithNoIndent("?")
|
if (type !is JKWildCardType
|
||||||
}
|
&& (type.nullability == Nullability.Default
|
||||||
// we print undefined types as nullable because we need smartcast work in nullability inference in post-processing
|
&& owner?.safeAs<JKLambdaExpression>()?.functionalType?.type != type
|
||||||
if (type.nullability == Nullability.Default
|
|| type.nullability == Nullability.Nullable)
|
||||||
&& owner?.safeAs<JKLambdaExpression>()?.functionalType?.type != type
|
|
||||||
) {
|
) {
|
||||||
printWithNoIndent("?")
|
printWithNoIndent("?")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
|||||||
import org.jetbrains.kotlin.nj2k.*
|
import org.jetbrains.kotlin.nj2k.*
|
||||||
import org.jetbrains.kotlin.nj2k.symbols.JKUniverseMethodSymbol
|
import org.jetbrains.kotlin.nj2k.symbols.JKUniverseMethodSymbol
|
||||||
import org.jetbrains.kotlin.nj2k.tree.*
|
import org.jetbrains.kotlin.nj2k.tree.*
|
||||||
|
import org.jetbrains.kotlin.nj2k.tree.impl.JKCapturedType
|
||||||
import org.jetbrains.kotlin.nj2k.tree.impl.psi
|
import org.jetbrains.kotlin.nj2k.tree.impl.psi
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : RecursiveApplicableConversionBase() {
|
class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : RecursiveApplicableConversionBase() {
|
||||||
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
||||||
@@ -26,7 +28,9 @@ class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : R
|
|||||||
|
|
||||||
private fun addInfoForTypeElement(typeElement: JKTypeElement) {
|
private fun addInfoForTypeElement(typeElement: JKTypeElement) {
|
||||||
typeElement.type.forAllInnerTypes { type ->
|
typeElement.type.forAllInnerTypes { type ->
|
||||||
if (type.nullability == Nullability.Default) {
|
if (type.nullability == Nullability.Default
|
||||||
|
|| type.safeAs<JKCapturedType>()?.wildcardType is JKStarProjectionType
|
||||||
|
) {
|
||||||
context.elementsInfoStorage.addEntry(type, UnknownNullability)
|
context.elementsInfoStorage.addEntry(type, UnknownNullability)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,6 +113,12 @@ class TypeMappingConversion(val context: NewJ2kConverterContext) : RecursiveAppl
|
|||||||
variance,
|
variance,
|
||||||
boundType.mapType(null)
|
boundType.mapType(null)
|
||||||
)
|
)
|
||||||
|
is JKCapturedType -> {
|
||||||
|
JKCapturedType(
|
||||||
|
wildcardType.mapType(null) as JKWildCardType,
|
||||||
|
nullability
|
||||||
|
)
|
||||||
|
}
|
||||||
else -> this
|
else -> this
|
||||||
}.fixRawType(typeElement)
|
}.fixRawType(typeElement)
|
||||||
|
|
||||||
|
|||||||
@@ -490,6 +490,11 @@ data class JKTypeParameterTypeImpl(
|
|||||||
override val nullability: Nullability = Nullability.Default
|
override val nullability: Nullability = Nullability.Default
|
||||||
) : JKTypeParameterType
|
) : JKTypeParameterType
|
||||||
|
|
||||||
|
data class JKCapturedType(
|
||||||
|
val wildcardType: JKWildCardType,
|
||||||
|
override val nullability: Nullability = Nullability.Default
|
||||||
|
) : JKType
|
||||||
|
|
||||||
class JKEnumConstantImpl(
|
class JKEnumConstantImpl(
|
||||||
name: JKNameIdentifier,
|
name: JKNameIdentifier,
|
||||||
arguments: JKArgumentList,
|
arguments: JKArgumentList,
|
||||||
|
|||||||
@@ -61,11 +61,13 @@ interface JKType {
|
|||||||
fun JKType.isNullable(): Boolean =
|
fun JKType.isNullable(): Boolean =
|
||||||
nullability != Nullability.NotNull
|
nullability != Nullability.NotNull
|
||||||
|
|
||||||
interface JKVarianceTypeParameterType : JKType {
|
interface JKWildCardType : JKType
|
||||||
|
|
||||||
|
interface JKVarianceTypeParameterType : JKWildCardType {
|
||||||
val variance: Variance
|
val variance: Variance
|
||||||
val boundType: JKType
|
val boundType: JKType
|
||||||
override val nullability: Nullability
|
override val nullability: Nullability
|
||||||
get() = Nullability.NotNull
|
get() = Nullability.Default
|
||||||
|
|
||||||
enum class Variance {
|
enum class Variance {
|
||||||
IN, OUT
|
IN, OUT
|
||||||
@@ -97,7 +99,7 @@ interface JKJavaArrayType : JKType {
|
|||||||
val type: JKType
|
val type: JKType
|
||||||
}
|
}
|
||||||
|
|
||||||
interface JKStarProjectionType : JKType {
|
interface JKStarProjectionType : JKWildCardType {
|
||||||
override val nullability: Nullability
|
override val nullability: Nullability
|
||||||
get() = Nullability.NotNull
|
get() = Nullability.NotNull
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,11 @@ fun PsiType.toJK(symbolProvider: JKSymbolProvider, nullability: Nullability = Nu
|
|||||||
)
|
)
|
||||||
else -> JKStarProjectionTypeImpl()
|
else -> JKStarProjectionTypeImpl()
|
||||||
}
|
}
|
||||||
|
is PsiCapturedWildcardType ->
|
||||||
|
JKCapturedType(
|
||||||
|
wildcard.toJK(symbolProvider, nullability) as JKWildCardType,
|
||||||
|
nullability
|
||||||
|
)
|
||||||
else -> throw Exception("Invalid PSI ${this::class.java}")
|
else -> throw Exception("Invalid PSI ${this::class.java}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// RUNTIME_WITH_FULL_JDK
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class Test {
|
||||||
|
private void addPackages(Collection<? extends Number> packages) {
|
||||||
|
List<Number> sorted = packages.stream()
|
||||||
|
.filter(repoPackage -> repoPackage != null)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import java.util.stream.Collectors
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
private fun addPackages(packages: Collection<Number>) {
|
||||||
|
val sorted: List<Number> = packages.stream()
|
||||||
|
.filter { repoPackage: Number? -> repoPackage != null }
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
public interface SamFace<T> {
|
||||||
|
void samMethod(T p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SamAcceptor<T> {
|
||||||
|
public void acceptSam(SamFace<T> sam) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
public class Test {
|
||||||
|
public void useSamUpper(SamAcceptor<? extends Number> acceptor) {
|
||||||
|
acceptor.acceptSam(p -> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void useSamLower(SamAcceptor<? super Number> acceptor) {
|
||||||
|
acceptor.acceptSam(p -> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void useSam(SamAcceptor<?> acceptor) {
|
||||||
|
acceptor.acceptSam(p -> {});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
class Test {
|
||||||
|
fun useSamUpper(acceptor: SamAcceptor<out Number?>) {
|
||||||
|
acceptor.acceptSam { p: Number? -> }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun useSamLower(acceptor: SamAcceptor<in Number?>) {
|
||||||
|
acceptor.acceptSam { p -> }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun useSam(acceptor: SamAcceptor<*>) {
|
||||||
|
acceptor.acceptSam { p: Any? -> }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
public interface SamFace<T> {
|
||||||
|
void samMethod(int p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SamAcceptor<T> {
|
||||||
|
public void acceptSam(SamFace<T> sam) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
public class Test {
|
||||||
|
public void useSamUpper(SamAcceptor<? extends Number> acceptor) {
|
||||||
|
acceptor.acceptSam(p -> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void useSamLower(SamAcceptor<? super Number> acceptor) {
|
||||||
|
acceptor.acceptSam(p -> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void useSam(SamAcceptor<?> acceptor) {
|
||||||
|
acceptor.acceptSam(p -> {});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
class Test {
|
||||||
|
fun useSamUpper(acceptor: SamAcceptor<out Number?>) {
|
||||||
|
acceptor.acceptSam { p: Int -> }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun useSamLower(acceptor: SamAcceptor<in Number?>) {
|
||||||
|
acceptor.acceptSam { p: Int -> }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun useSam(acceptor: SamAcceptor<*>) {
|
||||||
|
acceptor.acceptSam { p: Int -> }
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -5001,6 +5001,34 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nj2k/testData/newJ2k/types")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Types extends AbstractNewJavaToKotlinConverterSingleFileTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInTypes() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("nj2k/testData/newJ2k/types"), Pattern.compile("^([^\\.]+)\\.java$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("capturedTypeInStreamsLambda.java")
|
||||||
|
public void testCapturedTypeInStreamsLambda() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/types/capturedTypeInStreamsLambda.java");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("capturedWildcardTypeAsLambdaParameter.java")
|
||||||
|
public void testCapturedWildcardTypeAsLambdaParameter() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/types/capturedWildcardTypeAsLambdaParameter.java");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("unusedCapturedWildcardTypeInSAM.java")
|
||||||
|
public void testUnusedCapturedWildcardTypeInSAM() throws Exception {
|
||||||
|
runTest("nj2k/testData/newJ2k/types/unusedCapturedWildcardTypeInSAM.java");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nj2k/testData/newJ2k/varArg")
|
@TestMetadata("nj2k/testData/newJ2k/varArg")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user