Relax rules about inferring to Nothing for special calls

#KT-37388 Fixed
 #KT-38427 Fixed
 #KT-39953 Fixed
 #KT-38899 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2020-07-15 10:59:10 +03:00
parent e45cd02b01
commit 100a6f70ca
55 changed files with 424 additions and 264 deletions
@@ -178,7 +178,9 @@ class DiagnosticReporterByTrackingStrategy(
ArgumentTypeMismatchDiagnostic::class.java -> {
require(diagnostic is ArgumentTypeMismatchDiagnostic)
val expression = callArgument.safeAs<PSIKotlinCallArgument>()?.valueArgument?.getArgumentExpression()
val expression = callArgument.safeAs<PSIKotlinCallArgument>()?.valueArgument?.getArgumentExpression()?.let {
KtPsiUtil.deparenthesize(it) ?: it
}
if (expression != null) {
if (expression.isNull() && expression is KtConstantExpression) {
trace.reportDiagnosticOnce(NULL_FOR_NONNULL_TYPE.on(expression, diagnostic.expectedType))
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.util.javaslang.*
import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize
import java.util.*
@@ -302,9 +303,25 @@ internal class DataFlowInfoImpl private constructor(
when {
this == null -> other ?: ImmutableLinkedHashSet.empty()
other == null -> this
else -> this.intersect(other)
else -> {
// Here we cover the case when "this" has T?!! type and "other" has T
val thisApproximated = approximateDefinitelyNotNullableTypes(this)
val otherApproximated = approximateDefinitelyNotNullableTypes(other)
if (thisApproximated == null && otherApproximated == null ||
thisApproximated != null && otherApproximated != null
) {
this.intersect(other)
} else {
(thisApproximated ?: this).intersect(otherApproximated ?: other)
}
}
}
private fun approximateDefinitelyNotNullableTypes(set: ImmutableSet<KotlinType>): ImmutableSet<KotlinType>? {
if (!set.any { it.isDefinitelyNotNullType }) return null
return set.map { if (it is DefinitelyNotNullType) it.original.makeNotNullable() else it }
}
override fun or(other: DataFlowInfo): DataFlowInfo {
if (other === DataFlowInfo.EMPTY) return DataFlowInfo.EMPTY
if (this === DataFlowInfo.EMPTY) return DataFlowInfo.EMPTY
@@ -177,8 +177,7 @@ public class ControlStructureTypingUtils {
@NotNull KotlinType expectedType,
@NotNull LanguageVersionSettings languageVersionSettings
) {
if (languageVersionSettings.supportsFeature(LanguageFeature.NewInference)
|| construct == ResolveConstruct.ELVIS
if (construct == ResolveConstruct.ELVIS
|| TypeUtils.noExpectedType(expectedType)
|| TypeUtils.isDontCarePlaceholder(expectedType)
|| KotlinBuiltIns.isUnitOrNullableUnit(expectedType)