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 5921328bcb8..0b76e32371d 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/flexibleTypes.kt +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/flexibleTypes.kt @@ -61,6 +61,11 @@ public trait Flexibility : TypeCapability, SubtypingRepresentatives { public fun JetType.isFlexible(): Boolean = this.getCapability(javaClass()) != null public fun JetType.flexibility(): Flexibility = this.getCapability(javaClass())!! +public fun JetType.isNullabilityFlexible(): Boolean { + val flexibility = this.getCapability(javaClass()) ?: return false + return TypeUtils.isNullableType(flexibility.lowerBound) != TypeUtils.isNullableType(flexibility.upperBound) +} + // This function is intended primarily for sets: since JetType.equals() represents _syntactical_ equality of types, // whereas JetTypeChecker.DEFAULT.equalsTypes() represents semantical equality // A set of types (e.g. exact bounds etc) may contain, for example, X, X? and X! diff --git a/idea/ide-common/src/org/jetbrains/jet/plugin/util/FuzzyType.kt b/idea/ide-common/src/org/jetbrains/jet/plugin/util/FuzzyType.kt index 9cbdc5e9175..c779aee83d2 100644 --- a/idea/ide-common/src/org/jetbrains/jet/plugin/util/FuzzyType.kt +++ b/idea/ide-common/src/org/jetbrains/jet/plugin/util/FuzzyType.kt @@ -42,7 +42,7 @@ fun CallableDescriptor.fuzzyExtensionReceiverType(): FuzzyType? { fun FuzzyType.makeNotNullable() = FuzzyType(type.makeNotNullable(), freeParameters) fun FuzzyType.makeNullable() = FuzzyType(type.makeNullable(), freeParameters) -fun FuzzyType.isNullable() = type.isMarkedNullable() +fun FuzzyType.nullability() = type.nullability() class FuzzyType( val type: JetType, diff --git a/idea/ide-common/src/org/jetbrains/jet/plugin/util/TypeUtils.kt b/idea/ide-common/src/org/jetbrains/jet/plugin/util/TypeUtils.kt index c6c45c4a8e0..e9065334bbe 100644 --- a/idea/ide-common/src/org/jetbrains/jet/plugin/util/TypeUtils.kt +++ b/idea/ide-common/src/org/jetbrains/jet/plugin/util/TypeUtils.kt @@ -29,6 +29,7 @@ import org.jetbrains.jet.lang.types.isFlexible import org.jetbrains.jet.lang.types.flexibility import java.util.LinkedHashSet import org.jetbrains.jet.lang.types.isDynamic +import org.jetbrains.jet.lang.types.isNullabilityFlexible fun JetType.makeNullable() = TypeUtils.makeNullable(this) fun JetType.makeNotNullable() = TypeUtils.makeNotNullable(this) @@ -78,4 +79,18 @@ public fun JetType.getAllReferencedTypes(): Set { addType(this) return types +} + +public enum class TypeNullability { + NOT_NULL + NULLABLE + FLEXIBLE +} + +public fun JetType.nullability(): TypeNullability { + return when { + isNullabilityFlexible() -> TypeNullability.FLEXIBLE + TypeUtils.isNullableType(this) -> TypeNullability.NULLABLE + else -> TypeNullability.NOT_NULL + } } \ No newline at end of file diff --git a/idea/ide-common/src/org/jetbrains/jet/plugin/util/extensionsUtils.kt b/idea/ide-common/src/org/jetbrains/jet/plugin/util/extensionsUtils.kt index f816f3e0160..32390ebe48e 100644 --- a/idea/ide-common/src/org/jetbrains/jet/plugin/util/extensionsUtils.kt +++ b/idea/ide-common/src/org/jetbrains/jet/plugin/util/extensionsUtils.kt @@ -23,7 +23,6 @@ import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.jet.lang.resolve.scopes.JetScope import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor import org.jetbrains.jet.lang.resolve.calls.smartcasts.SmartCastUtils -import org.jetbrains.jet.lang.types.TypeUtils import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor public enum class CallType { @@ -79,7 +78,7 @@ public fun CallableDescriptor.substituteExtensionIfCallable( .map { var substitutor = extensionReceiverType.checkIsSuperTypeOf(it) // check if we may fail due to receiver expression being nullable - if (substitutor == null && TypeUtils.isNullableType(it) && !TypeUtils.isNullableType(extensionReceiverType.type)) { + if (substitutor == null && it.nullability() == TypeNullability.NULLABLE && extensionReceiverType.nullability() == TypeNullability.NOT_NULL) { substitutor = extensionReceiverType.checkIsSuperTypeOf(it.makeNotNullable()) } substitutor diff --git a/idea/src/org/jetbrains/jet/plugin/completion/LookupElementFactory.kt b/idea/src/org/jetbrains/jet/plugin/completion/LookupElementFactory.kt index ee7ad00b6a4..b8209b2e580 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/LookupElementFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/LookupElementFactory.kt @@ -38,6 +38,8 @@ import org.jetbrains.jet.plugin.caches.resolve.ResolutionFacade import com.intellij.codeInsight.lookup.DefaultLookupItemRenderer import org.jetbrains.jet.lang.types.TypeUtils import com.intellij.codeInsight.lookup.impl.LookupCellRenderer +import org.jetbrains.jet.plugin.util.nullability +import org.jetbrains.jet.plugin.util.TypeNullability public class LookupElementFactory( private val receiverTypes: Collection @@ -207,12 +209,12 @@ public class LookupElementFactory( private fun callableWeight(descriptor: DeclarationDescriptor): CallableWeight? { if (descriptor !is CallableDescriptor) return null - val isReceiverNullable = receiverTypes.isNotEmpty() && receiverTypes.all { it.isMarkedNullable() } + val isReceiverNullable = receiverTypes.isNotEmpty() && receiverTypes.all { it.nullability() == TypeNullability.NULLABLE } val receiverParameter = descriptor.getExtensionReceiverParameter() if (receiverParameter != null) { val receiverParamType = receiverParameter.getType() - return if (isReceiverNullable && !receiverParamType.isMarkedNullable()) + return if (isReceiverNullable && receiverParamType.nullability() == TypeNullability.NOT_NULL) CallableWeight.notApplicableReceiverNullable else if (receiverTypes.any { TypeUtils.equalTypes(it, receiverParamType) }) CallableWeight.thisTypeExtension diff --git a/idea/src/org/jetbrains/jet/plugin/completion/smart/Utils.kt b/idea/src/org/jetbrains/jet/plugin/completion/smart/Utils.kt index e6d6b49e48e..06367592d6a 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/smart/Utils.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/smart/Utils.kt @@ -41,8 +41,9 @@ import org.jetbrains.jet.lang.types.TypeSubstitutor import java.util.ArrayList import java.util.HashMap import org.jetbrains.jet.plugin.util.FuzzyType -import org.jetbrains.jet.plugin.util.isNullable import org.jetbrains.jet.plugin.util.makeNotNullable +import org.jetbrains.jet.plugin.util.nullability +import org.jetbrains.jet.plugin.util.TypeNullability class ArtificialElementInsertHandler( val textBeforeCaret: String, val textAfterCaret: String, val shortenRefs: Boolean) : InsertHandler{ @@ -117,7 +118,7 @@ fun Collection.classifyExpectedInfo(expectedInfo: ExpectedInfo): Expe return ExpectedInfoClassification.matches(substitutor) } - if (stream.any { it.isNullable() }) { + if (stream.any { it.nullability() == TypeNullability.NULLABLE }) { val substitutor2 = stream.map { it.makeNotNullable().checkIsSubtypeOf(expectedInfo.type) }.firstOrNull() if (substitutor2 != null) { return ExpectedInfoClassification.matchesIfNotNullable(substitutor2)