[FIR] Fully expand the bounds of type parameters for canBeNull check
This is required because a not-null bound `Foo` can resolve to a `typealias Foo = Bar?` in which case we must return true. #KT-64645 Fixed
This commit is contained in:
committed by
Space Team
parent
438b2dd164
commit
1018ff280e
+1
-1
@@ -35,7 +35,7 @@ internal class KtFirTypeInfoProvider(
|
||||
return (type as KtFirType).coneType.functionTypeKind(analysisSession.useSiteSession)
|
||||
}
|
||||
|
||||
override fun canBeNull(type: KtType): Boolean = (type as KtFirType).coneType.canBeNull
|
||||
override fun canBeNull(type: KtType): Boolean = (type as KtFirType).coneType.canBeNull(analysisSession.useSiteSession)
|
||||
|
||||
override fun isDenotable(type: KtType): Boolean {
|
||||
val coneType = (type as KtFirType).coneType
|
||||
|
||||
+6
@@ -35179,6 +35179,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/castchecks/insideCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt64645.kt")
|
||||
public void testKt64645() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/castchecks/kt64645.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartCastOfNullableExpressionWithExpectedType.kt")
|
||||
public void testSmartCastOfNullableExpressionWithExpectedType() throws Exception {
|
||||
|
||||
+6
@@ -35179,6 +35179,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/castchecks/insideCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt64645.kt")
|
||||
public void testKt64645() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/castchecks/kt64645.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartCastOfNullableExpressionWithExpectedType.kt")
|
||||
public void testSmartCastOfNullableExpressionWithExpectedType() throws Exception {
|
||||
|
||||
+6
@@ -32905,6 +32905,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/castchecks/insideCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt64645.kt")
|
||||
public void testKt64645() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/castchecks/kt64645.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartCastOfNullableExpressionWithExpectedType.kt")
|
||||
public void testSmartCastOfNullableExpressionWithExpectedType() throws Exception {
|
||||
|
||||
+6
@@ -33025,6 +33025,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/castchecks/insideCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt64645.kt")
|
||||
public void testKt64645() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/castchecks/kt64645.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartCastOfNullableExpressionWithExpectedType.kt")
|
||||
public void testSmartCastOfNullableExpressionWithExpectedType() throws Exception {
|
||||
|
||||
+1
-1
@@ -151,7 +151,7 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
|
||||
private fun Operation.canBeTrueFor(session: FirSession, type: ConeKotlinType): Boolean = when (this) {
|
||||
Operation.EqTrue, Operation.EqFalse ->
|
||||
AbstractTypeChecker.isSubtypeOf(session.typeContext, session.builtinTypes.booleanType.type, type)
|
||||
Operation.EqNull -> type.canBeNull
|
||||
Operation.EqNull -> type.canBeNull(session)
|
||||
Operation.NotEqNull -> !type.isNullableNothing
|
||||
}
|
||||
|
||||
|
||||
+3
-6
@@ -7,14 +7,11 @@ package org.jetbrains.kotlin.fir.analysis.checkers
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
import org.jetbrains.kotlin.fir.getContainingClassLookupTag
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.resolve.getClassAndItsOuterClassesWhenLocal
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.platformClassMapper
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
@@ -58,8 +55,8 @@ fun checkCasting(
|
||||
return if (result) CastingType.Possible else CastingType.Impossible
|
||||
}
|
||||
|
||||
val lhsNullable = lhsLowerType.canBeNull
|
||||
val rhsNullable = rhsLowerType.canBeNull
|
||||
val lhsNullable = lhsLowerType.canBeNull(session)
|
||||
val rhsNullable = rhsLowerType.canBeNull(session)
|
||||
if (lhsLowerType.isNothing) return CastingType.Possible
|
||||
if (lhsLowerType.isNullableNothing && !rhsNullable) {
|
||||
return if (isSafeCase) CastingType.Always else CastingType.Impossible
|
||||
@@ -150,7 +147,7 @@ fun isCastErased(supertype: ConeKotlinType, subtype: ConeKotlinType, context: Ch
|
||||
// here we want to restrict cases such as `x is T` for x = T?, when T might have nullable upper bound
|
||||
if (isNonReifiedTypeParameter && !isUpcast) {
|
||||
// hack to save previous behavior in case when `x is T`, where T is not nullable, see IsErasedNullableTasT.kt
|
||||
val nullableToDefinitelyNotNull = !subtype.canBeNull && supertype.withNullability(ConeNullability.NOT_NULL, typeContext) == subtype
|
||||
val nullableToDefinitelyNotNull = !subtype.canBeNull(context.session) && supertype.withNullability(ConeNullability.NOT_NULL, typeContext) == subtype
|
||||
if (!nullableToDefinitelyNotNull) {
|
||||
return true
|
||||
}
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ object FirNotNullAssertionChecker : FirCheckNotNullCallChecker() {
|
||||
|
||||
val type = argument.resolvedType.fullyExpandedType(context.session)
|
||||
|
||||
if (!type.canBeNull && context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) {
|
||||
if (!type.canBeNull(context.session) && context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) {
|
||||
reporter.reportOn(expression.source, FirErrors.UNNECESSARY_NOT_NULL_ASSERTION, type, context)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ object FirSpreadOfNullableChecker : FirFunctionCallChecker() {
|
||||
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
fun checkAndReport(argument: FirExpression, source: KtSourceElement?) {
|
||||
val coneType = argument.resolvedType
|
||||
if (argument is FirSpreadArgumentExpression && coneType !is ConeFlexibleType && coneType.canBeNull) {
|
||||
if (argument is FirSpreadArgumentExpression && coneType !is ConeFlexibleType && coneType.canBeNull(context.session)) {
|
||||
reporter.reportOn(source, FirErrors.SPREAD_OF_NULLABLE, context)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ object FirUnnecessarySafeCallChecker : FirSafeCallExpressionChecker() {
|
||||
reporter.reportOn(expression.source, FirErrors.UNEXPECTED_SAFE_CALL, context)
|
||||
return
|
||||
}
|
||||
if (!receiverType.canBeNull) {
|
||||
if (!receiverType.canBeNull(context.session)) {
|
||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) {
|
||||
reporter.reportOn(expression.source, FirErrors.UNNECESSARY_SAFE_CALL, receiverType, context)
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ object FirUselessElvisChecker : FirElvisExpressionChecker() {
|
||||
|
||||
val lhsType = expression.lhs.resolvedType
|
||||
if (lhsType is ConeErrorType) return
|
||||
if (!lhsType.canBeNull) {
|
||||
if (!lhsType.canBeNull(context.session)) {
|
||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) {
|
||||
reporter.reportOn(expression.source, FirErrors.USELESS_ELVIS, lhsType, context)
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ object FirDefinitelyNotNullableChecker : FirTypeRefChecker() {
|
||||
reporter.reportOn(intersection.source, FirErrors.NULLABLE_ON_DEFINITELY_NOT_NULLABLE, context)
|
||||
}
|
||||
|
||||
if (!intersection.isLeftValidForDefinitelyNotNullable) {
|
||||
if (!intersection.isLeftValidForDefinitelyNotNullable(context.session)) {
|
||||
reporter.reportOn(intersection.leftType.source, FirErrors.INCORRECT_LEFT_COMPONENT_OF_INTERSECTION, context)
|
||||
}
|
||||
|
||||
|
||||
+5
-7
@@ -6,15 +6,13 @@
|
||||
package org.jetbrains.kotlin.fir.backend
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirUnitExpression
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
|
||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
@@ -235,7 +233,7 @@ class Fir2IrImplicitCastInserter(
|
||||
this
|
||||
}
|
||||
}
|
||||
typeCanBeEnhancedOrFlexibleNullable(expandedValueType) && !expandedExpectedType.acceptsNullValues() -> {
|
||||
typeCanBeEnhancedOrFlexibleNullable(expandedValueType, session) && !expandedExpectedType.acceptsNullValues() -> {
|
||||
insertImplicitNotNullCastIfNeeded(expression)
|
||||
}
|
||||
// TODO: coerceIntToAnotherIntegerType
|
||||
@@ -258,7 +256,7 @@ class Fir2IrImplicitCastInserter(
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.acceptsNullValues(): Boolean {
|
||||
return canBeNull || hasEnhancedNullability
|
||||
return canBeNull(session) || hasEnhancedNullability
|
||||
}
|
||||
|
||||
private fun IrExpression.insertImplicitNotNullCastIfNeeded(expression: FirExpression): IrExpression {
|
||||
@@ -432,10 +430,10 @@ class Fir2IrImplicitCastInserter(
|
||||
)
|
||||
}
|
||||
|
||||
internal fun typeCanBeEnhancedOrFlexibleNullable(type: ConeKotlinType): Boolean {
|
||||
internal fun typeCanBeEnhancedOrFlexibleNullable(type: ConeKotlinType, session: FirSession): Boolean {
|
||||
return when {
|
||||
type.hasEnhancedNullability -> true
|
||||
type.hasFlexibleNullability && type.canBeNull -> true
|
||||
type.hasFlexibleNullability && type.canBeNull(session) -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -303,7 +303,7 @@ class DelegatedMemberGenerator(private val components: Fir2IrComponents) : Fir2I
|
||||
|
||||
val substitutor = substitutorByMap(substitution, session)
|
||||
val substitutedType = substitutor.substituteOrSelf(originalFirDeclaration.returnTypeRef.coneType)
|
||||
callTypeCanBeNullable = Fir2IrImplicitCastInserter.typeCanBeEnhancedOrFlexibleNullable(substitutedType)
|
||||
callTypeCanBeNullable = Fir2IrImplicitCastInserter.typeCanBeEnhancedOrFlexibleNullable(substitutedType, session)
|
||||
substitutedType.toIrType(typeOrigin)
|
||||
}
|
||||
true -> {
|
||||
|
||||
@@ -780,3 +780,24 @@ fun ConeKotlinType.convertToNonRawVersion(): ConeKotlinType {
|
||||
|
||||
return withAttributes(attributes.remove(CompilerConeAttributes.RawType))
|
||||
}
|
||||
|
||||
fun ConeKotlinType.canBeNull(session: FirSession): Boolean {
|
||||
if (isMarkedNullable) {
|
||||
return true
|
||||
}
|
||||
return when (this) {
|
||||
is ConeFlexibleType -> upperBound.canBeNull(session)
|
||||
is ConeDefinitelyNotNullType -> false
|
||||
is ConeTypeParameterType -> this.lookupTag.typeParameterSymbol.resolvedBounds.all {
|
||||
// Upper bounds can resolve to typealiases that can expand to nullable types.
|
||||
it.coneType.fullyExpandedType(session).canBeNull(session)
|
||||
}
|
||||
is ConeIntersectionType -> intersectedTypes.all { it.canBeNull(session) }
|
||||
else -> fullyExpandedType(session).isNullable
|
||||
}
|
||||
}
|
||||
|
||||
fun FirIntersectionTypeRef.isLeftValidForDefinitelyNotNullable(session: FirSession) =
|
||||
leftType.coneType.let { it is ConeTypeParameterType && it.canBeNull(session) && !it.isMarkedNullable }
|
||||
|
||||
val FirIntersectionTypeRef.isRightValidForDefinitelyNotNullable get() = rightType.coneType.isAny
|
||||
@@ -197,7 +197,7 @@ object CheckDispatchReceiver : ResolutionStage() {
|
||||
|
||||
if (smartcastedReceiver != null &&
|
||||
!smartcastedReceiver.isStable &&
|
||||
(isCandidateFromUnstableSmartcast || (isReceiverNullable && !smartcastedReceiver.smartcastType.canBeNull))
|
||||
(isCandidateFromUnstableSmartcast || (isReceiverNullable && !smartcastedReceiver.smartcastType.coneType.canBeNull(callInfo.session)))
|
||||
) {
|
||||
val dispatchReceiverType = (candidate.symbol as? FirCallableSymbol<*>)?.dispatchReceiverType?.let {
|
||||
context.session.typeApproximator.approximateToSuperType(
|
||||
|
||||
+1
-1
@@ -118,7 +118,7 @@ class MemberScopeTowerLevel(
|
||||
// with two exceptions:
|
||||
// - When the smart-casted type is always null, we want to return it and report UNSAFE_CALL.
|
||||
// - When the original type can be null, in this case the smart-case either makes it not-null or the call is red anyway.
|
||||
if (existing == null || dispatchReceiverValue.type.isNullableNothing || receiverTypeWithoutSmartCast.canBeNull) {
|
||||
if (existing == null || dispatchReceiverValue.type.isNullableNothing || receiverTypeWithoutSmartCast.canBeNull(session)) {
|
||||
map[candidateFromSmartCast.member] = MemberFromSmartcastScope(candidateFromSmartCast, DispatchReceiverToUse.SmartcastWithoutUnwrapping)
|
||||
} else {
|
||||
existing.dispatchReceiverToUse = DispatchReceiverToUse.SmartcastIfUnwrappedInvisible
|
||||
|
||||
+6
-5
@@ -368,7 +368,7 @@ abstract class FirDataFlowAnalyzer(
|
||||
if (operandVariable.isReal()) {
|
||||
flow.addImplication((expressionVariable eq isType) implies (operandVariable typeEq type))
|
||||
}
|
||||
if (!type.canBeNull) {
|
||||
if (!type.canBeNull(components.session)) {
|
||||
// x is (T & Any) => x != null
|
||||
flow.addImplication((expressionVariable eq isType) implies (operandVariable notEq null))
|
||||
} else if (type.isMarkedNullable) {
|
||||
@@ -383,7 +383,7 @@ abstract class FirDataFlowAnalyzer(
|
||||
if (operandVariable.isReal()) {
|
||||
flow.addTypeStatement(operandVariable typeEq type)
|
||||
}
|
||||
if (!type.canBeNull) {
|
||||
if (!type.canBeNull(components.session)) {
|
||||
flow.commitOperationStatement(operandVariable notEq null)
|
||||
} else {
|
||||
val expressionVariable = variableStorage.createSynthetic(typeOperatorCall)
|
||||
@@ -998,9 +998,10 @@ abstract class FirDataFlowAnalyzer(
|
||||
for (conditionalEffect in conditionalEffects) {
|
||||
val effect = conditionalEffect.effect as? ConeReturnsEffectDeclaration ?: continue
|
||||
val operation = effect.value.toOperation()
|
||||
val statements = logicSystem.approveContractStatement(conditionalEffect.condition, argumentVariables, substitutor) {
|
||||
logicSystem.approveOperationStatement(flow, it, removeApprovedOrImpossible = operation == null)
|
||||
} ?: continue // TODO: do what if the result is known to be false?
|
||||
val statements =
|
||||
logicSystem.approveContractStatement(conditionalEffect.condition, argumentVariables, substitutor) {
|
||||
logicSystem.approveOperationStatement(flow, it, removeApprovedOrImpossible = operation == null)
|
||||
} ?: continue // TODO: do what if the result is known to be false?
|
||||
if (operation == null) {
|
||||
flow.addAllStatements(statements)
|
||||
} else {
|
||||
|
||||
@@ -6,14 +6,16 @@
|
||||
package org.jetbrains.kotlin.fir.resolve.dfa
|
||||
|
||||
import kotlinx.collections.immutable.*
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import java.util.*
|
||||
import kotlin.math.max
|
||||
|
||||
abstract class LogicSystem(private val context: ConeInferenceContext) {
|
||||
private val nullableNothingType = context.session.builtinTypes.nullableNothingType.type
|
||||
private val anyType = context.session.builtinTypes.anyType.type
|
||||
val session: FirSession get() = context.session
|
||||
private val nullableNothingType = session.builtinTypes.nullableNothingType.type
|
||||
private val anyType = session.builtinTypes.anyType.type
|
||||
|
||||
abstract val variableStorage: VariableStorageImpl
|
||||
|
||||
@@ -340,7 +342,7 @@ abstract class LogicSystem(private val context: ConeInferenceContext) {
|
||||
val result = when {
|
||||
unified.isNullableAny -> return null
|
||||
unified.isAcceptableForSmartcast() -> unified
|
||||
unified.canBeNull -> return null
|
||||
unified.canBeNull(context.session) -> return null
|
||||
else -> context.anyType()
|
||||
}
|
||||
return PersistentTypeStatement(variable, persistentSetOf(result))
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.resolve.dfa
|
||||
|
||||
import org.jetbrains.kotlin.contracts.description.LogicOperationKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.contracts.description.*
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.types.canBeNull
|
||||
@@ -45,7 +46,7 @@ fun LogicSystem.approveContractStatement(
|
||||
substitutedType.isNullableNothing -> it.processEqNull(isType)
|
||||
else -> {
|
||||
// x is (T & Any) || x !is T? => x != null
|
||||
val fromNullability = if ((isType && !type.canBeNull) || (!isType && type.isMarkedNullable))
|
||||
val fromNullability = if ((isType && !type.canBeNull(session)) || (!isType && type.isMarkedNullable))
|
||||
it.processEqNull(false)
|
||||
else
|
||||
mapOf()
|
||||
|
||||
@@ -155,25 +155,3 @@ fun FirTypeProjection.toConeTypeProjection(): ConeTypeProjection = when (this) {
|
||||
}
|
||||
else -> errorWithAttachment("Unexpected ${this::class.simpleName}") { withFirEntry("projection", this@toConeTypeProjection) }
|
||||
}
|
||||
|
||||
val FirTypeRef.canBeNull: Boolean
|
||||
get() = coneType.canBeNull
|
||||
|
||||
val ConeKotlinType.canBeNull: Boolean
|
||||
get() {
|
||||
if (isMarkedNullable) {
|
||||
return true
|
||||
}
|
||||
return when (this) {
|
||||
is ConeFlexibleType -> upperBound.canBeNull
|
||||
is ConeDefinitelyNotNullType -> false
|
||||
is ConeTypeParameterType -> this.lookupTag.typeParameterSymbol.resolvedBounds.all { it.coneType.canBeNull }
|
||||
is ConeIntersectionType -> intersectedTypes.all { it.canBeNull }
|
||||
else -> isNullable
|
||||
}
|
||||
}
|
||||
|
||||
val FirIntersectionTypeRef.isLeftValidForDefinitelyNotNullable
|
||||
get() = leftType.coneType.let { it is ConeTypeParameterType && it.canBeNull && !it.isMarkedNullable }
|
||||
|
||||
val FirIntersectionTypeRef.isRightValidForDefinitelyNotNullable get() = rightType.coneType.isAny
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// FIR_IDENTICAL
|
||||
// DIAGNOSTICS: -DEBUG_INFO_SMARTCAST, -FINAL_UPPER_BOUND
|
||||
// ISSUE: KT-64645
|
||||
|
||||
class Box(val value: String)
|
||||
typealias NullableBox = Box?
|
||||
|
||||
fun <T : NullableBox> foo(x: T) {
|
||||
if (x != null) {
|
||||
x.value
|
||||
}
|
||||
}
|
||||
|
||||
fun foo2(x: NullableBox) {
|
||||
if (x != null) {
|
||||
x.value
|
||||
}
|
||||
}
|
||||
Generated
+6
@@ -35179,6 +35179,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/castchecks/insideCall.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt64645.kt")
|
||||
public void testKt64645() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/castchecks/kt64645.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("smartCastOfNullableExpressionWithExpectedType.kt")
|
||||
public void testSmartCastOfNullableExpressionWithExpectedType() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user