Null-aware types introduced

Flexible types should drive their own conversions to nullable/not-null
This commit is contained in:
Andrey Breslav
2014-08-26 16:07:23 +04:00
parent 969beb7898
commit 220c360081
10 changed files with 122 additions and 23 deletions
@@ -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);
}
}
@@ -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
@@ -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')"