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(