T
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index 6a5e923..5ae3715 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -8,4 +8,7 @@
   <component name="KotlinCompilerSettings">
     <option name="additionalArguments" value="-version -Xallow-kotlin-package -Xskip-metadata-version-check" />
   </component>
+  <component name="KotlinJpsPluginSettings">
+    <option name="version" value="1.8.0-dev-446" />
+  </component>
 </project>
\ No newline at end of file
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt
index d9965bf..f202b55 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt
@@ -1372,8 +1372,8 @@
             token,
         )
     }
-    add(FirErrors.SEALED_INLINE_CLASS_WITH_UNDERLYING_VALUE) { firDiagnostic ->
-        SealedInlineClassWithUnderlyingValueImpl(
+    add(FirErrors.SEALED_INLINE_CLASS_WITH_PRIMARY_CONSTRUCTOR) { firDiagnostic ->
+        SealedInlineClassWithPrimaryConstructorImpl(
             firDiagnostic as KtPsiDiagnostic,
             token,
         )
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt
index 32f3789..090a93a 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt
@@ -990,8 +990,8 @@
         override val diagnosticClass get() = ValueObjectNotSealedInlineChild::class
     }
 
-    abstract class SealedInlineClassWithUnderlyingValue : KtFirDiagnostic<KtDeclaration>() {
-        override val diagnosticClass get() = SealedInlineClassWithUnderlyingValue::class
+    abstract class SealedInlineClassWithPrimaryConstructor : KtFirDiagnostic<KtDeclaration>() {
+        override val diagnosticClass get() = SealedInlineClassWithPrimaryConstructor::class
     }
 
     abstract class SealedInlineChildNotValue : KtFirDiagnostic<KtDeclaration>() {
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt
index 6775868..0c4b3d5 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt
@@ -1187,10 +1187,10 @@
     override val token: KtLifetimeToken,
 ) : KtFirDiagnostic.ValueObjectNotSealedInlineChild(), KtAbstractFirDiagnostic<KtDeclaration>
 
-internal class SealedInlineClassWithUnderlyingValueImpl(
+internal class SealedInlineClassWithPrimaryConstructorImpl(
     override val firDiagnostic: KtPsiDiagnostic,
     override val token: KtLifetimeToken,
-) : KtFirDiagnostic.SealedInlineClassWithUnderlyingValue(), KtAbstractFirDiagnostic<KtDeclaration>
+) : KtFirDiagnostic.SealedInlineClassWithPrimaryConstructor(), KtAbstractFirDiagnostic<KtDeclaration>
 
 internal class SealedInlineChildNotValueImpl(
     override val firDiagnostic: KtPsiDiagnostic,
diff --git a/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassDeclaration.kt b/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassDeclaration.kt
index 2eaf012..09d0fa2 100644
--- a/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassDeclaration.kt
+++ b/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassDeclaration.kt
@@ -9,7 +9,7 @@
 
 <!VALUE_CLASS_NOT_FINAL!>open<!> inline class NotFinalClass1(val x: Int)
 <!VALUE_CLASS_NOT_FINAL!>abstract<!> inline class NotFinalClass2(val x: Int)
-<!VALUE_CLASS_NOT_FINAL!>sealed<!> inline class NotFinalClass3(val x: Int)
+<!UNSUPPORTED_FEATURE!>sealed<!> inline class NotFinalClass3(val x: Int)
 
 <!VALUE_CLASS_CANNOT_BE_CLONEABLE, VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class CloneableClass1(val x: Int): Cloneable
 <!VALUE_CLASS_CANNOT_BE_CLONEABLE!>inline<!> class CloneableClass2(val x: Int): <!PLATFORM_CLASS_MAPPED_TO_KOTLIN!>java.lang.Cloneable<!>
diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt
index 9ffd2f3..c953bdf 100644
--- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt
+++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt
@@ -15,8 +15,6 @@
 import org.jetbrains.kotlin.descriptors.EffectiveVisibility
 import org.jetbrains.kotlin.descriptors.Visibility
 import org.jetbrains.kotlin.diagnostics.WhenMissingCase
-import org.jetbrains.kotlin.diagnostics.deprecationError2
-import org.jetbrains.kotlin.diagnostics.error0
 import org.jetbrains.kotlin.fir.FirModuleData
 import org.jetbrains.kotlin.fir.PrivateForInline
 import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.*
@@ -426,7 +424,7 @@
         val INNER_CLASS_INSIDE_VALUE_CLASS by error<KtDeclaration>(PositioningStrategy.INNER_MODIFIER)
         val VALUE_CLASS_CANNOT_BE_CLONEABLE by error<KtDeclaration>(PositioningStrategy.INLINE_OR_VALUE_MODIFIER)
         val VALUE_OBJECT_NOT_SEALED_INLINE_CHILD by error<KtDeclaration>(PositioningStrategy.INLINE_OR_VALUE_MODIFIER)
-        val SEALED_INLINE_CLASS_WITH_UNDERLYING_VALUE by error<KtDeclaration>(PositioningStrategy.INLINE_OR_VALUE_MODIFIER)
+        val SEALED_INLINE_CLASS_WITH_PRIMARY_CONSTRUCTOR by error<KtDeclaration>(PositioningStrategy.INLINE_OR_VALUE_MODIFIER)
         val SEALED_INLINE_CHILD_NOT_VALUE by error<KtDeclaration>()
         val SEALED_INLINE_CHILD_OVERLAPPING_TYPE by error<KtDeclaration>(PositioningStrategy.INLINE_OR_VALUE_MODIFIER)
     }
diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt
index 96fc6f2..923ffd7 100644
--- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt
+++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt
@@ -322,7 +322,7 @@
     val INNER_CLASS_INSIDE_VALUE_CLASS by error0<KtDeclaration>(SourceElementPositioningStrategies.INNER_MODIFIER)
     val VALUE_CLASS_CANNOT_BE_CLONEABLE by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
     val VALUE_OBJECT_NOT_SEALED_INLINE_CHILD by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
-    val SEALED_INLINE_CLASS_WITH_UNDERLYING_VALUE by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
+    val SEALED_INLINE_CLASS_WITH_PRIMARY_CONSTRUCTOR by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
     val SEALED_INLINE_CHILD_NOT_VALUE by error0<KtDeclaration>()
     val SEALED_INLINE_CHILD_OVERLAPPING_TYPE by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
 
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineClassDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineClassDeclarationChecker.kt
index 1d0f907..fffc4e5 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineClassDeclarationChecker.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineClassDeclarationChecker.kt
@@ -14,6 +14,7 @@
 import org.jetbrains.kotlin.diagnostics.reportOn
 import org.jetbrains.kotlin.fir.FirSession
 import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
+import org.jetbrains.kotlin.fir.analysis.checkers.getModifier
 import org.jetbrains.kotlin.fir.analysis.checkers.hasModifier
 import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
@@ -52,11 +53,19 @@
             reporter.reportOn(declaration.source, FirErrors.VALUE_CLASS_NOT_TOP_LEVEL, context)
         }
 
-        if (declaration.modality != Modality.FINAL &&
-            !(declaration.modality == Modality.SEALED &&
-                    context.languageVersionSettings.supportsFeature(LanguageFeature.SealedInlineClasses))
-        ) {
-            reporter.reportOn(declaration.source, FirErrors.VALUE_CLASS_NOT_FINAL, context)
+        if (declaration.modality != Modality.FINAL) {
+            if (declaration.modality == Modality.SEALED) {
+                if (!context.languageVersionSettings.supportsFeature(LanguageFeature.SealedInlineClasses)) {
+                    reporter.reportOn(
+                        declaration.getModifier(KtTokens.SEALED_KEYWORD)?.source,
+                        FirErrors.UNSUPPORTED_FEATURE,
+                        LanguageFeature.SealedInlineClasses to context.languageVersionSettings,
+                        context
+                    )
+                }
+            } else {
+                reporter.reportOn(declaration.source, FirErrors.VALUE_CLASS_NOT_FINAL, context)
+            }
         }
 
         for (supertypeEntry in declaration.superTypeRefs) {
@@ -182,7 +191,7 @@
             context.languageVersionSettings.supportsFeature(LanguageFeature.SealedInlineClasses) &&
             primaryConstructor?.source?.kind is KtRealSourceElementKind
         ) {
-            reporter.reportOn(declaration.source, FirErrors.SEALED_INLINE_CLASS_WITH_UNDERLYING_VALUE, context)
+            reporter.reportOn(declaration.source, FirErrors.SEALED_INLINE_CLASS_WITH_PRIMARY_CONSTRUCTOR, context)
             return
         }
 
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt
index e903a91..6b55e75 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt
@@ -461,7 +461,7 @@
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_INHERITOR_IN_DIFFERENT_PACKAGE
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_INLINE_CHILD_NOT_VALUE
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_INLINE_CHILD_OVERLAPPING_TYPE
-import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_INLINE_CLASS_WITH_UNDERLYING_VALUE
+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_INLINE_CLASS_WITH_PRIMARY_CONSTRUCTOR
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_SUPERTYPE
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_SUPERTYPE_IN_LOCAL_CLASS
 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_VALUE_CLASS
@@ -1242,7 +1242,7 @@
         map.put(VALUE_OBJECT_NOT_SEALED_INLINE_CHILD, "value object must be child of sealed inline class")
         map.put(SEALED_INLINE_CHILD_NOT_VALUE, "child of sealed inline class must be value");
         map.put(SEALED_INLINE_CHILD_OVERLAPPING_TYPE, "Sealed inline class child cannot be distinguished from another one");
-        map.put(SEALED_INLINE_CLASS_WITH_UNDERLYING_VALUE, "Sealed inline class cannot have underlying value");
+        map.put(SEALED_INLINE_CLASS_WITH_PRIMARY_CONSTRUCTOR, "Sealed inline class cannot have primary constructor");
 
         // Inline
         map.put(
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java
index b954069..cc7c8e3 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java
@@ -11,7 +11,6 @@
 import kotlin.Pair;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.kotlin.config.LanguageFeature;
-import org.jetbrains.kotlin.config.LanguageVersion;
 import org.jetbrains.kotlin.config.LanguageVersionSettings;
 import org.jetbrains.kotlin.descriptors.*;
 import org.jetbrains.kotlin.diagnostics.rendering.DeclarationWithDiagnosticComponents;
@@ -27,7 +26,6 @@
 import org.jetbrains.kotlin.psi.*;
 import org.jetbrains.kotlin.resolve.VarianceConflictDiagnosticData;
 import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData;
-import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor;
 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
 import org.jetbrains.kotlin.resolve.calls.tower.WrongResolutionToClassifier;
 import org.jetbrains.kotlin.resolve.calls.util.BuilderLambdaLabelingInfo;
@@ -43,7 +41,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import static org.jetbrains.kotlin.config.LanguageFeature.ReportTypeVarianceConflictOnQualifierArguments;
 import static org.jetbrains.kotlin.diagnostics.ClassicPositioningStrategies.ACTUAL_DECLARATION_NAME;
 import static org.jetbrains.kotlin.diagnostics.ClassicPositioningStrategies.INCOMPATIBLE_DECLARATION;
 import static org.jetbrains.kotlin.diagnostics.PositioningStrategies.*;
@@ -412,7 +409,7 @@
     DiagnosticFactory0<PsiElement> VALUE_CLASS_NOT_TOP_LEVEL = DiagnosticFactory0.create(ERROR);
     DiagnosticFactory0<PsiElement> VALUE_CLASS_NOT_FINAL = DiagnosticFactory0.create(ERROR);
     DiagnosticFactory0<PsiElement> SEALED_INLINE_CLASS_WRONG_MODIFIER = DiagnosticFactory0.create(WARNING);
-    DiagnosticFactory0<PsiElement> SEALED_INLINE_CLASS_WITH_UNDERLYING_VALUE = DiagnosticFactory0.create(ERROR);
+    DiagnosticFactory0<PsiElement> SEALED_INLINE_CLASS_WITH_PRIMARY_CONSTRUCTOR = DiagnosticFactory0.create(ERROR);
     DiagnosticFactory0<PsiElement> ABSENCE_OF_PRIMARY_CONSTRUCTOR_FOR_VALUE_CLASS = DiagnosticFactory0.create(ERROR);
     DiagnosticFactory0<KtElement> INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE = DiagnosticFactory0.create(ERROR);
     DiagnosticFactory0<KtElement> VALUE_CLASS_EMPTY_CONSTRUCTOR = DiagnosticFactory0.create(ERROR);
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
index 3ed003f..08d49f6 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java
@@ -767,8 +767,8 @@
         MAP.put(NON_PRIVATE_OR_PROTECTED_CONSTRUCTOR_IN_SEALED, "Constructor must be private or protected in sealed class");
 
         MAP.put(VALUE_CLASS_NOT_TOP_LEVEL, "Value classes cannot be local or inner");
-        MAP.put(VALUE_CLASS_NOT_FINAL, "Value classes can be only final or sealed");
-        MAP.put(SEALED_INLINE_CLASS_WITH_UNDERLYING_VALUE, "Sealed inline class cannot have underlying value");
+        MAP.put(VALUE_CLASS_NOT_FINAL, "Value classes must be final or sealed");
+        MAP.put(SEALED_INLINE_CLASS_WITH_PRIMARY_CONSTRUCTOR, "Sealed inline class cannot have primary constructor");
         MAP.put(SEALED_INLINE_CLASS_WRONG_MODIFIER, "Sealed inline class should use 'value' modifier instead of 'inline'");
         MAP.put(ABSENCE_OF_PRIMARY_CONSTRUCTOR_FOR_VALUE_CLASS, "Primary constructor is required for value class");
         MAP.put(INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE, "Inline class must have exactly one primary constructor parameter");
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt
index 8d6956f..c0531f8 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/InlineClassDeclarationChecker.kt
@@ -80,7 +80,12 @@
         }
 
         if (modalityModifier != null && isSealed && !context.languageVersionSettings.supportsFeature(LanguageFeature.SealedInlineClasses)) {
-            trace.report(Errors.VALUE_CLASS_NOT_FINAL.on(modalityModifier))
+            trace.report(
+                Errors.UNSUPPORTED_FEATURE.on(
+                    modalityModifier,
+                    LanguageFeature.SealedInlineClasses to context.languageVersionSettings
+                )
+            )
             return
         }
 
@@ -91,19 +96,19 @@
         }
 
         if (isSealed && primaryConstructor != null) {
-            trace.report(Errors.SEALED_INLINE_CLASS_WITH_UNDERLYING_VALUE.on(primaryConstructor))
+            trace.report(Errors.SEALED_INLINE_CLASS_WITH_PRIMARY_CONSTRUCTOR.on(primaryConstructor))
             return
         }
 
-        if (!isNoinlineChildOfSealedInlineClass) {
-            if (context.languageVersionSettings.supportsFeature(LanguageFeature.ValueClasses) && descriptor.isValueClass()) {
-                if (primaryConstructor != null && primaryConstructor.valueParameters.isEmpty()) {
+        if (!isNoinlineChildOfSealedInlineClass && primaryConstructor != null) {
+            if (context.languageVersionSettings.supportsFeature(LanguageFeature.ValueClasses)) {
+                if (primaryConstructor.valueParameters.isEmpty()) {
                     (primaryConstructor.valueParameterList ?: declaration).let {
                         trace.report(Errors.VALUE_CLASS_EMPTY_CONSTRUCTOR.on(it))
                         return
                     }
                 }
-            } else if (!isSealed && primaryConstructor != null && primaryConstructor.valueParameters.size != 1) {
+            } else if (primaryConstructor.valueParameters.size != 1) {
                 (primaryConstructor.valueParameterList ?: declaration).let {
                     trace.report(Errors.INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE.on(it))
                     return
@@ -114,7 +119,7 @@
         var baseParametersOk = true
         val baseParameterTypes = descriptor.safeAs<ClassDescriptor>()?.defaultType?.substitutedUnderlyingTypes() ?: emptyList()
 
-        for ((baseParameter, baseParameterType) in (primaryConstructor?.valueParameters ?: emptyList()) zip baseParameterTypes) {
+        for ((baseParameter, baseParameterType) in primaryConstructor?.valueParameters.orEmpty() zip baseParameterTypes) {
             if (!isParameterAcceptableForInlineClass(baseParameter)) {
                 trace.report(Errors.VALUE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER.on(baseParameter))
                 baseParametersOk = false
diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/VarargLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/VarargLowering.kt
index 7e0ed41..344e516 100644
--- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/VarargLowering.kt
+++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/VarargLowering.kt
@@ -7,7 +7,6 @@
 
 import org.jetbrains.kotlin.backend.common.BodyLoweringPass
 import org.jetbrains.kotlin.backend.common.compilationException
-import org.jetbrains.kotlin.backend.common.DefaultInlineClassesUtils.getInlineClassUnderlyingType
 import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
 import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
 import org.jetbrains.kotlin.ir.declarations.IrClass
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
index fe17bb1..f614742 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
@@ -41,7 +41,6 @@
 import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
 import org.jetbrains.kotlin.load.java.JvmAbi
 import org.jetbrains.kotlin.name.Name
-import org.jetbrains.kotlin.util.OperatorNameConventions
 import org.jetbrains.kotlin.utils.addToStdlib.popLast
 
 val jvmInlineClassPhase = makeIrFilePhase(
@@ -118,11 +117,8 @@
                             val tmp = irTemporary(transformed.argument)
                             +irIfNull(
                                 context.irBuiltIns.booleanType, irGet(tmp), irFalse(),
-                                irCall(isCheck.symbol).also {
-                                    it.putValueArgument(
-                                        0,
-                                        coerceInlineClasses(irGet(tmp), top.defaultType, context.irBuiltIns.anyNType)
-                                    )
+                                irCall(isCheck.symbol).apply {
+                                    putValueArgument(0, coerceFromSealedInlineClass(top, irGet(tmp)))
                                 }
                             )
                         }
@@ -135,21 +131,16 @@
                             val tmp = irTemporary(transformed.argument)
                             +irIfNull(
                                 context.irBuiltIns.booleanType, irGet(tmp), irTrue(),
-                                irNot(
-                                    irCall(isCheck.symbol).also {
-                                        it.putValueArgument(
-                                            0,
-                                            coerceInlineClasses(irGet(tmp), top.defaultType, context.irBuiltIns.anyNType)
-                                        )
-                                    }
-                                )
+                                irNot(irCall(isCheck.symbol).apply {
+                                    putValueArgument(0, coerceFromSealedInlineClass(top, irGet(tmp)))
+                                })
                             )
                         }
                     }
                 }
                 IrTypeOperator.CAST -> {
                     // if (Top.is-Child(top)) top else CCE
-                    return generateAsCheck(currentScopeSymbol, transformed, top, isCheck, underlyingType) {
+                    return generateAsCheckForSealedInlineClass(currentScopeSymbol, transformed, top, isCheck, underlyingType) {
                         irCall(this@JvmInlineClassLowering.context.ir.symbols.throwTypeCastException).also {
                             it.putValueArgument(
                                 0,
@@ -160,7 +151,7 @@
                 }
                 IrTypeOperator.SAFE_CAST -> {
                     // if (Top.is-Child(top)) top else null
-                    return generateAsCheck(currentScopeSymbol, transformed, top, isCheck, underlyingType) { irNull() }
+                    return generateAsCheckForSealedInlineClass(currentScopeSymbol, transformed, top, isCheck, underlyingType) { irNull() }
                 }
                 else -> {
                     return transformed
@@ -170,7 +161,7 @@
         return super.visitTypeOperator(expression)
     }
 
-    private fun generateAsCheck(
+    private fun generateAsCheckForSealedInlineClass(
         currentScopeSymbol: IrSymbol,
         expression: IrTypeOperatorCall,
         top: IrClass,
@@ -184,18 +175,14 @@
                 +irIfNull(
                     expression.type, irGet(tmp), onFail(),
                     irBlock {
-                        val unboxedTmp = irTemporary(coerceInlineClasses(irGet(tmp), top.defaultType, context.irBuiltIns.anyNType))
+                        val unboxedTmp = irTemporary(coerceFromSealedInlineClass(top, irGet(tmp)))
                         +irWhen(
                             expression.type, listOf(
                                 irBranch(
                                     irCall(isCheck.symbol).also { it.putValueArgument(0, irGet(unboxedTmp)) },
-                                    coerceInlineClasses(
-                                        irImplicitCast(irGet(unboxedTmp), underlyingType),
-                                        underlyingType,
-                                        expression.typeOperand
-                                    )
+                                    coerceInlineClasses(irGet(unboxedTmp), underlyingType, expression.typeOperand)
                                 ),
-                                irBranch(irTrue(), onFail())
+                                irElseBranch(onFail())
                             )
                         )
                     }
@@ -204,6 +191,12 @@
         }
     }
 
+    /* For `is` and `as` checks, we cannot use INSTANCEOF and CHECKCAST, since the underlying type of inline child can be `Any`
+     * instead, we check, whether it is not noinline first, and then use INSTANCEOF underlying type. Since we do not want to generate
+     * these switch-cases for each `is` and `as` check, we generate is-<Child> methods, which we call in `is` and `as` checks.
+     *
+     * These methods we generate only for inline subclasses, for noinline subclasses we simply use INSTANCEOF.
+     */
     private fun buildIsMethodsForSealedInlineClass(info: SealedInlineClassInfo) {
         for (childInfo in info.inlineSubclasses + info.sealedInlineSubclasses.dropLast(1)) {
             val child = childInfo.owner
@@ -225,18 +218,12 @@
 
                     for (noinline in info.noinlineSubclasses) {
                         branches += irBranch(
-                            irIs(
-                                coerceInlineClasses(param(), context.irBuiltIns.anyNType, info.top.defaultType),
-                                noinline.owner.defaultType
-                            ),
+                            irIs(coerceToSealedInlineClass(param(), info.top), noinline.owner.defaultType),
                             irReturn(irFalse())
                         )
                     }
 
-                    branches += irBranch(
-                        irTrue(),
-                        irReturn(irIs(param(), underlyingType))
-                    )
+                    branches += irElseBranch(irReturn(irIs(param(), underlyingType)))
 
                     +irReturn(irWhen(context.irBuiltIns.booleanType, branches))
                 }
@@ -457,7 +444,7 @@
             }
             irExprBody(
                 if (returnBoxedSealedInlineClass) {
-                    coerceInlineClasses(call, context.irBuiltIns.anyNType, source.returnType)
+                    coerceToSealedInlineClass(call, source.returnType.getClass()!!)
                 } else {
                     call
                 }
@@ -692,37 +679,22 @@
                     if (left.type.isInlineChildOfSealedInlineClass()) left.type.findTopSealedInlineSuperClass()
                     else left.type.classOrNull!!.owner
 
-                val rightVar = if (
-                    right.type.isNoinlineChildOfSealedInlineClass() || right.type.isInlineChildOfSealedInlineClass() ||
-                    right.type.classOrNull?.owner?.modality == Modality.SEALED
-                ) {
-                    val rightTop =
-                        if (right.type.classOrNull?.owner?.modality == Modality.SEALED) right.type.classOrNull!!.owner
-                        else right.type.findTopSealedInlineSuperClass()
-
-                    irTemporary(
-                        coerceInlineClasses(
-                            irImplicitCast(right, context.irBuiltIns.anyNType),
-                            rightTop.defaultType,
-                            context.irBuiltIns.anyNType,
-                        )
-                    )
-                } else {
-                    irTemporary(right)
-                }
+                val rightVar = irTemporary(
+                    if (right.type.classOrNull?.owner?.let { it.modality == Modality.SEALED || it.isChildOfSealedInlineClass() } == true)
+                        coerceFromSealedInlineClass(right.type.findTopSealedInlineSuperClass(), right)
+                    else right
+                )
 
                 val leftVar: IrVariable
-                val equalsMethod = if (rightIsUnboxed || right.type.isNoinlineChildOfSealedInlineClass()) {
-                    leftVar = irTemporary(
-                        coerceInlineClasses(
-                            left, leftTop.defaultType, context.irBuiltIns.anyNType,
-                        )
-                    )
-                    this@JvmInlineClassLowering.context.inlineClassReplacements.getSpecializedEqualsMethod(leftTop, context.irBuiltIns)
+                val equalsMethod: IrSimpleFunction
+                if (rightIsUnboxed || right.type.isNoinlineChildOfSealedInlineClass()) {
+                    leftVar = irTemporary(coerceFromSealedInlineClass(leftTop, left))
+                    equalsMethod =
+                        this@JvmInlineClassLowering.context.inlineClassReplacements.getSpecializedEqualsMethod(leftTop, context.irBuiltIns)
                 } else {
                     leftVar = irTemporary(left)
                     val equals = leftTop.functions.single { it.name.asString() == "equals" && it.overriddenSymbols.isNotEmpty() }
-                    this@JvmInlineClassLowering.context.inlineClassReplacements.getReplacementFunction(equals)!!
+                    equalsMethod = this@JvmInlineClassLowering.context.inlineClassReplacements.getReplacementFunction(equals)!!
                 }
 
                 +irCall(equalsMethod).apply {
@@ -777,15 +749,9 @@
                     val equals = this@JvmInlineClassLowering.context.inlineClassReplacements.getSpecializedEqualsMethod(
                         top, context.irBuiltIns
                     )
-                    val leftVar = irTemporary(
-                        coerceInlineClasses(left, top.defaultType, context.irBuiltIns.anyNType)
-                    )
-                    val rightVal = irTemporary(
-                        coerceInlineClasses(right, top.defaultType, context.irBuiltIns.anyNType)
-                    )
                     +irCall(equals).also {
-                        it.putValueArgument(0, irGet(leftVar))
-                        it.putValueArgument(1, irGet(rightVal))
+                        it.putValueArgument(0, coerceFromSealedInlineClass(top, left))
+                        it.putValueArgument(1, coerceFromSealedInlineClass(top, right))
                     }
                 } else {
                     val equals = this@JvmInlineClassLowering.context.inlineClassReplacements.getReplacementFunction(
@@ -976,52 +942,7 @@
     private fun rewriteOpenAndAbstractMethodsForSealed(info: SealedInlineClassInfo) {
         for ((methodSymbol, retargets, addToClass) in info.methods) {
             if (methodSymbol.owner.isEquals(context)) {
-                val function = replacements.getReplacementFunction(methodSymbol.owner)!!
-                val equals = context.inlineClassReplacements.getSpecializedEqualsMethod(info.top, context.irBuiltIns)
-
-                with(context.createIrBuilder(function.symbol)) {
-                    function.body = irBlockBody {
-                        +irReturn(
-                            irWhen(
-                                context.irBuiltIns.booleanType, listOf(
-                                    irBranch(irIs(irGet(function.valueParameters[1]), info.top.defaultType),
-                                             irBlock {
-                                                 val left = irTemporary(
-                                                     coerceInlineClasses(
-                                                         irGet(function.valueParameters[0]),
-                                                         info.top.defaultType,
-                                                         context.irBuiltIns.anyNType,
-                                                     )
-                                                 )
-                                                 val right = irTemporary(
-                                                     coerceInlineClasses(
-                                                         irGet(function.valueParameters[1]),
-                                                         info.top.defaultType,
-                                                         context.irBuiltIns.anyNType,
-                                                     )
-                                                 )
-                                                 +irCall(equals).also {
-                                                     it.putValueArgument(0, irGet(left))
-                                                     it.putValueArgument(1, irGet(right))
-                                                 }
-                                             }
-                                    ),
-                                    irBranch(irTrue(), irFalse())
-                                )
-                            )
-                        )
-                    }
-                }
-
-                // Replace fake override with generated function
-                val fakeOverride = info.top.functions.single {
-                    it.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT &&
-                            it.name.asString() == "equals-impl" && it.valueParameters.size == 2 &&
-                            it.valueParameters[0].type.classOrNull == info.top.symbol &&
-                            it.valueParameters[1].type == context.irBuiltIns.anyNType
-                }
-                info.top.declarations.remove(fakeOverride)
-                info.top.addMember(function)
+                generateEqualsMethodForSealedInlineClass(info.top, replacements.getReplacementFunction(methodSymbol.owner)!!)
 
                 continue
             }
@@ -1034,79 +955,29 @@
                 ) ?: error("Cannot find replacement for ${methodSymbol.owner.render()}")
             val oldBody = function.body
 
-            fun findFakeOverrideOfInterfaceMethod(): IrSimpleFunction? = info.top.functions.find {
-                it.isFakeOverride &&
-                        replacements.getSealedInlineClassChildFunctionInTop(info.top to it.withoutReceiver()).symbol == methodSymbol
-            }
-
             with(context.createIrBuilder(function.symbol)) {
                 function.body = irBlockBody {
-                    var counter = 0
                     fun copyOldBody() = when (oldBody) {
-                        is IrExpressionBody -> irReturn(oldBody.expression.deepCopySavingMetadata())
+                        is IrExpressionBody -> irReturn(oldBody.expression.deepCopySavingMetadata(function))
                         is IrBlockBody -> irBlock {
                             for (stmt in oldBody.statements) {
-                                +stmt.deepCopySavingMetadata()
+                                +stmt.deepCopySavingMetadata(function)
                             }
                         }
+
                         null -> {
-                            var expression: IrExpression? = null
-                            if (methodSymbol.owner.origin == JvmLoweredDeclarationOrigin.GENERATED_SEALED_INLINE_CLASS_METHOD) {
-                                val fakeOverride = findFakeOverrideOfInterfaceMethod()
-                                if (fakeOverride != null) {
-                                    val defaultMethod = fakeOverride.overriddenSymbols.find {
-                                        it.owner.parentAsClass.isInterface && it.owner.modality != Modality.ABSTRACT
+                            callDefaultMethodOfSealedInlineClassSuperinterface(info.top, methodSymbol, function)
+                                ?: irThrow(
+                                    irCall(this@JvmInlineClassLowering.context.ir.symbols.illegalStateExceptionCtorString).apply {
+                                        putValueArgument(0, irString("Invalid sealed inline class method call"))
                                     }
-                                    if (defaultMethod != null) {
-                                        val callDefaultImpls = this@JvmInlineClassLowering.context.state.jvmDefaultMode
-                                            .let { it.isEnabled && !it.forAllMethodsWithBody }
-                                        if (callDefaultImpls) {
-                                            val defaultImplsMethod =
-                                                this@JvmInlineClassLowering.context.cachedDeclarations
-                                                    .getDefaultImplsFunction(defaultMethod.owner)
-                                            expression = irCall(defaultImplsMethod.symbol).also {
-                                                for ((target, source) in defaultImplsMethod.explicitParameters
-                                                    .zip(function.explicitParameters)
-                                                ) {
-                                                    it.putArgument(target, irGet(source))
-                                                }
-                                            }
-                                        } else {
-                                            expression = IrCallImpl(
-                                                UNDEFINED_OFFSET, UNDEFINED_OFFSET,
-                                                defaultMethod.owner.returnType,
-                                                defaultMethod,
-                                                defaultMethod.owner.valueParameters.size,
-                                                defaultMethod.owner.typeParameters.size,
-                                                null,
-                                                defaultMethod.owner.parentAsClass.symbol
-                                            ).also {
-                                                it.dispatchReceiver = irImplicitCast(
-                                                    irGet(function.valueParameters[0]), defaultMethod.owner.parentAsClass.defaultType
-                                                )
-                                                for ((target, source) in defaultMethod.owner.explicitParameters
-                                                    .zip(function.explicitParameters).drop(1)
-                                                ) {
-                                                    it.putArgument(target, irGet(source))
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                            expression ?: irThrow(
-                                irCall(this@JvmInlineClassLowering.context.ir.symbols.illegalStateExceptionCtorString).also {
-                                    it.putValueArgument(0, irString("${counter++}"))
-                                }
-                            )
+                                )
                         }
+
                         else -> error("oldBody is not a function body: ${oldBody.dump()}")
                     }
 
-                    val receiver = irTemporary(
-                        coerceInlineClasses(irGet(function.valueParameters[0]), info.top.defaultType, context.irBuiltIns.anyNType),
-                        "anyN_receiver"
-                    )
+                    val receiver = irTemporary(coerceFromSealedInlineClass(info.top, irGet(function.valueParameters[0])))
 
                     val branches = mutableListOf<IrBranch>()
 
@@ -1154,18 +1025,14 @@
                             irBranch(
                                 irIs(irGet(receiver), underlyingType),
                                 if (retargetClass.symbol == info.top.symbol) copyOldBody()
-                                else irReturn(irCall(toCall).apply {
+                                else irCall(toCall).apply {
                                     putValueArgument(
-                                        0, coerceInlineClasses(
-                                            irImplicitCast(irGet(receiver), underlyingType),
-                                            underlyingType,
-                                            inlineSubclass.owner.defaultType
-                                        )
+                                        0, coerceInlineClasses(irGet(receiver), underlyingType, inlineSubclass.owner.defaultType)
                                     )
                                     for ((target, source) in toCall.owner.explicitParameters.zip(function.explicitParameters).drop(1)) {
                                         putArgument(target, irGet(source))
                                     }
-                                })
+                                }
                             )
                     }
 
@@ -1175,95 +1042,173 @@
                         retarget = replacements.getReplacementFunction(retarget.owner)?.symbol
                     }
 
-                    if (retarget != null) {
-                        branches += irBranch(
-                            irTrue(),
-                            if (retarget.owner.parentAsClass.symbol == info.top.symbol) copyOldBody()
-                            else irReturn(irCall(retarget).apply {
-                                putValueArgument(
-                                    0, coerceInlineClasses(
-                                        irImplicitCast(irGet(receiver), context.irBuiltIns.anyNType),
-                                        context.irBuiltIns.anyNType,
-                                        sealedInlineSubclass.owner.defaultType.findTopSealedInlineSuperClass().defaultType
-                                    )
-                                )
+                    branches += irElseBranch(
+                        if (retarget != null && retarget.owner.parentAsClass.symbol != info.top.symbol) {
+                            irCall(retarget).apply {
+                                putValueArgument(0, coerceToSealedInlineClass(irGet(receiver), info.top))
                                 for ((target, source) in retarget.owner.explicitParameters.zip(function.explicitParameters).drop(1)) {
                                     putArgument(target, irGet(source))
                                 }
-                            })
-                        )
-                    } else {
-                        branches += irBranch(irTrue(), copyOldBody())
-                    }
+                            }
+                        } else {
+                            copyOldBody()
+                        }
+                    )
 
                     +irReturn(irWhen(function.returnType, branches))
                 }
             }
 
             if (addToClass) {
-                if (methodSymbol.owner.modality != Modality.ABSTRACT) {
-                    info.top.addMember(function)
-                }
+//                info.top.addFunctionToSealedInlineClass(methodSymbol, function, retargets)
+            }
+        }
+    }
 
-                val allOverridden = retargets
-                    .flatMap { (_, retarget) -> retarget.owner.allOverridden() }
-                    .toSet()
+    fun IrClass.addFunctionToSealedInlineClass(
+        methodSymbol: IrSimpleFunctionSymbol,
+        function: IrSimpleFunction,
+        retargets: Map<IrClassSymbol, IrSimpleFunctionSymbol>
+    ) {
+        if (methodSymbol.owner.modality != Modality.ABSTRACT) {
+            addMember(function)
+        }
 
-                if (retargets.any { (_, retarget) ->
-                        retarget.owner.parentAsClass.let { it.isInline && it.modality == Modality.SEALED }
-                    } || allOverridden.any { it.parentAsClass.isInterface }
-                ) {
-                    val bridge = context.irFactory.buildFun {
-                        updateFrom(methodSymbol.owner)
-                        origin = methodSymbol.owner.origin
-                        modality = Modality.OPEN
-                        name = methodSymbol.owner.name
-                        returnType = methodSymbol.owner.returnType
-                    }.apply {
-                        copyParameterDeclarationsFrom(methodSymbol.owner)
-                        annotations = methodSymbol.owner.annotations
-                        parent = info.top
+        val allOverridden = retargets
+            .flatMap { (_, retarget) -> retarget.owner.allOverridden() }
+            .toSet()
+
+        if (retargets.any { (_, retarget) ->
+                retarget.owner.parentAsClass.let { it.isInline && it.modality == Modality.SEALED }
+            } || allOverridden.any { it.parentAsClass.isInterface }
+        ) {
+            val bridge = context.irFactory.buildFun {
+                updateFrom(methodSymbol.owner)
+                origin = methodSymbol.owner.origin
+                modality = Modality.OPEN
+                name = methodSymbol.owner.name
+                returnType = methodSymbol.owner.returnType
+            }.apply {
+                copyParameterDeclarationsFrom(methodSymbol.owner)
+                annotations = methodSymbol.owner.annotations
+                parent = this
+            }
+            addMember(bridge)
+
+            val returnBoxed = bridge.returnType.isInlineClassType() && !bridge.returnType.isNullable() &&
+                    allOverridden.any {
+                        it.returnType.isNullable() || it.returnType.isAny() ||
+                                it.returnType.isNullableAny() || it.returnType.isTypeParameter()
                     }
-                    info.top.addMember(bridge)
 
-                    val returnBoxed = bridge.returnType.isInlineClassType() && !bridge.returnType.isNullable() &&
-                            allOverridden.any {
-                                it.returnType.isNullable() || it.returnType.isAny() ||
-                                        it.returnType.isNullableAny() || it.returnType.isTypeParameter()
+            createBridgeBody(bridge, function, returnBoxed)
+        }
+
+        for ((_, retarget) in retargets) {
+            val override = if (retarget.owner.origin != JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT) {
+                retarget.owner.overriddenSymbols += methodSymbol
+                replacements.getReplacementFunction(retarget.owner) ?: retarget.owner
+            } else retarget.owner
+
+            override.overriddenSymbols += function.symbol
+        }
+
+        // Remove fake overrides of default methods, we generated its replacement ourselves
+        if (methodSymbol.owner.origin == JvmLoweredDeclarationOrigin.GENERATED_SEALED_INLINE_CLASS_METHOD) {
+            val fakeOverride = findFakeOverrideOfInterfaceMethodInSealedInlineClass(methodSymbol)
+            if (fakeOverride != null && fakeOverride.allOverridden().any {
+                    it.parentAsClass.isInterface && it.modality != Modality.ABSTRACT
+                }) {
+                declarations.remove(fakeOverride)
+            }
+        }
+    }
+
+    fun IrClass.findFakeOverrideOfInterfaceMethodInSealedInlineClass(methodSymbol: IrSimpleFunctionSymbol): IrSimpleFunction? =
+        functions.find {
+            it.isFakeOverride && context.inlineClassReplacements
+                .getSealedInlineClassChildFunctionInTop(this to it.withoutReceiver()).symbol == methodSymbol
+        }
+
+    fun IrBuilderWithScope.callDefaultMethodOfSealedInlineClassSuperinterface(
+        top: IrClass,
+        methodSymbol: IrSimpleFunctionSymbol,
+        function: IrSimpleFunction
+    ): IrExpression? {
+        if (methodSymbol.owner.origin == JvmLoweredDeclarationOrigin.GENERATED_SEALED_INLINE_CLASS_METHOD) {
+            val fakeOverride = top.findFakeOverrideOfInterfaceMethodInSealedInlineClass(methodSymbol)
+            if (fakeOverride != null) {
+                val defaultMethod = fakeOverride.overriddenSymbols.find {
+                    it.owner.parentAsClass.isInterface && it.owner.modality != Modality.ABSTRACT
+                }
+                if (defaultMethod != null) {
+                    val callDefaultImpls = this@JvmInlineClassLowering.context.state.jvmDefaultMode
+                        .let { it.isEnabled && !it.forAllMethodsWithBody }
+                    if (callDefaultImpls) {
+                        val defaultImplsMethod =
+                            this@JvmInlineClassLowering.context.cachedDeclarations
+                                .getDefaultImplsFunction(defaultMethod.owner)
+                        return irCall(defaultImplsMethod.symbol).apply {
+                            for ((target, source) in defaultImplsMethod.explicitParameters.zip(function.explicitParameters)) {
+                                putArgument(target, irGet(source))
                             }
-
-                    createBridgeBody(bridge, function, returnBoxed)
-                }
-
-                for ((_, retarget) in retargets) {
-                    val override = if (retarget.owner.origin != JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT) {
-                        retarget.owner.overriddenSymbols += methodSymbol
-                        replacements.getReplacementFunction(retarget.owner) ?: retarget.owner
-                    } else retarget.owner
-
-                    override.overriddenSymbols += function.symbol
-                }
-
-                // Remove fake overrides of default methods, we generated its replacement ourselves
-                if (methodSymbol.owner.origin == JvmLoweredDeclarationOrigin.GENERATED_SEALED_INLINE_CLASS_METHOD) {
-                    val fakeOverride = findFakeOverrideOfInterfaceMethod()
-                    if (fakeOverride != null && fakeOverride.allOverridden().any {
-                            it.parentAsClass.isInterface && it.modality != Modality.ABSTRACT
-                    }) {
-                        info.top.declarations.remove(fakeOverride)
+                        }
+                    } else {
+                        return irCall(defaultMethod).apply {
+                            dispatchReceiver = irGet(function.valueParameters[0])
+                            for ((target, source) in defaultMethod.owner.explicitParameters.zip(function.explicitParameters).drop(1)) {
+                                putArgument(target, irGet(source))
+                            }
+                        }
                     }
                 }
             }
         }
+        return null
     }
 
+    /* The equals function for sealed inline classes looks like
+     * (given the class is named Top)
+     *
+     * fun equals(other: Any?) =
+     *   other is Top && equal-impl0(this.$value, other.$value)
+     */
+    private fun generateEqualsMethodForSealedInlineClass(top: IrClass, function: IrSimpleFunction) {
+        val equals = context.inlineClassReplacements.getSpecializedEqualsMethod(top, context.irBuiltIns)
+
+        with(context.createIrBuilder(function.symbol)) {
+            function.body = irExprBody(irAndand(
+                irIs(irGet(function.valueParameters[1]), top.defaultType),
+                irCall(equals).apply {
+                    putValueArgument(0, coerceFromSealedInlineClass(top, irGet(function.valueParameters[0])))
+                    putValueArgument(1, coerceFromSealedInlineClass(top, irGet(function.valueParameters[1])))
+                }
+            ))
+        }
+
+        // Replace fake override with generated function
+        val fakeOverride = top.functions.single {
+            it.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT &&
+                    it.name.asString() == "equals-impl" && it.valueParameters.size == 2 &&
+                    it.valueParameters[0].type.classOrNull == top.symbol &&
+                    it.valueParameters[1].type == context.irBuiltIns.anyNType
+        }
+        top.declarations.remove(fakeOverride)
+        top.addMember(function)
+    }
+
+    private fun coerceFromSealedInlineClass(top: IrClass, expr: IrExpression): IrExpression =
+        coerceInlineClasses(expr, top.defaultType, context.irBuiltIns.anyNType)
+
+    private fun coerceToSealedInlineClass(expr: IrExpression, top: IrClass): IrExpression =
+        coerceInlineClasses(expr, context.irBuiltIns.anyNType, top.defaultType)
+
     private fun buildUnboxFunction(irClass: IrClass) {
         val function = context.inlineClassReplacements.getUnboxFunction(irClass)
         val field = getInlineClassBackingField(irClass)
 
-        function.body = context.createIrBuilder(function.symbol).irBlockBody {
-            val thisVal = irGet(function.dispatchReceiverParameter!!)
-            +irReturn(irGetField(thisVal, field))
+        function.body = with(context.createIrBuilder(function.symbol)) {
+            irExprBody(irGetField(irGet(function.dispatchReceiverParameter!!), field))
         }
 
         irClass.declarations += function
@@ -1275,7 +1220,7 @@
         val right = function.valueParameters[1]
         val type = left.type.unboxInlineClass()
 
-        function.body = context.createIrBuilder(valueClass.symbol).run {
+        function.body = with(context.createIrBuilder(valueClass.symbol)) {
             irExprBody(
                 irEquals(
                     coerceInlineClasses(irGet(left), left.type, type),
@@ -1287,83 +1232,76 @@
         valueClass.declarations += function
     }
 
+    /* For sealed inline classes, inside `equals-impl0` we check for types of parameters and then call respective `equals` of `equals-impl0`
+     * functions.
+     *
+     * For example, given the code
+     *
+     * @JvmInline
+     * sealed value class Top {
+     *   @JvmInline
+     *   value class I(val i: Int)
+     *   @JvmInline
+     *   value class L(val l: Long)
+     *
+     *   value class S(...)
+     * }
+     *
+     * First, we generate checks for noinline subclasses, and then for inline ones.
+     * For noinline classes we just generate reference equals, since we do not support user-defined equals for value classes yet.
+     *
+     * So, we generate the following function
+     *
+     * static fun Top.equals-impl0($this: Any?, other: Any?): Boolean = when {
+     *   $this is S -> $this === other
+     *   $this is Int && other is Int -> I.equals-impl0($this as Int?, other as Int?)
+     *   $this is Long && other is Long -> L.equals-impl0($this as Long?, other as Long?)
+     *   else -> false
+     * }
+     */
     private fun buildSpecializedEqualsMethodForSealed(info: SealedInlineClassInfo) {
         val irClass = info.top
         val inlineSubclasses = info.inlineSubclasses
         val noinlineSubclasses = info.noinlineSubclasses
 
-        val boolAnd = context.ir.symbols.getBinaryOperator(
-            OperatorNameConventions.AND, context.irBuiltIns.booleanType, context.irBuiltIns.booleanType
-        )
-
         val function = context.inlineClassReplacements.getSpecializedEqualsMethod(irClass, context.irBuiltIns)
 
         with(context.createIrBuilder(function.symbol)) {
             function.body = irBlockBody {
                 val left = irTemporary(
-                    coerceInlineClasses(
-                        irGet(function.valueParameters[0]),
-                        this@JvmInlineClassLowering.context.irBuiltIns.anyNType,
-                        irClass.defaultType
-                    )
+                    coerceToSealedInlineClass(irGet(function.valueParameters[0]), irClass)
                 )
 
                 val right = irTemporary(
-                    coerceInlineClasses(
-                        irGet(function.valueParameters[1]),
-                        this@JvmInlineClassLowering.context.irBuiltIns.anyNType,
-                        irClass.defaultType
-                    )
+                    coerceToSealedInlineClass(irGet(function.valueParameters[1]), irClass)
                 )
 
                 val branches = mutableListOf<IrBranch>()
 
                 for (noinlineSubclass in noinlineSubclasses) {
                     branches += irBranch(
-                        irCallOp(
-                            boolAnd, context.irBuiltIns.booleanType,
-                            irIs(irGet(left), noinlineSubclass.owner.defaultType),
-                            irIs(irGet(right), noinlineSubclass.owner.defaultType),
-                        ),
-                        // TODO: Revisit, when we will support user-defined equals.
-                        irReturn(irTrue())
+                        irIs(irGet(left), noinlineSubclass.owner.defaultType),
+                        irEqeqeq(irGet(left), irGet(right))
                     )
                 }
 
                 for (inlineSubclass in inlineSubclasses) {
-                    val unboxedLeft = coerceInlineClasses(
-                        irGet(left),
-                        irClass.defaultType,
-                        this@JvmInlineClassLowering.context.irBuiltIns.anyNType,
-                    )
-                    val unboxedRight = coerceInlineClasses(
-                        irGet(right),
-                        irClass.defaultType,
-                        this@JvmInlineClassLowering.context.irBuiltIns.anyNType,
-                    )
                     val eq = this@JvmInlineClassLowering.context.inlineClassReplacements
                         .getSpecializedEqualsMethod(inlineSubclass.owner, context.irBuiltIns)
-                    val underlyingType = getInlineClassUnderlyingType(inlineSubclass.owner)
+                    val underlyingType = context.irBuiltIns.getInlineClassUnderlyingType(inlineSubclass.owner)
                     branches += irBranch(
-                        irCallOp(
-                            boolAnd, context.irBuiltIns.booleanType,
-                            irIs(unboxedLeft, underlyingType),
-                            irIs(unboxedRight, underlyingType),
+                        irAndand(
+                            irIs(irGet(function.valueParameters[0]), underlyingType),
+                            irIs(irGet(function.valueParameters[1]), underlyingType)
                         ),
-                        irReturn(
-                            irCall(eq).apply {
-                                putValueArgument(
-                                    0, irImplicitCast(irGet(left), underlyingType)
-                                )
-                                putValueArgument(
-                                    1, irImplicitCast(irGet(right), underlyingType)
-                                )
-                            }
-                        )
+                        irCall(eq).apply {
+                            putValueArgument(0, irGet(left))
+                            putValueArgument(1, irGet(right))
+                        }
                     )
                 }
 
-                branches += irBranch(irTrue(), irReturn(irFalse()))
+                branches += irElseBranch(irFalse())
 
                 +irReturn(irWhen(context.irBuiltIns.booleanType, branches))
             }
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt
index 37e1f1f..c162f3c 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/indy/LambdaMetafactoryArguments.kt
@@ -578,7 +578,7 @@
         if (erasedAdapteeClass.isSingleFieldValueClass) {
             // Inline classes mapped to non-null reference types are a special case because they can't be boxed trivially.
             // TODO consider adding a special type annotation to force boxing on an inline class type regardless of its underlying type.
-            val underlyingAdapteeType = getInlineClassUnderlyingType(erasedAdapteeClass)
+            val underlyingAdapteeType = context.irBuiltIns.getInlineClassUnderlyingType(erasedAdapteeClass)
             if (!underlyingAdapteeType.isNullable() && !underlyingAdapteeType.isPrimitiveType()) {
                 return TypeAdaptationConstraint.CONFLICT
             }
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedInlineClassReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedInlineClassReplacements.kt
index 0f4ddc0..be457cb 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedInlineClassReplacements.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedInlineClassReplacements.kt
@@ -5,7 +5,6 @@
 
 package org.jetbrains.kotlin.backend.jvm
 
-import org.jetbrains.kotlin.backend.common.BackendContext
 import org.jetbrains.kotlin.backend.jvm.ir.*
 import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
 import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
@@ -153,9 +152,7 @@
                 copyTypeParametersFrom(irClass)
                 addValueParameter {
                     name = InlineClassDescriptorResolver.BOXING_VALUE_PARAMETER_NAME
-                    type =
-                        if (irClass.modality == Modality.SEALED) context.irBuiltIns.anyNType
-                        else getInlineClassUnderlyingType(irClass)
+                    type = context.irBuiltIns.getInlineClassUnderlyingType(irClass)
                 }
             }
         }
@@ -170,9 +167,7 @@
             irFactory.buildFun {
                 name = Name.identifier(KotlinTypeMapper.UNBOX_JVM_METHOD_NAME)
                 origin = JvmLoweredDeclarationOrigin.SYNTHETIC_INLINE_CLASS_MEMBER
-                returnType =
-                    if (irClass.modality == Modality.SEALED) context.irBuiltIns.anyNType
-                    else getInlineClassUnderlyingType(irClass)
+                returnType = context.irBuiltIns.getInlineClassUnderlyingType(irClass)
                 if (irClass.modality == Modality.SEALED) {
                     modality = Modality.OPEN
                 }
@@ -257,18 +252,18 @@
             }.apply {
                 parent = irClass
                 // We ignore type arguments here, since there is no good way to go from type arguments to types in the IR anyway.
-                val typeArgument =
+                val argumentType =
                     if (irClass.modality == Modality.SEALED) context.irBuiltIns.anyNType
                     else IrSimpleTypeImpl(
                         irClass.symbol, false, List(irClass.typeParameters.size) { IrStarProjectionImpl }, listOf()
                     )
                 addValueParameter {
                     name = InlineClassDescriptorResolver.SPECIALIZED_EQUALS_FIRST_PARAMETER_NAME
-                    type = typeArgument
+                    type = argumentType
                 }
                 addValueParameter {
                     name = InlineClassDescriptorResolver.SPECIALIZED_EQUALS_SECOND_PARAMETER_NAME
-                    type = typeArgument
+                    type = argumentType
                 }
             }
         }
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt
index d9e0920..3fab431 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt
@@ -161,6 +161,9 @@
 fun IrBuilderWithScope.irEqeqeq(arg1: IrExpression, arg2: IrExpression) =
     context.eqeqeq(startOffset, endOffset, arg1, arg2)
 
+fun IrBuilderWithScope.irAndand(arg1: IrExpression, arg2: IrExpression) =
+    context.andand(startOffset, endOffset, arg1, arg2)
+
 fun IrBuilderWithScope.irNull() =
     irNull(context.irBuiltIns.nothingNType)
 
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt
index 91479a3..f118084 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt
@@ -5,15 +5,17 @@
 
 package org.jetbrains.kotlin.ir.util
 
+import org.jetbrains.kotlin.descriptors.Modality
+import org.jetbrains.kotlin.ir.IrBuiltIns
 import org.jetbrains.kotlin.ir.declarations.IrClass
 import org.jetbrains.kotlin.ir.declarations.IrField
 import org.jetbrains.kotlin.ir.declarations.IrProperty
 import org.jetbrains.kotlin.ir.declarations.inlineClassRepresentation
-import org.jetbrains.kotlin.ir.types.IrSimpleType
+import org.jetbrains.kotlin.ir.types.IrType
 
-fun getInlineClassUnderlyingType(irClass: IrClass): IrSimpleType {
+fun IrBuiltIns.getInlineClassUnderlyingType(irClass: IrClass): IrType {
     val representation = irClass.inlineClassRepresentation ?: error("Not an inline class: ${irClass.render()}")
-    return representation.underlyingType
+    return if (irClass.modality == Modality.SEALED) anyNType else representation.underlyingType
 }
 
 fun getInlineClassBackingField(irClass: IrClass): IrField {
diff --git a/compiler/testData/diagnostics/tests/inlineClasses/inlineClassDeclarationCheck.fir.kt b/compiler/testData/diagnostics/tests/inlineClasses/inlineClassDeclarationCheck.fir.kt
index 5ad1a24..95ccb21 100644
--- a/compiler/testData/diagnostics/tests/inlineClasses/inlineClassDeclarationCheck.fir.kt
+++ b/compiler/testData/diagnostics/tests/inlineClasses/inlineClassDeclarationCheck.fir.kt
@@ -35,6 +35,6 @@
 final inline class D0(val x: Int)
 <!VALUE_CLASS_NOT_FINAL!>open<!> inline class D1(val x: Int)
 <!VALUE_CLASS_NOT_FINAL!>abstract<!> inline class D2(val x: Int)
-<!VALUE_CLASS_NOT_FINAL!>sealed<!> inline class D3(val x: Int)
+<!UNSUPPORTED_FEATURE!>sealed<!> inline class D3(val x: Int)
 
 <!INCOMPATIBLE_MODIFIERS!>inline<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class D4(val x: String)
diff --git a/compiler/testData/diagnostics/tests/inlineClasses/inlineClassDeclarationCheck.kt b/compiler/testData/diagnostics/tests/inlineClasses/inlineClassDeclarationCheck.kt
index 224c5c1..69d83da 100644
--- a/compiler/testData/diagnostics/tests/inlineClasses/inlineClassDeclarationCheck.kt
+++ b/compiler/testData/diagnostics/tests/inlineClasses/inlineClassDeclarationCheck.kt
@@ -35,6 +35,6 @@
 final inline class D0(val x: Int)
 <!VALUE_CLASS_NOT_FINAL!>open<!> inline class D1(val x: Int)
 <!VALUE_CLASS_NOT_FINAL!>abstract<!> inline class D2(val x: Int)
-<!VALUE_CLASS_NOT_FINAL!>sealed<!> <!SEALED_INLINE_CLASS_WRONG_MODIFIER!>inline<!> class D3(val x: Int)
+<!UNSUPPORTED_FEATURE!>sealed<!> <!SEALED_INLINE_CLASS_WRONG_MODIFIER!>inline<!> class D3(val x: Int)
 
 <!INCOMPATIBLE_MODIFIERS!>inline<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class <!CONFLICTING_JVM_DECLARATIONS, CONFLICTING_JVM_DECLARATIONS, CONFLICTING_JVM_DECLARATIONS!>D4(val x: String)<!>
diff --git a/compiler/testData/diagnostics/tests/inlineClasses/sealed-inline-class/with-value.fir.kt b/compiler/testData/diagnostics/tests/inlineClasses/sealed-inline-class/with-value.fir.kt
index 025b593..4b54c82 100644
--- a/compiler/testData/diagnostics/tests/inlineClasses/sealed-inline-class/with-value.fir.kt
+++ b/compiler/testData/diagnostics/tests/inlineClasses/sealed-inline-class/with-value.fir.kt
@@ -6,4 +6,4 @@
 annotation class JvmInline
 
 @JvmInline
-sealed <!SEALED_INLINE_CLASS_WITH_UNDERLYING_VALUE!>value<!> class Result(val value: Any)
+sealed <!SEALED_INLINE_CLASS_WITH_PRIMARY_CONSTRUCTOR!>value<!> class Result(val value: Any)
diff --git a/compiler/testData/diagnostics/tests/inlineClasses/sealed-inline-class/with-value.kt b/compiler/testData/diagnostics/tests/inlineClasses/sealed-inline-class/with-value.kt
index 1e5220c..07112c8 100644
--- a/compiler/testData/diagnostics/tests/inlineClasses/sealed-inline-class/with-value.kt
+++ b/compiler/testData/diagnostics/tests/inlineClasses/sealed-inline-class/with-value.kt
@@ -6,4 +6,4 @@
 annotation class JvmInline
 
 @JvmInline
-sealed value class Result<!SEALED_INLINE_CLASS_WITH_UNDERLYING_VALUE!>(val value: Any)<!>
+sealed value class Result<!SEALED_INLINE_CLASS_WITH_PRIMARY_CONSTRUCTOR!>(val value: Any)<!>
diff --git a/compiler/testData/diagnostics/tests/valueClasses/sealedValueClass.kt b/compiler/testData/diagnostics/tests/valueClasses/sealedValueClass.kt
index efb6668..b1bc92f 100644
--- a/compiler/testData/diagnostics/tests/valueClasses/sealedValueClass.kt
+++ b/compiler/testData/diagnostics/tests/valueClasses/sealedValueClass.kt
@@ -2,4 +2,4 @@
 // !SKIP_JAVAC
 // !LANGUAGE: -SealedInlineClasses
 
-<!VALUE_CLASS_NOT_FINAL!>sealed<!> <!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class SVC
+<!UNSUPPORTED_FEATURE!>sealed<!> <!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class SVC
diff --git a/compiler/testData/diagnostics/tests/valueClasses/valueClassDeclarationCheck.kt b/compiler/testData/diagnostics/tests/valueClasses/valueClassDeclarationCheck.kt
index ecfec1b..ed47380 100644
--- a/compiler/testData/diagnostics/tests/valueClasses/valueClassDeclarationCheck.kt
+++ b/compiler/testData/diagnostics/tests/valueClasses/valueClassDeclarationCheck.kt
@@ -48,6 +48,6 @@
 final value class D0(val x: Int)
 <!VALUE_CLASS_NOT_FINAL!>open<!> <!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class D1(val x: Int)
 <!VALUE_CLASS_NOT_FINAL!>abstract<!> <!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class D2(val x: Int)
-<!VALUE_CLASS_NOT_FINAL!>sealed<!> <!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class D3(val x: Int)
+<!UNSUPPORTED_FEATURE!>sealed<!> <!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class D3(val x: Int)
 
 <!INCOMPATIBLE_MODIFIERS, VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class D4(val x: String)