From 8e10b5fdecdd6eec4a8f1c55d440650637df0ef6 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Thu, 29 Apr 2021 23:50:22 -0700 Subject: [PATCH] FIR: introduce FirExpressionWithSmartcastToNull This new kind of expression encompasses the nullability of the original expression after null check (or equivalent `is Nothing?` check). Unlike FirExpressionWithSmartcast, this expression won't be materialized during conversion to backend IR. Also, Nothing? is discarded when computing the intersection of possible types from smartcast info. In that way, Nothing? is not used during resolution, while such smartcast info is stored in it (and the expression kind itself). --- .../analysis/cfa/FirReturnsImpliesAnalyzer.kt | 7 +- .../fir/backend/Fir2IrImplicitCastInserter.kt | 8 ++ .../kotlin/fir/backend/Fir2IrVisitor.kt | 8 ++ .../kotlin/fir/resolve/ResolveUtils.kt | 29 +++++- .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 13 ++- .../jetbrains/kotlin/fir/resolve/dfa/util.kt | 11 ++- .../FirDeclarationsResolveTransformer.kt | 3 +- .../contracts/ConeEffectExtractor.kt | 9 +- .../FirExpressionWithSmartcastToNull.kt | 63 +++++++++++++ .../kotlin/fir/visitors/FirTransformer.kt | 9 ++ .../kotlin/fir/visitors/FirVisitor.kt | 3 + .../kotlin/fir/visitors/FirVisitorVoid.kt | 9 ++ ...FirExpressionWithSmartcastToNullBuilder.kt | 26 ++++++ .../FirExpressionWithSmartcastToNullImpl.kt | 88 +++++++++++++++++++ .../fir/tree/generator/FirTreeBuilder.kt | 1 + .../generator/ImplementationConfigurator.kt | 1 + .../fir/tree/generator/NodeConfigurator.kt | 6 ++ ...rtcastToNothingAfterCheckingForNull.fir.kt | 2 +- .../contracts/smartcasts/throwsEffect.fir.kt | 2 +- .../analysis/smartcasts/pos/8.fir.kt | 4 +- .../diagnostics/notLinked/dfa/neg/1.fir.kt | 28 +++--- .../diagnostics/notLinked/dfa/neg/16.fir.kt | 8 +- .../diagnostics/notLinked/dfa/neg/2.fir.kt | 16 ++-- .../diagnostics/notLinked/dfa/neg/29.fir.kt | 4 +- .../diagnostics/notLinked/dfa/neg/33.fir.kt | 8 +- .../diagnostics/notLinked/dfa/neg/38.fir.kt | 12 +-- .../diagnostics/notLinked/dfa/neg/39.fir.kt | 4 +- .../diagnostics/notLinked/dfa/neg/45.fir.kt | 2 +- .../diagnostics/notLinked/dfa/pos/1.fir.kt | 2 +- .../diagnostics/notLinked/dfa/pos/2.fir.kt | 2 +- .../diagnostics/notLinked/dfa/pos/3.fir.kt | 32 +++---- .../diagnostics/notLinked/dfa/pos/4.fir.kt | 30 +++---- .../diagnostics/notLinked/dfa/pos/40.fir.kt | 8 +- .../diagnostics/notLinked/dfa/pos/68.fir.kt | 8 +- .../diagnostics/notLinked/dfa/pos/7.fir.kt | 4 +- .../diagnostics/notLinked/dfa/pos/70.fir.kt | 4 +- 36 files changed, 370 insertions(+), 104 deletions(-) create mode 100644 compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirExpressionWithSmartcastToNull.kt create mode 100644 compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirExpressionWithSmartcastToNullBuilder.kt create mode 100644 compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirExpressionWithSmartcastToNullImpl.kt diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt index 5b1a821867c..53cc228d7ff 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirReturnsImpliesAnalyzer.kt @@ -27,10 +27,7 @@ import org.jetbrains.kotlin.fir.resolve.dfa.cfg.JumpNode import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertyAccessorSymbol import org.jetbrains.kotlin.fir.typeContext -import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.fir.types.coneType -import org.jetbrains.kotlin.fir.types.intersectTypesOrNull -import org.jetbrains.kotlin.fir.types.isNullable +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.ConstantValueKind import org.jetbrains.kotlin.utils.addIfNotNull @@ -56,7 +53,7 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() { throw IllegalStateException("Update of all receivers is not possible for this logic system") override fun ConeKotlinType.isAcceptableForSmartcast(): Boolean { - return true + return !isNullableNothing } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt index cb39e86be00..ebe7c9e559f 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt @@ -277,6 +277,14 @@ class Fir2IrImplicitCastInserter( return implicitCastOrExpression(data as IrExpression, expressionWithSmartcast.typeRef) } + override fun visitExpressionWithSmartcastToNull( + expressionWithSmartcastToNull: FirExpressionWithSmartcastToNull, + data: IrElement + ): IrElement { + // We don't want an implicit cast to Nothing?. This expression just encompasses nullability after null check. + return data + } + internal fun implicitCastFromDispatchReceiver( original: IrExpression, originalTypeRef: FirTypeRef, diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index c6c2384e2f1..c62983eff3c 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -420,6 +420,14 @@ class Fir2IrVisitor( return implicitCastInserter.visitExpressionWithSmartcast(expressionWithSmartcast, value) } + override fun visitExpressionWithSmartcastToNull( + expressionWithSmartcastToNull: FirExpressionWithSmartcastToNull, + data: Any? + ): IrElement { + // This should not be materialized. Generate the expression with the original expression. + return convertToIrExpression(expressionWithSmartcastToNull.originalExpression) + } + override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: Any?): IrElement { val explicitReceiverExpression = convertToIrReceiverExpression( callableReferenceAccess.explicitReceiver, callableReferenceAccess.calleeReference, callableReferenceAccess diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index 98ec4b43de3..e510e28564f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -247,9 +247,35 @@ private fun BodyResolveComponents.typeFromSymbol(symbol: AbstractFirBasedSymbol< } } -fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo(qualifiedAccessExpression: FirQualifiedAccessExpression): FirQualifiedAccessExpression { +fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo( + qualifiedAccessExpression: FirQualifiedAccessExpression +): FirQualifiedAccessExpression { val typesFromSmartCast = dataFlowAnalyzer.getTypeUsingSmartcastInfo(qualifiedAccessExpression) ?: return qualifiedAccessExpression val originalType = qualifiedAccessExpression.resultType.coneType + // For example, if (x == null) { ... }, + // we don't want to smartcast to Nothing?, but we want to record the nullability to its own kind of node. + // TODO: should we differentiate x == null v.s. x is Nothing? + if (typesFromSmartCast.any { it.isNullableNothing }) { + val typesFromSmartcastWithoutNullableNothing = + typesFromSmartCast.filterTo(mutableListOf()) { !it.isNullableNothing }.also { + it += originalType + } + val intersectedTypeWithoutNullableNothing = + ConeTypeIntersector.intersectTypes(session.inferenceComponents.ctx, typesFromSmartcastWithoutNullableNothing) + val intersectedTypeRefWithoutNullableNothing = buildResolvedTypeRef { + source = qualifiedAccessExpression.resultType.source?.fakeElement(FirFakeSourceElementKind.SmartCastedTypeRef) + type = intersectedTypeWithoutNullableNothing + annotations += qualifiedAccessExpression.resultType.annotations + delegatedTypeRef = qualifiedAccessExpression.resultType + } + return buildExpressionWithSmartcastToNull { + originalExpression = qualifiedAccessExpression + // TODO: Use Nothing? during resolution? + typeRef = intersectedTypeRefWithoutNullableNothing + // NB: Nothing? in types from smartcast in DFA is recorded here (and the expression kind itself). + this.typesFromSmartCast = typesFromSmartCast + } + } val allTypes = typesFromSmartCast.also { it += originalType } @@ -259,6 +285,7 @@ fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo(qualifiedAc source = qualifiedAccessExpression.resultType.source?.fakeElement(FirFakeSourceElementKind.SmartCastedTypeRef) type = intersectedType annotations += qualifiedAccessExpression.resultType.annotations + delegatedTypeRef = qualifiedAccessExpression.resultType } return buildExpressionWithSmartcast { originalExpression = qualifiedAccessExpression diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index 7ddc401ef6e..36f0592df6a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -119,9 +119,11 @@ abstract class FirDataFlowAnalyzer( } override fun ConeKotlinType.isAcceptableForSmartcast(): Boolean { + if (this.isNullableNothing) return false return when (this) { is ConeClassLikeType -> { - val symbol = fullyExpandedType(components.session).lookupTag.toSymbol(components.session) ?: return false + val symbol = + fullyExpandedType(components.session).lookupTag.toSymbol(components.session) ?: return false val declaration = symbol.fir as? FirRegularClass ?: return true visibilityChecker.isVisible( declaration, @@ -545,9 +547,12 @@ abstract class FirDataFlowAnalyzer( flow.addImplication((expressionVariable notEq isEq) implies (operandVariable typeEq any)) } -// TODO: design do we need casts to Nothing? -// flow.addImplication((expressionVariable eq !isEq) implies (operandVariable typeEq nullableNothing)) -// flow.addImplication((expressionVariable notEq !isEq) implies (operandVariable typeNotEq nullableNothing)) + if (shouldAddImplicationForStatement(expressionVariable eq !isEq)) { + flow.addImplication((expressionVariable eq !isEq) implies (operandVariable typeNotEq nullableNothing)) + } + if (shouldAddImplicationForStatement(expressionVariable notEq !isEq)) { + flow.addImplication((expressionVariable notEq !isEq) implies (operandVariable typeEq nullableNothing)) + } } node.flow = flow } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/util.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/util.kt index 7c763a21042..e203d07b79f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/util.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/util.kt @@ -99,7 +99,10 @@ internal val FirElement.symbol: AbstractFirBasedSymbol<*>? is FirWhenSubjectExpression -> whenRef.value.subject?.symbol is FirSafeCallExpression -> regularQualifiedAccess.symbol else -> null - }?.takeIf { this.unwrapSmartcastExpression() is FirThisReceiverExpression || (it !is FirFunctionSymbol<*> && it !is FirAccessorSymbol) } + }?.takeIf { + (this as? FirExpression)?.unwrapSmartcastExpression() is FirThisReceiverExpression || + (it !is FirFunctionSymbol<*> && it !is FirAccessorSymbol) + } @DfaInternals internal val FirResolvable.symbol: AbstractFirBasedSymbol<*>? @@ -110,4 +113,8 @@ internal val FirResolvable.symbol: AbstractFirBasedSymbol<*>? else -> null } -private fun FirElement.unwrapSmartcastExpression(): FirElement = if (this is FirExpressionWithSmartcast) originalExpression else this +internal fun FirExpression.unwrapSmartcastExpression(): FirExpression = + when (this) { + is FirExpressionWithSmartcast -> originalExpression + else -> this + } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index 068b81c8ff8..2224ea86e21 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate import org.jetbrains.kotlin.fir.resolve.dfa.FirControlFlowGraphReferenceImpl +import org.jetbrains.kotlin.fir.resolve.dfa.unwrapSmartcastExpression import org.jetbrains.kotlin.fir.resolve.inference.extractLambdaInfoFromFunctionalType import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor @@ -793,7 +794,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor if (variable.returnTypeRef is FirImplicitTypeRef) { val resultType = when { initializer != null -> { - val unwrappedInitializer = (initializer as? FirExpressionWithSmartcast)?.originalExpression ?: initializer + val unwrappedInitializer = initializer.unwrapSmartcastExpression() unwrappedInitializer.resultType } variable.getter != null && variable.getter !is FirDefaultPropertyAccessor -> variable.getter?.returnTypeRef diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/ConeEffectExtractor.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/ConeEffectExtractor.kt index 2f97eb2805c..c90d8318c2c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/ConeEffectExtractor.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/contracts/ConeEffectExtractor.kt @@ -118,6 +118,13 @@ class ConeEffectExtractor( return expressionWithSmartcast.originalExpression.accept(this, data) } + override fun visitExpressionWithSmartcastToNull( + expressionWithSmartcastToNull: FirExpressionWithSmartcastToNull, + data: Nothing? + ): ConeContractDescriptionElement? { + return expressionWithSmartcastToNull.originalExpression.accept(this, data) + } + override fun visitQualifiedAccessExpression( qualifiedAccessExpression: FirQualifiedAccessExpression, data: Nothing? @@ -189,4 +196,4 @@ class ConeEffectExtractor( else -> null } } -} \ No newline at end of file +} diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirExpressionWithSmartcastToNull.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirExpressionWithSmartcastToNull.kt new file mode 100644 index 00000000000..3e643586063 --- /dev/null +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirExpressionWithSmartcastToNull.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.expressions + +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirSourceElement +import org.jetbrains.kotlin.fir.references.FirReference +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.FirTypeProjection +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.visitors.* +import org.jetbrains.kotlin.fir.FirImplementationDetail + +/* + * This file was generated automatically + * DO NOT MODIFY IT MANUALLY + */ + +abstract class FirExpressionWithSmartcastToNull : FirExpressionWithSmartcast() { + abstract override val source: FirSourceElement? + abstract override val typeRef: FirTypeRef + abstract override val annotations: List + abstract override val calleeReference: FirReference + abstract override val typeArguments: List + abstract override val explicitReceiver: FirExpression? + abstract override val dispatchReceiver: FirExpression + abstract override val extensionReceiver: FirExpression + abstract override val originalExpression: FirQualifiedAccessExpression + abstract override val typesFromSmartCast: Collection + abstract override val originalType: FirTypeRef + + override fun accept(visitor: FirVisitor, data: D): R = visitor.visitExpressionWithSmartcastToNull(this, data) + + @Suppress("UNCHECKED_CAST") + override fun transform(transformer: FirTransformer, data: D): E = + transformer.transformExpressionWithSmartcastToNull(this, data) as E + + @FirImplementationDetail + abstract override fun replaceSource(newSource: FirSourceElement?) + + abstract override fun replaceTypeRef(newTypeRef: FirTypeRef) + + abstract override fun replaceCalleeReference(newCalleeReference: FirReference) + + abstract override fun replaceTypeArguments(newTypeArguments: List) + + abstract override fun replaceExplicitReceiver(newExplicitReceiver: FirExpression?) + + abstract override fun transformAnnotations(transformer: FirTransformer, data: D): FirExpressionWithSmartcastToNull + + abstract override fun transformCalleeReference(transformer: FirTransformer, data: D): FirExpressionWithSmartcastToNull + + abstract override fun transformTypeArguments(transformer: FirTransformer, data: D): FirExpressionWithSmartcastToNull + + abstract override fun transformExplicitReceiver(transformer: FirTransformer, data: D): FirExpressionWithSmartcastToNull + + abstract override fun transformDispatchReceiver(transformer: FirTransformer, data: D): FirExpressionWithSmartcastToNull + + abstract override fun transformExtensionReceiver(transformer: FirTransformer, data: D): FirExpressionWithSmartcastToNull +} diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirTransformer.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirTransformer.kt index dd9216418e5..5785f82fda7 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirTransformer.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirTransformer.kt @@ -91,6 +91,7 @@ import org.jetbrains.kotlin.fir.expressions.FirComponentCall import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast +import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcastToNull import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression import org.jetbrains.kotlin.fir.expressions.FirCheckedSafeCallSubject import org.jetbrains.kotlin.fir.expressions.FirGetClassCall @@ -480,6 +481,10 @@ abstract class FirTransformer : FirVisitor() { return transformElement(expressionWithSmartcast, data) } + open fun transformExpressionWithSmartcastToNull(expressionWithSmartcastToNull: FirExpressionWithSmartcastToNull, data: D): FirStatement { + return transformElement(expressionWithSmartcastToNull, data) + } + open fun transformSafeCallExpression(safeCallExpression: FirSafeCallExpression, data: D): FirStatement { return transformElement(safeCallExpression, data) } @@ -980,6 +985,10 @@ abstract class FirTransformer : FirVisitor() { return transformExpressionWithSmartcast(expressionWithSmartcast, data) } + final override fun visitExpressionWithSmartcastToNull(expressionWithSmartcastToNull: FirExpressionWithSmartcastToNull, data: D): FirStatement { + return transformExpressionWithSmartcastToNull(expressionWithSmartcastToNull, data) + } + final override fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression, data: D): FirStatement { return transformSafeCallExpression(safeCallExpression, data) } diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitor.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitor.kt index d64174b776c..3749d283c7a 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitor.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitor.kt @@ -91,6 +91,7 @@ import org.jetbrains.kotlin.fir.expressions.FirComponentCall import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast +import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcastToNull import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression import org.jetbrains.kotlin.fir.expressions.FirCheckedSafeCallSubject import org.jetbrains.kotlin.fir.expressions.FirGetClassCall @@ -309,6 +310,8 @@ abstract class FirVisitor { open fun visitExpressionWithSmartcast(expressionWithSmartcast: FirExpressionWithSmartcast, data: D): R = visitElement(expressionWithSmartcast, data) + open fun visitExpressionWithSmartcastToNull(expressionWithSmartcastToNull: FirExpressionWithSmartcastToNull, data: D): R = visitElement(expressionWithSmartcastToNull, data) + open fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression, data: D): R = visitElement(safeCallExpression, data) open fun visitCheckedSafeCallSubject(checkedSafeCallSubject: FirCheckedSafeCallSubject, data: D): R = visitElement(checkedSafeCallSubject, data) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitorVoid.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitorVoid.kt index 7996a04e254..d424151e70d 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitorVoid.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/visitors/FirVisitorVoid.kt @@ -91,6 +91,7 @@ import org.jetbrains.kotlin.fir.expressions.FirComponentCall import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast +import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcastToNull import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression import org.jetbrains.kotlin.fir.expressions.FirCheckedSafeCallSubject import org.jetbrains.kotlin.fir.expressions.FirGetClassCall @@ -479,6 +480,10 @@ abstract class FirVisitorVoid : FirVisitor() { visitElement(expressionWithSmartcast) } + open fun visitExpressionWithSmartcastToNull(expressionWithSmartcastToNull: FirExpressionWithSmartcastToNull) { + visitElement(expressionWithSmartcastToNull) + } + open fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression) { visitElement(safeCallExpression) } @@ -979,6 +984,10 @@ abstract class FirVisitorVoid : FirVisitor() { visitExpressionWithSmartcast(expressionWithSmartcast) } + final override fun visitExpressionWithSmartcastToNull(expressionWithSmartcastToNull: FirExpressionWithSmartcastToNull, data: Nothing?) { + visitExpressionWithSmartcastToNull(expressionWithSmartcastToNull) + } + final override fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression, data: Nothing?) { visitSafeCallExpression(safeCallExpression) } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirExpressionWithSmartcastToNullBuilder.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirExpressionWithSmartcastToNullBuilder.kt new file mode 100644 index 00000000000..b639f24c92d --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/builder/FirExpressionWithSmartcastToNullBuilder.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.expressions.builder + +import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcastToNull +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression +import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionWithSmartcastToNullImpl +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.FirTypeRef + +class FirExpressionWithSmartcastToNullBuilder { + lateinit var originalExpression: FirQualifiedAccessExpression + lateinit var typeRef: FirTypeRef + lateinit var typesFromSmartCast: Collection + + fun build(): FirExpressionWithSmartcastToNull { + return FirExpressionWithSmartcastToNullImpl(originalExpression, typeRef, typesFromSmartCast) + } +} + +inline fun buildExpressionWithSmartcastToNull(init: FirExpressionWithSmartcastToNullBuilder.() -> Unit): FirExpressionWithSmartcastToNull { + return FirExpressionWithSmartcastToNullBuilder().apply(init).build() +} diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirExpressionWithSmartcastToNullImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirExpressionWithSmartcastToNullImpl.kt new file mode 100644 index 00000000000..117b4c8702b --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirExpressionWithSmartcastToNullImpl.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.expressions.impl + +import org.jetbrains.kotlin.fir.FirImplementationDetail +import org.jetbrains.kotlin.fir.FirSourceElement +import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.references.FirReference +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import org.jetbrains.kotlin.fir.types.FirTypeProjection +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.visitors.FirTransformer +import org.jetbrains.kotlin.fir.visitors.FirVisitor +import org.jetbrains.kotlin.fir.visitors.transformSingle + +class FirExpressionWithSmartcastToNullImpl( + override var originalExpression: FirQualifiedAccessExpression, + override val typeRef: FirTypeRef, + override val typesFromSmartCast: Collection +) : FirExpressionWithSmartcastToNull() { + init { + assert(originalExpression.typeRef is FirResolvedTypeRef) + } + + override val source: FirSourceElement? get() = originalExpression.source + override val annotations: List get() = originalExpression.annotations + override val typeArguments: List get() = originalExpression.typeArguments + override val explicitReceiver: FirExpression? get() = originalExpression.explicitReceiver + override val dispatchReceiver: FirExpression get() = originalExpression.dispatchReceiver + override val extensionReceiver: FirExpression get() = originalExpression.extensionReceiver + override val calleeReference: FirReference get() = originalExpression.calleeReference + override val originalType: FirTypeRef get() = originalExpression.typeRef + + override fun transformChildren(transformer: FirTransformer, data: D): FirExpressionWithSmartcastToNull { + originalExpression = originalExpression.transformSingle(transformer, data) + return this + } + + override fun acceptChildren(visitor: FirVisitor, data: D) { + originalExpression.accept(visitor, data) + } + + override fun transformCalleeReference(transformer: FirTransformer, data: D): FirExpressionWithSmartcastToNull { + throw IllegalStateException() + } + + override fun transformExplicitReceiver(transformer: FirTransformer, data: D): FirExpressionWithSmartcastToNull { + throw IllegalStateException() + } + + override fun transformDispatchReceiver(transformer: FirTransformer, data: D): FirExpressionWithSmartcastToNull { + throw IllegalStateException() + } + + override fun transformExtensionReceiver(transformer: FirTransformer, data: D): FirExpressionWithSmartcastToNull { + throw IllegalStateException() + } + + override fun transformTypeArguments(transformer: FirTransformer, data: D): FirExpressionWithSmartcastToNull { + throw IllegalStateException() + } + + override fun transformAnnotations(transformer: FirTransformer, data: D): FirExpressionWithSmartcastToNull { + throw IllegalStateException() + } + + override fun replaceTypeArguments(newTypeArguments: List) { + throw IllegalStateException() + } + + override fun replaceCalleeReference(newCalleeReference: FirReference) { + throw IllegalStateException() + } + + override fun replaceExplicitReceiver(newExplicitReceiver: FirExpression?) { + throw IllegalStateException() + } + + override fun replaceTypeRef(newTypeRef: FirTypeRef) {} + + @FirImplementationDetail + override fun replaceSource(newSource: FirSourceElement?) { + } +} diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt index 33f36619765..7284f5db49d 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt @@ -108,6 +108,7 @@ object FirTreeBuilder : AbstractFirTreeBuilder() { val callableReferenceAccess = element("CallableReferenceAccess", Expression, qualifiedAccessExpression) val thisReceiverExpression = element("ThisReceiverExpression", Expression, qualifiedAccessExpression) val expressionWithSmartcast = element("ExpressionWithSmartcast", Expression, qualifiedAccessExpression) + val expressionWithSmartcastToNull = element("ExpressionWithSmartcastToNull", Expression, expressionWithSmartcast) val safeCallExpression = element("SafeCallExpression", Expression, expression) val checkedSafeCallSubject = element("CheckedSafeCallSubject", Expression, expression) val getClassCall = element("GetClassCall", Expression, expression, call) diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt index e0df248bf6a..7681915f965 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt @@ -156,6 +156,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() impl(qualifiedAccessExpression) noImpl(expressionWithSmartcast) + noImpl(expressionWithSmartcastToNull) impl(getClassCall) { default("argument") { diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt index f859ef8aab3..4f637700029 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt @@ -459,6 +459,12 @@ object NodeConfigurator : AbstractFieldConfigurator(FirTreeBuild +field("originalType", typeRef) } + expressionWithSmartcastToNull.configure { + +field("originalExpression", qualifiedAccessExpression) + +field("typesFromSmartCast", "Collection", null, customType = coneKotlinTypeType) + +field("originalType", typeRef) + } + safeCallExpression.configure { +field("receiver", expression).withTransform() // Special node that might be used as a reference to receiver of a safe call after null check diff --git a/compiler/testData/diagnostics/tests/smartCasts/smartcastToNothingAfterCheckingForNull.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/smartcastToNothingAfterCheckingForNull.fir.kt index 3c61a09af0b..99d461442fa 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/smartcastToNothingAfterCheckingForNull.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/smartcastToNothingAfterCheckingForNull.fir.kt @@ -24,6 +24,6 @@ fun g(x: B) { if (y is Nothing?) { f(y) - g(y) + g(y) } } diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/throwsEffect.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/throwsEffect.fir.kt index 219ab26035a..745a7da6705 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/throwsEffect.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/smartcasts/throwsEffect.fir.kt @@ -26,7 +26,7 @@ fun testSpilling(x: Any?) { myAssert(x is String) x.length } - x.length + x.length } fun testAssertInIf(x: Any?) { diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/pos/8.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/pos/8.fir.kt index f5870d06e5f..727ad27b035 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/pos/8.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/analysis/smartcasts/pos/8.fir.kt @@ -20,11 +20,11 @@ fun T?.case_3(value_1: Int?, value_2: Boolean): Boolean { // TESTCASE NUMBER: 4 fun case_4(value_1: Number, block: (() -> Unit)?): Boolean? { - contract { + contract { returns(true) implies (value_1 is Int) returns(false) implies (block == null) returns(null) implies (block != null) - } + } return value_1 == null } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/1.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/1.fir.kt index 1cfd84548ef..5bd13b398fc 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/1.fir.kt @@ -87,7 +87,7 @@ fun case_6(x: EmptyClass?) { // TESTCASE NUMBER: 7 fun case_7() { - if (nullableNumberProperty != null || nullableNumberProperty != null is Boolean) { + if (nullableNumberProperty != null || nullableNumberProperty != null is Boolean) { nullableNumberProperty nullableNumberProperty.equals(null) nullableNumberProperty.propT @@ -262,8 +262,8 @@ fun case_16() { // TESTCASE NUMBER: 17 val case_17 = if (nullableIntProperty == null == true == false) 0 else { - nullableIntProperty - nullableIntProperty.java + nullableIntProperty + nullableIntProperty.java } //TESTCASE NUMBER: 18 @@ -440,18 +440,18 @@ fun case_25(b: Boolean) { // TESTCASE NUMBER: 26 fun case_26(a: ((Float) -> Int?)?, b: Float?) { if (a != null == true == false && b != null == true == false) { - val x = a(b) + val x = a(b) if (x != null == true === false) { - x - x.equals(null) - x.propT - x.propAny - x.propNullableT - x.propNullableAny - x.funT() - x.funAny() - x.funNullableT() - x.funNullableAny() + x + x.equals(null) + x.propT + x.propAny + x.propNullableT + x.propNullableAny + x.funT() + x.funAny() + x.funNullableT() + x.funNullableAny() } } } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/16.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/16.fir.kt index a2221158e07..c1789a86e4a 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/16.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/16.fir.kt @@ -18,8 +18,8 @@ fun case_1(x: ClassWithCustomEquals) { // TESTCASE NUMBER: 2 fun case_2(x: ClassWithCustomEquals) { if (x == null) { - x - x.inv() + x + x.inv() } } @@ -76,8 +76,8 @@ fun case_6(x: ClassWithCustomEquals) { // TESTCASE NUMBER: 7 fun case_7(x: ClassWithCustomEquals) { if ((x != null) == false) { - x - x.inv() + x + x.inv() } } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/2.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/2.fir.kt index e03dfe54da5..39807322f91 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/2.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/2.fir.kt @@ -37,8 +37,8 @@ fun case_4(x: Any) { // TESTCASE NUMBER: 5 fun case_5(x: Any?) { if (!(x !is Nothing?)) { - x - x?.inv() + x + x?.inv() } } @@ -61,16 +61,16 @@ fun case_7(x: Any) { // TESTCASE NUMBER: 8 fun case_8(x: Any?) { if (!(x is Nothing?)) else { - x - x?.inv() + x + x?.inv() } } // TESTCASE NUMBER: 9 fun case_9(x: Any?) { if (!!(x !is Nothing?)) else { - x - x?.inv() + x + x?.inv() } } @@ -85,7 +85,7 @@ fun case_10(x: Any?) { // TESTCASE NUMBER: 11 fun case_11(x: Any?) { if (x is Nothing?) { - x - x?.inv() + x + x?.inv() } } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/29.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/29.fir.kt index 1f32dd0cb51..13e674b4c5e 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/29.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/29.fir.kt @@ -9,8 +9,8 @@ fun case_1(a: Any?) { if (true) continue } - a - a.equals(10) + a + a.equals(10) } // TESTCASE NUMBER: 2 diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/33.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/33.fir.kt index 0cb3d4cbb07..fa890f0a159 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/33.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/33.fir.kt @@ -12,7 +12,7 @@ fun nullableStringArg(number: String?) {} */ fun case_1(x: Int?) { if (x == null) { - nullableStringArg(x) + nullableStringArg(x) } } @@ -34,7 +34,7 @@ fun case_2(x: Int?, y: Nothing?) { */ fun case_3(x: Int?) { if (x == null) { - nullableStringArg(x) + nullableStringArg(x) } } @@ -45,7 +45,7 @@ fun case_3(x: Int?) { */ fun case_4(x: Int?) { if (x == null) { - nullableStringArg(x) + nullableStringArg(x) } } @@ -57,6 +57,6 @@ fun case_4(x: Int?) { fun case_5(x: Int?) { if (x == null) { var y = x - nullableStringArg(y) + nullableStringArg(y) } } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/38.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/38.fir.kt index 310fcb05941..1df5b95afd5 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/38.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/38.fir.kt @@ -15,8 +15,8 @@ fun case_1() { break@outer } } - x - x.length + x + x.length } /* @@ -32,8 +32,8 @@ fun case_2() { break@outer } } - x - x.length + x + x.length } /* @@ -145,8 +145,8 @@ fun case_9() { inner@ do { x = null } while (x != null) - x - x.length + x + x.length } } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/39.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/39.fir.kt index 56737b0323d..7a57b8a3cfb 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/39.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/39.fir.kt @@ -151,8 +151,8 @@ fun case_12() { while (true) { y += if (x == null) break else 10 } - x - x.inv() + x + x.inv() } // TESTCASE NUMBER: 13 diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/45.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/45.fir.kt index c2eca5ea7b3..ab7a6254b79 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/45.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/45.fir.kt @@ -17,5 +17,5 @@ fun case_1(x: Number?): Long? { * ISSUES: KT-22997 */ fun case_2(x: Number?): Long? { - if (x == null || x is Long) return x else return 0L + if (x == null || x is Long) return x else return 0L } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/1.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/1.fir.kt index 31b1bb2a01f..f3d63fbc9c5 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/1.fir.kt @@ -122,7 +122,7 @@ fun case_6(x: EmptyClass?) { // TESTCASE NUMBER: 7 fun case_7() { - if (nullableNumberProperty != null || nullableNumberProperty != null) { + if (nullableNumberProperty != null || nullableNumberProperty != null) { nullableNumberProperty nullableNumberProperty.equals(null) nullableNumberProperty.propT diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/2.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/2.fir.kt index 8f5762dbd85..0817a8c0c67 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/2.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/2.fir.kt @@ -288,7 +288,7 @@ fun case_11(b: Boolean) { if (z != null || b) { } else { - ?")!>z + ? & ?")!>z } } } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/3.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/3.fir.kt index 8ee33236b69..08b2302cb78 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/3.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/3.fir.kt @@ -16,14 +16,14 @@ import otherpackage.* // TESTCASE NUMBER: 1 fun case_1(x: Any?) { if (x == null) { - x + x } } // TESTCASE NUMBER: 2 fun case_2(x: Nothing?) { if (x == null) { - x + x } } @@ -38,7 +38,7 @@ fun case_3() { // TESTCASE NUMBER: 4 fun case_4(x: Char?) { if (x == null && true) { - x + x } } @@ -46,7 +46,7 @@ fun case_4(x: Char?) { fun case_5() { val x: Unit? = null - if (x == null) x + if (x == null) x } // TESTCASE NUMBER: 6 @@ -54,7 +54,7 @@ fun case_6(x: EmptyClass?) { val y = true if (x == null && !y) { - x + x } } @@ -67,8 +67,8 @@ fun case_7() { // TESTCASE NUMBER: 8 fun case_8(x: TypealiasNullableString) { - if (x == null && x == null) - x + if (x == null && x == null) + x } /* @@ -105,7 +105,7 @@ fun case_11(x: TypealiasNullableString?, y: TypealiasNullableString) { if (y == null) { if (nullableStringProperty != null) { if (z == null) { - x + x } } } @@ -172,7 +172,7 @@ fun case_14() { // TESTCASE NUMBER: 15 fun case_15(x: TypealiasNullableString) { val t = if (x != null) "" else { - x + x } } @@ -187,13 +187,13 @@ fun case_16() { // TESTCASE NUMBER: 17 val case_17 = if (nullableIntProperty !== null) 0 else { - nullableIntProperty + nullableIntProperty } //TESTCASE NUMBER: 18 fun case_18(a: DeepObject.A.B.C.D.E.F.G.J?) { if (a == null) { - a + a } } @@ -249,15 +249,15 @@ fun case_21() { // TESTCASE NUMBER: 22 fun case_22(a: (() -> Unit)?) { if (a == null) { - ?")!>a + ? & kotlin.Function0?")!>a } } // TESTCASE NUMBER: 23 fun case_23(a: ((Float) -> Int?)?, b: Float?) { if (a == null && b == null) { - ?")!>a - b + ? & kotlin.Function1?")!>a + b if (a != null) { ? & kotlin.Function1")!>a } @@ -290,13 +290,13 @@ fun case_25(b: Boolean) { val z = ?")!>y() if (z == null) { - ?")!>z + ? & ?")!>z } } } // TESTCASE NUMBER: 26 -fun case_26(a: Int?, b: Int? = if (a !== null) 0 else a) { +fun case_26(a: Int?, b: Int? = if (a !== null) 0 else a) { a b } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/4.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/4.fir.kt index 9d02e24f57a..d191413dbc5 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/4.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/4.fir.kt @@ -19,14 +19,14 @@ import otherpackage.* // TESTCASE NUMBER: 1 fun case_1(x: Any) { if (x === null) { - x + x } } // TESTCASE NUMBER: 2 fun case_2(x: Nothing) { if (x == null) { - x + x } } @@ -41,7 +41,7 @@ fun case_3() { // TESTCASE NUMBER: 4 fun case_4(x: Char) { if (x == null && true) { - x + x } } @@ -49,7 +49,7 @@ fun case_4(x: Char) { fun case_5() { val x: Unit = kotlin.Unit - if (x == null) x + if (x == null) x } // TESTCASE NUMBER: 6 @@ -57,7 +57,7 @@ fun case_6(x: EmptyClass) { val y = true if (x == null && !y) { - x + x } } @@ -70,7 +70,7 @@ fun case_7() { // TESTCASE NUMBER: 8 fun case_8(x: TypealiasString) { - if (x == null && x == null) x + if (x == null && x == null) x } // TESTCASE NUMBER: 9 @@ -78,7 +78,7 @@ fun case_9(x: TypealiasString) { if (x != null) { } else if (false) { - x + x } } @@ -103,7 +103,7 @@ fun case_11(x: TypealiasString, y: TypealiasString) { if (y == null) { if (stringProperty != null) { if (false || false || false || z == null || false) { - x + x } } } @@ -112,14 +112,14 @@ fun case_11(x: TypealiasString, y: TypealiasString) { // TESTCASE NUMBER: 12 fun case_12(x: TypealiasString, y: TypealiasString) = if (x != null) "1" - else if (y !== null) x + else if (y !== null) x else "-1" // TESTCASE NUMBER: 13 fun case_13(x: otherpackage.EmptyClass13) = if (x != null) { 1 - } else x + } else x // TESTCASE NUMBER: 14 class A14 { @@ -179,7 +179,7 @@ fun case_16() { val x: TypealiasNothing = return if (x == null) { - x + x } } @@ -195,7 +195,7 @@ val case_17 = if (true && true && in //TESTCASE NUMBER: 18 fun case_18(a: DeepObject.A.B.C.D.E.F.G.J) { if (a == null) { - a + a } } @@ -256,7 +256,7 @@ fun case_22(a: (() -> Unit)) { // TESTCASE NUMBER: 23 fun case_23(a: ((Float) -> Int), b: Float) { if (a == null && b == null) { - val x = a(b) + val x = a(b) if (x !== null) { x } @@ -276,13 +276,13 @@ fun case_24(a: ((() -> Unit) -> Unit), b: (() -> Unit)) { } // TESTCASE NUMBER: 25 -fun case_25(a: (() -> Unit) -> Unit, b: (() -> Unit) -> Unit = if (a == null) , kotlin.Unit>")!>a else {{}}) { +fun case_25(a: (() -> Unit) -> Unit, b: (() -> Unit) -> Unit = if (a == null) , kotlin.Unit> & kotlin.Function1, kotlin.Unit>")!>a else {{}}) { , kotlin.Unit>")!>a , kotlin.Unit>")!>b } // TESTCASE NUMBER: 26 -fun case_26(a: Int, b: Int = if (a === null) a else 0) { +fun case_26(a: Int, b: Int = if (a === null) a else 0) { a b } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/40.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/40.fir.kt index 30338a08970..89aaeaf3d42 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/40.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/40.fir.kt @@ -133,8 +133,8 @@ fun case_13(x: Any?) { */ fun case_14(x: Any?) { if (x == null) { - x - x?.equals(10) + x + x?.equals(10) x!!.equals(10) x.equals(10) } @@ -147,8 +147,8 @@ fun case_14(x: Any?) { */ fun case_15(x: Any?) { if (x !== null) else { - x - x?.equals(10) + x + x?.equals(10) x!!.equals(10) x.equals(10) } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/68.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/68.fir.kt index 5256453fa6f..09c79cabad4 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/68.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/68.fir.kt @@ -13,8 +13,8 @@ fun case_1(x: Any?) { // TESTCASE NUMBER: 2 fun case_2(x: Any?) { (x as Nothing?)!! - x - x.inv() + x + x.inv() } // TESTCASE NUMBER: 3 @@ -36,8 +36,8 @@ fun case_4(x: Any?) { // TESTCASE NUMBER: 5 fun case_5(x: Any?) { if (x as Nothing? is Nothing) { - x - x.inv() + x + x.inv() } } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/7.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/7.fir.kt index 63fe7a9a7b9..0b11b0ed40e 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/7.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/7.fir.kt @@ -39,7 +39,7 @@ fun case_1(x: Any?) { */ fun case_2(x: Nothing?) { if (x !== null && x !== null) { - x + x } } @@ -115,7 +115,7 @@ fun case_6(x: Class?) { // TESTCASE NUMBER: 7 fun case_7() { val x: EmptyObject? = null - if (x != null || x != null || x != null) { + if (x != null || x != null || x != null) { x x.equals(null) x.propT diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/70.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/70.fir.kt index d32762d5c7d..46a14698e57 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/70.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/70.fir.kt @@ -25,7 +25,7 @@ fun case_2(): Int? { val x: Int? = null return when (x != null) { false -> { - x + x } else -> null } @@ -53,7 +53,7 @@ fun case_4(): Int? { val x: Int? = null return when (x == null) { true -> { - x + x } else -> null }