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.types.KotlinType
|
||||
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.isSubtypeOf
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
@@ -56,6 +57,13 @@ val fixTypeMismatchDiagnosticBasedProcessing =
|
||||
val fix = NumberConversionFix(element, expectedType, disableIfAvailable = null)
|
||||
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 =
|
||||
functionalInterfaceType?.toJK(symbolProvider)?.takeUnless { type ->
|
||||
type.isKotlinFunctionType
|
||||
}?.asTypeElement() ?: JKTypeElementImpl(JKNoTypeImpl)
|
||||
functionalInterfaceType
|
||||
?.takeUnless { type ->
|
||||
type.safeAs<PsiClassType>()?.parameters?.any { it is PsiCapturedWildcardType } == true
|
||||
}?.toJK(symbolProvider)
|
||||
?.takeUnless { type ->
|
||||
type.isKotlinFunctionType
|
||||
}?.asTypeElement() ?: JKTypeElementImpl(JKNoTypeImpl)
|
||||
|
||||
fun PsiMethodReferenceExpression.toJK(): JKMethodReferenceExpression {
|
||||
val symbol = symbolProvider.provideSymbolForReference<JKSymbol>(this).let { symbol ->
|
||||
|
||||
@@ -935,10 +935,25 @@ private class JKPrinter(
|
||||
private fun JKClassSymbol.needFqName(): Boolean =
|
||||
fqName !in mappedToKotlinFqNames
|
||||
|
||||
private fun JKType.renderTypeInfo() {
|
||||
print(elementInfoStorage.getOrCreateInfoForElement(this).render())
|
||||
}
|
||||
|
||||
fun renderType(type: JKType, owner: JKTreeElement?) {
|
||||
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) {
|
||||
is JKClassType -> {
|
||||
renderClassSymbol(type.classReference, owner)
|
||||
@@ -962,12 +977,11 @@ private class JKPrinter(
|
||||
renderList(type.parameters, renderElement = { renderType(it, null) })
|
||||
}
|
||||
}
|
||||
if (type.nullability == Nullability.Nullable) {
|
||||
printWithNoIndent("?")
|
||||
}
|
||||
// we print undefined types as nullable because we need smartcast work in nullability inference in post-processing
|
||||
if (type.nullability == Nullability.Default
|
||||
&& owner?.safeAs<JKLambdaExpression>()?.functionalType?.type != type
|
||||
// we print undefined types as nullable because we need smartcast to work in nullability inference in post-processing
|
||||
if (type !is JKWildCardType
|
||||
&& (type.nullability == Nullability.Default
|
||||
&& owner?.safeAs<JKLambdaExpression>()?.functionalType?.type != type
|
||||
|| type.nullability == Nullability.Nullable)
|
||||
) {
|
||||
printWithNoIndent("?")
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@ import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.nj2k.*
|
||||
import org.jetbrains.kotlin.nj2k.symbols.JKUniverseMethodSymbol
|
||||
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.utils.addToStdlib.safeAs
|
||||
|
||||
class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : RecursiveApplicableConversionBase() {
|
||||
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
||||
@@ -26,7 +28,9 @@ class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : R
|
||||
|
||||
private fun addInfoForTypeElement(typeElement: JKTypeElement) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,12 @@ class TypeMappingConversion(val context: NewJ2kConverterContext) : RecursiveAppl
|
||||
variance,
|
||||
boundType.mapType(null)
|
||||
)
|
||||
is JKCapturedType -> {
|
||||
JKCapturedType(
|
||||
wildcardType.mapType(null) as JKWildCardType,
|
||||
nullability
|
||||
)
|
||||
}
|
||||
else -> this
|
||||
}.fixRawType(typeElement)
|
||||
|
||||
|
||||
@@ -490,6 +490,11 @@ data class JKTypeParameterTypeImpl(
|
||||
override val nullability: Nullability = Nullability.Default
|
||||
) : JKTypeParameterType
|
||||
|
||||
data class JKCapturedType(
|
||||
val wildcardType: JKWildCardType,
|
||||
override val nullability: Nullability = Nullability.Default
|
||||
) : JKType
|
||||
|
||||
class JKEnumConstantImpl(
|
||||
name: JKNameIdentifier,
|
||||
arguments: JKArgumentList,
|
||||
|
||||
@@ -61,11 +61,13 @@ interface JKType {
|
||||
fun JKType.isNullable(): Boolean =
|
||||
nullability != Nullability.NotNull
|
||||
|
||||
interface JKVarianceTypeParameterType : JKType {
|
||||
interface JKWildCardType : JKType
|
||||
|
||||
interface JKVarianceTypeParameterType : JKWildCardType {
|
||||
val variance: Variance
|
||||
val boundType: JKType
|
||||
override val nullability: Nullability
|
||||
get() = Nullability.NotNull
|
||||
get() = Nullability.Default
|
||||
|
||||
enum class Variance {
|
||||
IN, OUT
|
||||
@@ -97,7 +99,7 @@ interface JKJavaArrayType : JKType {
|
||||
val type: JKType
|
||||
}
|
||||
|
||||
interface JKStarProjectionType : JKType {
|
||||
interface JKStarProjectionType : JKWildCardType {
|
||||
override val nullability: Nullability
|
||||
get() = Nullability.NotNull
|
||||
}
|
||||
|
||||
@@ -121,6 +121,11 @@ fun PsiType.toJK(symbolProvider: JKSymbolProvider, nullability: Nullability = Nu
|
||||
)
|
||||
else -> JKStarProjectionTypeImpl()
|
||||
}
|
||||
is PsiCapturedWildcardType ->
|
||||
JKCapturedType(
|
||||
wildcard.toJK(symbolProvider, nullability) as JKWildCardType,
|
||||
nullability
|
||||
)
|
||||
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")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user