From d2e6767c07bed474178cfeddff4361c378d4252e Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 13 Nov 2014 02:55:12 +0200 Subject: [PATCH] Delegation and nullability turned into capabilities Otherwise they did not sustain substitutions --- .../tests/dynamicTypes/dynamicCalls.kt | 4 ++-- .../tests/dynamicTypes/dynamicSafeCalls.kt | 10 ++++++++++ .../tests/dynamicTypes/dynamicSafeCalls.txt | 3 +++ .../tests/dynamicTypes/implicitDynamicReceiver.kt | 4 ++-- .../jet/checkers/JetDiagnosticsTestGenerated.java | 6 ++++++ .../org/jetbrains/jet/lang/types/dynamicTypes.kt | 15 ++++++++------- .../org/jetbrains/jet/lang/types/flexibleTypes.kt | 14 ++++++++++++-- 7 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/dynamicTypes/dynamicSafeCalls.kt create mode 100644 compiler/testData/diagnostics/tests/dynamicTypes/dynamicSafeCalls.txt diff --git a/compiler/testData/diagnostics/tests/dynamicTypes/dynamicCalls.kt b/compiler/testData/diagnostics/tests/dynamicTypes/dynamicCalls.kt index 3b190301e5e..e87f6e4fa3a 100644 --- a/compiler/testData/diagnostics/tests/dynamicTypes/dynamicCalls.kt +++ b/compiler/testData/diagnostics/tests/dynamicTypes/dynamicCalls.kt @@ -11,8 +11,8 @@ fun test(d: dynamic) { val v3 = d.foo(1, "") v3.isDynamic() // to check that anything is resolvable -// val v4 = d.foo() -// v4.isDynamic() // to check that anything is resolvable + val v4 = d.foo() + v4.isDynamic() // to check that anything is resolvable val v5 = d.foo v5.isDynamic() // to check that anything is resolvable diff --git a/compiler/testData/diagnostics/tests/dynamicTypes/dynamicSafeCalls.kt b/compiler/testData/diagnostics/tests/dynamicTypes/dynamicSafeCalls.kt new file mode 100644 index 00000000000..fe3a4bb1217 --- /dev/null +++ b/compiler/testData/diagnostics/tests/dynamicTypes/dynamicSafeCalls.kt @@ -0,0 +1,10 @@ +// MODULE[js]: m1 +// FILE: k.kt + +fun test(d: dynamic) { + val v1 = d?.foo() + v1.isDynamic() // to check that anything is resolvable + + val v2 = d!!.foo(1) + v2.isDynamic() // to check that anything is resolvable +} diff --git a/compiler/testData/diagnostics/tests/dynamicTypes/dynamicSafeCalls.txt b/compiler/testData/diagnostics/tests/dynamicTypes/dynamicSafeCalls.txt new file mode 100644 index 00000000000..41a648f7f82 --- /dev/null +++ b/compiler/testData/diagnostics/tests/dynamicTypes/dynamicSafeCalls.txt @@ -0,0 +1,3 @@ +package + +internal fun test(/*0*/ d: dynamic): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/dynamicTypes/implicitDynamicReceiver.kt b/compiler/testData/diagnostics/tests/dynamicTypes/implicitDynamicReceiver.kt index 8fd422bb026..5f0f49930d3 100644 --- a/compiler/testData/diagnostics/tests/dynamicTypes/implicitDynamicReceiver.kt +++ b/compiler/testData/diagnostics/tests/dynamicTypes/implicitDynamicReceiver.kt @@ -11,8 +11,8 @@ fun (dynamic).test() { val v3 = foo(1, "") v3.isDynamic() // to check that anything is resolvable -// val v4 = foo() -// v4.isDynamic() // to check that anything is resolvable + val v4 = foo() + v4.isDynamic() // to check that anything is resolvable val v5 = foo v5.isDynamic() // to check that anything is resolvable diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index e8b0e31d167..2bdabaa077d 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -3728,6 +3728,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("dynamicSafeCalls.kt") + public void testDynamicSafeCalls() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dynamicTypes/dynamicSafeCalls.kt"); + doTest(fileName); + } + @TestMetadata("implicitDynamicReceiver.kt") public void testImplicitDynamicReceiver() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dynamicTypes/implicitDynamicReceiver.kt"); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/dynamicTypes.kt b/core/descriptors/src/org/jetbrains/jet/lang/types/dynamicTypes.kt index 07639b419b7..31e92afeebd 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/dynamicTypes.kt +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/dynamicTypes.kt @@ -31,15 +31,13 @@ class DynamicTypesAllowed: DynamicTypesSettings() { trait Dynamicity : TypeCapability +// Object is created only for convenience here. Dynamic types may occur in the form of DelegatingFlexibleTypes, +// which are produced by substitutions object DynamicType : DelegatingFlexibleType( KotlinBuiltIns.getInstance().getNothingType(), KotlinBuiltIns.getInstance().getNullableAnyType(), DynamicTypeCapabilities -) { - override fun getDelegate() = upperBound - - override fun isNullable() = false -} +) fun JetType.isDynamic(): Boolean = this.getCapability(javaClass()) != null @@ -49,12 +47,13 @@ public object DynamicTypeCapabilities : FlexibleTypeCapabilities { override fun getCapability(capabilityClass: Class, jetType: JetType, flexibility: Flexibility): T? { if (capabilityClass.isAssignableFrom(javaClass())) [suppress("UNCHECKED_CAST")] - return Impl as T + return Impl(flexibility) as T else return null } - private object Impl : Dynamicity, Specificity, NullAwareness { + private class Impl(flexibility: Flexibility) : Dynamicity, Specificity, NullAwareness, FlexibleTypeDelegation { + override val delegateType: JetType = flexibility.upperBound override fun getSpecificityRelationTo(otherType: JetType): Specificity.Relation { return if (!otherType.isDynamic()) Specificity.Relation.LESS_SPECIFIC else Specificity.Relation.DONT_KNOW @@ -64,5 +63,7 @@ public object DynamicTypeCapabilities : FlexibleTypeCapabilities { // Nullability has no effect on dynamics return DynamicType } + + override fun computeIsNullable() = false } } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/flexibleTypes.kt b/core/descriptors/src/org/jetbrains/jet/lang/types/flexibleTypes.kt index a1e6cefaffb..cb60c8fd047 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/flexibleTypes.kt +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/flexibleTypes.kt @@ -90,6 +90,7 @@ public fun JetType.upperIfFlexible(): JetType = if (this.isFlexible()) this.flex public trait NullAwareness : TypeCapability { public fun makeNullableAsSpecified(nullable: Boolean): JetType + public fun computeIsNullable(): Boolean } public trait Approximation : TypeCapability { @@ -124,12 +125,15 @@ public fun JetType.getApproximationTo( extras: Approximation.DataFlowExtras = Approximation.DataFlowExtras.EMPTY ): Approximation.Info? = this.getCapability(javaClass())?.approximateToExpectedType(expectedType, extras) +trait FlexibleTypeDelegation : TypeCapability { + public val delegateType: JetType +} public open class DelegatingFlexibleType protected ( override val lowerBound: JetType, override val upperBound: JetType, override val extraCapabilities: FlexibleTypeCapabilities -) : DelegatingType(), NullAwareness, Flexibility, Approximation { +) : DelegatingType(), NullAwareness, Flexibility, FlexibleTypeDelegation, Approximation { class object { platformStatic fun create(lowerBound: JetType, upperBound: JetType, extraCapabilities: FlexibleTypeCapabilities): JetType { if (lowerBound == upperBound) return lowerBound @@ -157,6 +161,10 @@ public open class DelegatingFlexibleType protected ( extraCapabilities) } + override fun computeIsNullable() = delegateType.isNullable() + + override fun isNullable(): Boolean = getCapability(javaClass())!!.computeIsNullable() + override fun approximateToExpectedType(expectedType: JetType, dataFlowExtras: Approximation.DataFlowExtras): Approximation.Info? { // val foo: Any? = foo() : Foo! if (JetTypeChecker.DEFAULT.isSubtypeOf(upperBound, expectedType)) return null @@ -171,7 +179,9 @@ public open class DelegatingFlexibleType protected ( return Approximation.Info(this, expectedType, dataFlowExtras.presentableText) } - override fun getDelegate() = lowerBound + override val delegateType: JetType = lowerBound + + override fun getDelegate() = getCapability(javaClass())!!.delegateType override fun toString() = "('$lowerBound'..'$upperBound')" }