Stability fixes
diff --git a/compiler/fir/analysis-tests/testData/resolve/rich-errors/genericCalls.fir.txt b/compiler/fir/analysis-tests/testData/resolve/rich-errors/genericCalls.fir.txt index 9e36ee1..8f2e737 100644 --- a/compiler/fir/analysis-tests/testData/resolve/rich-errors/genericCalls.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/rich-errors/genericCalls.fir.txt
@@ -61,3 +61,22 @@ R|/foo6<Inapplicable(INAPPLICABLE): /foo6>#|<R|kotlin/Nothing | TypeVariable(T)|, R|kotlin/Nothing | TypeVariable(V)|>(Q|E3|, Q|E2|) R|/foo6<Inapplicable(INAPPLICABLE): /foo6>#|<R|kotlin/Nothing | TypeVariable(T)|, R|kotlin/Nothing | TypeVariable(V)|>(Q|E3|, Q|E3|) } + public final inline fun <T, E1 : R|kotlin/Nothing | Error|, E2 : R|kotlin/Nothing | Error|> R|T | E1|.onError(f: R|(kotlin/Nothing | E1) -> kotlin/Nothing | E2|): R|T | E2| { + when () { + (this@R|/onError| is R|kotlin/Nothing | Error|) -> { + ^onError R|<local>/f|.R|SubstitutionOverride<kotlin/Function1.invoke: R|kotlin/Nothing | E2|>|(this@R|/onError|) + } + else -> { + ^onError this@R|/onError| + } + } + + } + public final fun onErrorCaller(v: R|kotlin/Int | E1|): R|kotlin/Nothing | E1| { + lval v2: R|kotlin/Int| = R|<local>/v|.R|/onError|<R|kotlin/Int|, R|kotlin/Nothing | E1|, R|kotlin/Nothing | TypeVariable(E2)|>(<L> = onError@fun <anonymous>(it: R|kotlin/Nothing | E1|): R|kotlin/Nothing | TypeVariable(E2)| <inline=Inline, kind=UNKNOWN> { + ^onErrorCaller R|<local>/it| + } + ) + lval v3: R|kotlin/Int| = R|<local>/v2| + Null(null)!! + }
diff --git a/compiler/fir/analysis-tests/testData/resolve/rich-errors/genericCalls.kt b/compiler/fir/analysis-tests/testData/resolve/rich-errors/genericCalls.kt index 114da2a..e867625 100644 --- a/compiler/fir/analysis-tests/testData/resolve/rich-errors/genericCalls.kt +++ b/compiler/fir/analysis-tests/testData/resolve/rich-errors/genericCalls.kt
@@ -48,3 +48,17 @@ <!INAPPLICABLE_CANDIDATE!>foo6<!>(E3, E2) <!INAPPLICABLE_CANDIDATE!>foo6<!>(E3, E3) } + +inline fun <T : Any?, E1 : KError, E2: KError> (T | E1).onError(f: (E1) -> E2): T | E2 { + if (this is KError) { + return f(this) + } else { + return this + } +} + +fun onErrorCaller(v: Int | E1): E1 { + val v2 = v.onError { return it } + val v3: Int = v2 + null!! +}
diff --git a/compiler/fir/analysis-tests/testData/resolve/rich-errors/safeCall.fir.txt b/compiler/fir/analysis-tests/testData/resolve/rich-errors/safeCall.fir.txt index 4fb65e1..e54d6ea 100644 --- a/compiler/fir/analysis-tests/testData/resolve/rich-errors/safeCall.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/rich-errors/safeCall.fir.txt
@@ -37,3 +37,11 @@ public get(): R|kotlin/Int| public final val v52: R|kotlin/Int?| = R|/identity|<R|kotlin/Int? | E1|>(R|/neString|?.{ $subj$.R|/foo|() }) public get(): R|kotlin/Int?| + public final fun foo(v: R|kotlin/Int | E1|): R|kotlin/Int| { + lval tmp: R|kotlin/Nothing | E1| = R|<local>/v|?.{ $subj$.R|kotlin/let|<R|kotlin/Int|, R|kotlin/Nothing|>(<L> = let@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Nothing| <inline=Inline, kind=EXACTLY_ONCE> { + ^foo R|<local>/it| + } + ) } + lval tmp2: R|kotlin/Nothing | E1| = R|<local>/tmp| + Null(null)!! + }
diff --git a/compiler/fir/analysis-tests/testData/resolve/rich-errors/safeCall.kt b/compiler/fir/analysis-tests/testData/resolve/rich-errors/safeCall.kt index c7e0bb8..a157351 100644 --- a/compiler/fir/analysis-tests/testData/resolve/rich-errors/safeCall.kt +++ b/compiler/fir/analysis-tests/testData/resolve/rich-errors/safeCall.kt
@@ -1,22 +1,28 @@ -// RUN_PIPELINE_TILL: FRONTEND +// RUN_PIPELINE_TILL: BACKEND error object E1 -val nString: String? = null!! -val eString: String | E1 = null!! -val neString: String? | E1 = null!! +//val nString: String? = null!! +//val eString: String | E1 = null!! +//val neString: String? | E1 = null!! +// +//fun String.foo(): Int = null!! +// +//fun <T : Any? | E1> identity(v: T): T = v +// +//val v1: Int? = nString?.foo() +//val v2: Int | E1 = eString?.foo() +//val v3: Int? | E1 = neString?.foo() +//val v4: Int = <!INITIALIZER_TYPE_MISMATCH!>eString?.foo()<!> +//val v5: Int? = <!INITIALIZER_TYPE_MISMATCH!>neString?.foo()<!> +//val v12: Int? = identity(nString?.foo()) +//val v22: Int | E1 = identity(eString?.foo()) +//val v32: Int? | E1 = identity(neString?.foo()) +//val v42: Int = <!INITIALIZER_TYPE_MISMATCH!>identity(eString?.foo())<!> +//val v52: Int? = <!INITIALIZER_TYPE_MISMATCH!>identity(neString?.foo())<!> -fun String.foo(): Int = null!! - -fun <T : Any? | E1> identity(v: T): T = v - -val v1: Int? = nString?.foo() -val v2: Int | E1 = eString?.foo() -val v3: Int? | E1 = neString?.foo() -val v4: Int = <!INITIALIZER_TYPE_MISMATCH!>eString?.foo()<!> -val v5: Int? = <!INITIALIZER_TYPE_MISMATCH!>neString?.foo()<!> -val v12: Int? = identity(nString?.foo()) -val v22: Int | E1 = identity(eString?.foo()) -val v32: Int? | E1 = identity(neString?.foo()) -val v42: Int = <!INITIALIZER_TYPE_MISMATCH!>identity(eString?.foo())<!> -val v52: Int? = <!INITIALIZER_TYPE_MISMATCH!>identity(neString?.foo())<!> +fun foo(v: Int | E1): Int { + val tmp = v?.let { return it } + val tmp2: E1 = tmp + null!! +}
diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt index ef96b1f..5cb24d1 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt
@@ -77,6 +77,7 @@ companion object { fun create(valueType: ConeValueType, errorType: CEType): ConeErrorUnionType { + if (errorType is CEBotType) error("Unexpected") return ConeErrorUnionType(valueType, errorType) } @@ -86,7 +87,7 @@ } fun addErrorComponent(original: ConeKotlinType, errorType: CEType): ConeKotlinType { - if (errorType == CEBotType) return original + if (errorType is CEBotType) return original return when (original) { is ConeFlexibleType -> {
diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/utils/IrElementsCreationUtils.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/utils/IrElementsCreationUtils.kt index 99d30fd..b9ec115 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/utils/IrElementsCreationUtils.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/utils/IrElementsCreationUtils.kt
@@ -39,6 +39,8 @@ import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.types.isAny +import org.jetbrains.kotlin.ir.types.isNullableAny import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.name.* @@ -114,8 +116,8 @@ IrGetValueImpl(startOffset, endOffset, receiverVariableSymbol), ) - // TODO: RE: HIGH: make errorable too - val resultType = expressionOnNotNull.type.makeNullable() + val mayHaveErrors = receiverVariable.type.isAny() || receiverVariable.type.isNullableAny() + val resultType = if (mayHaveErrors) receiverVariable.type else expressionOnNotNull.type.makeNullable() return IrBlockImpl(startOffset, endOffset, resultType, IrStatementOrigin.SAFE_CALL).apply { statements += receiverVariable @@ -123,10 +125,11 @@ branches += IrBranchImpl( conditionNull(), IrConstImpl.constNull(startOffset, endOffset, builtins.nothingNType) ) - // TODO: RE: HIGH: Do not add if receiverVariable.type is not appropriate - branches += IrBranchImpl( - conditionError(), IrGetValueImpl(startOffset, endOffset, receiverVariableSymbol) - ) + if (mayHaveErrors) { + branches += IrBranchImpl( + conditionError(), IrGetValueImpl(startOffset, endOffset, receiverVariableSymbol) + ) + } branches += IrElseBranchImpl( IrConstImpl.boolean(startOffset, endOffset, builtins.booleanType, true), expressionOnNotNull
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index eb6a4be..034ff9d 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt
@@ -771,12 +771,37 @@ !subTs.isSubtypeOfAtomic(CEBotType) } - return unsatisfiedSubTs.map { it to upperType } + val containedVariablesSub = subTs.filter { it is CETypeVariableType } + + if (unsatisfiedSubTs.isEmpty()) { + val containedVariablesSuper = superTs.filter { it is CETypeVariableType } + + return buildList { + containedVariablesSub.forEach { subV -> + add(subV to CETopType) + } + containedVariablesSuper.forEach { superV -> + add(superV to CETopType) + } + } + } + + val lostSubV = containedVariablesSub.filter { subV -> + !unsatisfiedSubTs.contains(subV) + } + + return buildList { + unsatisfiedSubTs.forEach { subT -> + add(subT to upperType) + } + lostSubV.forEach { subV -> + add(subV to CETopType) + } + } } override fun ErrorTypeMarker.isPossibleSubtypeOf(other: ErrorTypeMarker): Boolean { require(this !is CEUnionType) { "Expected atomic" } - require(!this.isSubtypeOf(other)) { "Already a subtype" } val subT = this as CEType val superTs = (other as CEType).collectAtomics(mutableListOf())
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt index 0c9a655..4103742 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt
@@ -778,7 +778,7 @@ } } -fun CEType.toConeType(): ConeRigidType = ConeErrorUnionType.create(StandardTypes.Nothing, this) +fun CEType.toConeType(): ConeRigidType = ConeErrorUnionType.createNormalized(StandardTypes.Nothing, this) fun ConeKotlinType.isSubtypeOf(superType: ConeKotlinType, session: FirSession, errorTypesEqualToAnything: Boolean = false): Boolean = AbstractTypeChecker.isSubtypeOf(
diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt index cc8ccf9..7434579 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/LightTreeRawFirDeclarationBuilder.kt
@@ -638,7 +638,7 @@ baseModuleData, callableIdForName(it.firValueParameter.name), classIsExpect, - currentDispatchReceiverType()?.expectNonErrorClassSoft, + currentDispatchReceiverType(), context ) }
diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt index e3ee9d1..9ae4ea1 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol import org.jetbrains.kotlin.fir.types.ConeClassLikeType +import org.jetbrains.kotlin.fir.types.ConeRigidType import org.jetbrains.kotlin.fir.types.FirErrorTypeRef import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef import org.jetbrains.kotlin.fir.types.FirTypeRef @@ -117,7 +118,7 @@ moduleData: FirModuleData, callableId: CallableId, isExpect: Boolean, - currentDispatchReceiver: ConeClassLikeType?, + currentDispatchReceiver: ConeRigidType?, context: Context<T> ): FirProperty { val name = this.firValueParameter.name
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 d4a12fd..4d10845 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
@@ -602,7 +602,7 @@ } else { valueType } - ConeErrorUnionType.create(newValueComponent, newErrorComponent) + ConeErrorUnionType.createNormalized(newValueComponent, newErrorComponent) } else { intersectedUpperType }
diff --git a/compiler/psi/src/org/jetbrains/kotlin/resolve/ModifierCheckerHelpers.kt b/compiler/psi/src/org/jetbrains/kotlin/resolve/ModifierCheckerHelpers.kt index c9fe4b6..a123e3c 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/resolve/ModifierCheckerHelpers.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/resolve/ModifierCheckerHelpers.kt
@@ -216,7 +216,7 @@ KotlinTarget.BACKING_FIELD ), DATA_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY, KotlinTarget.LOCAL_CLASS, KotlinTarget.STANDALONE_OBJECT), - ERROR_KEYWORD to EnumSet.of(KotlinTarget.STANDALONE_OBJECT), + ERROR_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY, KotlinTarget.LOCAL_CLASS, KotlinTarget.STANDALONE_OBJECT), INLINE_KEYWORD to EnumSet.of( KotlinTarget.FUNCTION, KotlinTarget.PROPERTY,
diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt index b093f5b..073ccf6 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/AbstractTypeChecker.kt
@@ -341,7 +341,7 @@ preparedSubType.projectOnValue(), preparedSuperType.projectOnValue(), isFromNullabilityConstraint - ) + ) && completeIsSubTypeOfErrors(state, botTypeOfErrors(), preparedSuperTypeUb.errorType()) } preparedSubTypeLb is ErrorUnionTypeMarker && preparedSuperTypeUb is ValueTypeMarker -> { completeIsSubTypeOfValues(