Null-aware types introduced
Flexible types should drive their own conversions to nullable/not-null
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
// FILE: p/Utils.java
|
||||
|
||||
package p;
|
||||
|
||||
public class Utils {
|
||||
public static java.util.Collection<String> c() { return null; }
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
import p.*
|
||||
|
||||
fun <T : Any> T.foo() {}
|
||||
|
||||
fun test<D>(b: Boolean) {
|
||||
val c = if (b) Utils.c() else null
|
||||
|
||||
c?.foo()
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// FILE: p/Utils.java
|
||||
|
||||
package p;
|
||||
|
||||
public class Utils {
|
||||
public static String str() { return null; }
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
import p.*
|
||||
|
||||
fun <T : Any> T.foo() {}
|
||||
|
||||
fun test<D>(b: Boolean) {
|
||||
val str = if (b) Utils.str() else null
|
||||
|
||||
str?.foo()
|
||||
}
|
||||
@@ -6157,7 +6157,8 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
|
||||
@TestMetadata("GenericsInSupertypes.kt")
|
||||
public void testGenericsInSupertypes() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/j+k/GenericsInSupertypes.kt");
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/GenericsInSupertypes.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inheritAbstractSamAdapter.kt")
|
||||
@@ -6168,7 +6169,8 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
|
||||
@TestMetadata("InheritedGenericFunction.kt")
|
||||
public void testInheritedGenericFunction() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/j+k/InheritedGenericFunction.kt");
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/InheritedGenericFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("innerNestedClassFromJava.kt")
|
||||
@@ -7698,7 +7700,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/platformTypes")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@InnerTestClasses({PlatformTypes.MethodCall.class})
|
||||
@InnerTestClasses({PlatformTypes.CommonSupertype.class, PlatformTypes.MethodCall.class})
|
||||
@RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class)
|
||||
public static class PlatformTypes extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInPlatformTypes() throws Exception {
|
||||
@@ -7719,7 +7721,8 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
|
||||
@TestMetadata("getParentOfType.kt")
|
||||
public void testGetParentOfType() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/platformTypes/getParentOfType.kt");
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/getParentOfType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inference.kt")
|
||||
@@ -7728,15 +7731,44 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("override.kt")
|
||||
public void testOverride() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/override.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("safeCall.kt")
|
||||
public void testSafeCall() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/safeCall.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("override.kt")
|
||||
public void testOverride() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/platformTypes/override.kt");
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/platformTypes/commonSupertype")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class)
|
||||
public static class CommonSupertype extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInCommonSupertype() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/platformTypes/commonSupertype"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("collectionOrNull.kt")
|
||||
public void testCollectionOrNull() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/commonSupertype/collectionOrNull.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inferenceWithBound.kt")
|
||||
public void testInferenceWithBound() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/commonSupertype/inferenceWithBound.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("stringOrNull.kt")
|
||||
public void testStringOrNull() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/commonSupertype/stringOrNull.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/platformTypes/methodCall")
|
||||
@@ -7747,11 +7779,6 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/platformTypes/methodCall"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("inferenceWithBound.kt")
|
||||
public void testInferenceWithBound() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/inferenceWithBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("int.kt")
|
||||
public void testInt() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/methodCall/int.kt");
|
||||
@@ -7802,7 +7829,8 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
|
||||
@TestMetadata("singleton.kt")
|
||||
public void testSingleton() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/singleton.kt");
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/methodCall/singleton.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("string.kt")
|
||||
@@ -7813,7 +7841,8 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
|
||||
@TestMetadata("visitor.kt")
|
||||
public void testVisitor() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/visitor.kt");
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/methodCall/visitor.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-3
@@ -61,7 +61,7 @@ class LazyJavaTypeResolver(
|
||||
val jetType = JavaToKotlinClassMap.getInstance().mapPrimitiveKotlinClass("[" + javaComponentType.getCanonicalText())
|
||||
if (jetType != null) {
|
||||
return if (PLATFORM_TYPES && attr.allowFlexible)
|
||||
DelegatingFlexibleType(jetType, TypeUtils.makeNullable(jetType))
|
||||
FlexibleJavaClassifierType.create(jetType, TypeUtils.makeNullable(jetType))
|
||||
else TypeUtils.makeNullableAsSpecified(jetType, !attr.isMarkedNotNull)
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ class LazyJavaTypeResolver(
|
||||
val componentType = transformJavaType(javaComponentType, howArgumentTypeIsUsed.toAttributes(attr.allowFlexible))
|
||||
val result = KotlinBuiltIns.getInstance().getArrayType(projectionKind, componentType)
|
||||
return if (PLATFORM_TYPES && attr.allowFlexible)
|
||||
DelegatingFlexibleType(
|
||||
FlexibleJavaClassifierType.create(
|
||||
KotlinBuiltIns.getInstance().getArrayType(INVARIANT, componentType),
|
||||
TypeUtils.makeNullable(
|
||||
KotlinBuiltIns.getInstance().getArrayType(OUT_VARIANCE, componentType)
|
||||
@@ -264,10 +264,20 @@ class LazyJavaTypeResolver(
|
||||
override fun isNullable(): Boolean = _nullable()
|
||||
}
|
||||
|
||||
private open class FlexibleJavaClassifierType(
|
||||
public open class FlexibleJavaClassifierType protected (
|
||||
lowerBound: JetType,
|
||||
upperBound: JetType
|
||||
) : DelegatingFlexibleType(lowerBound, upperBound), CustomTypeVariable {
|
||||
public class object {
|
||||
public fun create(lowerBound: JetType, upperBound: JetType): JetType {
|
||||
if (lowerBound == upperBound) return lowerBound
|
||||
return FlexibleJavaClassifierType(lowerBound, upperBound)
|
||||
}
|
||||
}
|
||||
|
||||
override fun create(lowerBound: JetType, upperBound: JetType): JetType {
|
||||
return FlexibleJavaClassifierType.create(lowerBound, upperBound)
|
||||
}
|
||||
|
||||
override val isTypeVariable: Boolean = lowerBound.getConstructor() == upperBound.getConstructor()
|
||||
&& lowerBound.getConstructor().getDeclarationDescriptor() is TypeParameterDescriptor
|
||||
|
||||
+2
-1
@@ -24,6 +24,7 @@ import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaPackage;
|
||||
import org.jetbrains.jet.lang.resolve.java.descriptor.*;
|
||||
import org.jetbrains.jet.lang.resolve.java.lazy.types.LazyJavaTypeResolver;
|
||||
import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.*;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
@@ -101,7 +102,7 @@ public class SingleAbstractMethodUtils {
|
||||
if (fixedProjections == null) return null;
|
||||
|
||||
if (JavaPackage.getPLATFORM_TYPES() && !isSamConstructor) {
|
||||
return new DelegatingFlexibleType(fixedProjections, TypeUtils.makeNullable(fixedProjections));
|
||||
return LazyJavaTypeResolver.FlexibleJavaClassifierType.OBJECT$.create(fixedProjections, TypeUtils.makeNullable(fixedProjections));
|
||||
}
|
||||
|
||||
return TypeUtils.makeNullableAsSpecified(fixedProjections, !isSamConstructor && samType.isNullable());
|
||||
|
||||
@@ -64,7 +64,7 @@ public class CommonSupertypes {
|
||||
}
|
||||
|
||||
if (!hasFlexible) return commonSuperTypeForInflexible(types);
|
||||
return new DelegatingFlexibleType(commonSuperTypeForInflexible(lower), commonSuperTypeForInflexible(upper));
|
||||
return DelegatingFlexibleType.OBJECT$.create(commonSuperTypeForInflexible(lower), commonSuperTypeForInflexible(upper));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -163,7 +163,7 @@ public class TypeSubstitutor {
|
||||
unsafeSubstitute(new TypeProjectionImpl(originalProjectionKind, flexibleType.getUpperBound()), recursionDepth + 1);
|
||||
// todo: projection kind is neglected
|
||||
return new TypeProjectionImpl(originalProjectionKind,
|
||||
new DelegatingFlexibleType(
|
||||
DelegatingFlexibleType.OBJECT$.create(
|
||||
substitutedLower.getType(),
|
||||
substitutedUpper.getType()
|
||||
)
|
||||
|
||||
@@ -111,7 +111,9 @@ public class TypeUtils {
|
||||
|
||||
@NotNull
|
||||
public static JetType makeNullableAsSpecified(@NotNull JetType type, boolean nullable) {
|
||||
if (TypesPackage.isFlexible(type)) return type;
|
||||
if (type instanceof NullAwareType) {
|
||||
return ((NullAwareType) type).makeNullableAsSpecified(nullable);
|
||||
}
|
||||
|
||||
// Wrapping serves two purposes here
|
||||
// 1. It's requires less memory than copying with a changed nullability flag: a copy has many fields, while a wrapper has only one
|
||||
|
||||
@@ -18,6 +18,10 @@ package org.jetbrains.jet.lang.types
|
||||
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
|
||||
|
||||
public trait NullAwareType {
|
||||
public fun makeNullableAsSpecified(nullable: Boolean): JetType
|
||||
}
|
||||
|
||||
public trait FlexibleType : JetType {
|
||||
public val lowerBound: JetType
|
||||
public val upperBound: JetType
|
||||
@@ -27,19 +31,34 @@ public fun JetType.isFlexible(): Boolean = this is FlexibleType
|
||||
|
||||
public fun JetType.lowerIfFlexible(): JetType = if (this is FlexibleType) lowerBound else this
|
||||
|
||||
public open class DelegatingFlexibleType(
|
||||
public open class DelegatingFlexibleType protected (
|
||||
override val lowerBound: JetType,
|
||||
override val upperBound: JetType
|
||||
) : DelegatingType(), FlexibleType {
|
||||
) : DelegatingType(), FlexibleType, NullAwareType {
|
||||
class object {
|
||||
public fun create(lowerBound: JetType, upperBound: JetType): JetType {
|
||||
if (lowerBound == upperBound) return lowerBound
|
||||
return DelegatingFlexibleType(lowerBound, upperBound)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
assert (!lowerBound.isFlexible()) { "Lower bound of a flexible type can not be flexible: $lowerBound" }
|
||||
assert (!upperBound.isFlexible()) { "Upper bound of a flexible type can not be flexible: $upperBound" }
|
||||
assert (lowerBound != upperBound) { "Lower and upper bounds are equal: $lowerBound == $upperBound" }
|
||||
assert (JetTypeChecker.DEFAULT.isSubtypeOf(lowerBound, upperBound)) {
|
||||
"Lower bound $lowerBound of a flexible type must be a subtype of the upper bound $upperBound"
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun create(lowerBound: JetType, upperBound: JetType): JetType {
|
||||
return DelegatingFlexibleType.create(lowerBound, upperBound)
|
||||
}
|
||||
|
||||
override fun makeNullableAsSpecified(nullable: Boolean): JetType {
|
||||
return create(TypeUtils.makeNullableAsSpecified(lowerBound, nullable), TypeUtils.makeNullableAsSpecified(upperBound, nullable))
|
||||
}
|
||||
|
||||
override fun getDelegate() = lowerBound
|
||||
|
||||
override fun toString() = "('$lowerBound'..'$upperBound')"
|
||||
|
||||
Reference in New Issue
Block a user