diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionTypeProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionTypeProvider.kt
index 6f8d1b0cdba..f5336ceb90f 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionTypeProvider.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirExpressionTypeProvider.kt
@@ -6,21 +6,6 @@
package org.jetbrains.kotlin.analysis.api.fir.components
import com.intellij.psi.PsiElement
-import org.jetbrains.kotlin.fir.FirLabel
-import org.jetbrains.kotlin.fir.FirPackageDirective
-import org.jetbrains.kotlin.fir.declarations.*
-import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
-import org.jetbrains.kotlin.fir.expressions.*
-import org.jetbrains.kotlin.fir.psi
-import org.jetbrains.kotlin.fir.references.FirNamedReference
-import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
-import org.jetbrains.kotlin.fir.resolve.constructFunctionalType
-import org.jetbrains.kotlin.fir.typeContext
-import org.jetbrains.kotlin.fir.types.FirTypeRef
-import org.jetbrains.kotlin.fir.types.coneType
-import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
-import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType
-import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.api.components.KtExpressionTypeProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.utils.getReferencedElementType
@@ -29,6 +14,26 @@ import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtClassErrorType
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
+import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
+import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType
+import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
+import org.jetbrains.kotlin.fir.FirLabel
+import org.jetbrains.kotlin.fir.FirPackageDirective
+import org.jetbrains.kotlin.fir.declarations.*
+import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
+import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
+import org.jetbrains.kotlin.fir.expressions.*
+import org.jetbrains.kotlin.fir.psi
+import org.jetbrains.kotlin.fir.references.FirNamedReference
+import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
+import org.jetbrains.kotlin.fir.references.FirSuperReference
+import org.jetbrains.kotlin.fir.resolve.constructFunctionalType
+import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
+import org.jetbrains.kotlin.fir.typeContext
+import org.jetbrains.kotlin.fir.types.ConeIntersectionType
+import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
+import org.jetbrains.kotlin.fir.types.FirTypeRef
+import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -39,6 +44,21 @@ internal class KtFirExpressionTypeProvider(
override fun getKtExpressionType(expression: KtExpression): KtType? = withValidityAssertion {
when (val fir = expression.unwrap().getOrBuildFir(firResolveState)) {
+ is FirPropertyAccessExpression -> {
+ // For unresolved `super`, we manually create an intersection type so that IDE features like completion can work correctly.
+ val containingClass =
+ (fir.dispatchReceiver as? FirThisReceiverExpression)?.calleeReference?.boundSymbol as? FirClassSymbol<*>
+ if (fir.calleeReference is FirSuperReference && fir.typeRef is FirErrorTypeRef && containingClass != null) {
+ val superTypes = containingClass.superConeTypes
+ when (superTypes.size) {
+ 0 -> analysisSession.builtinTypes.ANY
+ 1 -> superTypes.single().asKtType()
+ else -> ConeIntersectionType(superTypes).asKtType()
+ }
+ } else {
+ fir.typeRef.coneType.asKtType()
+ }
+ }
is FirExpression -> fir.typeRef.coneType.asKtType()
is FirNamedReference -> fir.getReferencedElementType(firResolveState).asKtType()
is FirStatement -> with(analysisSession) { builtinTypes.UNIT }
diff --git a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/HLExpressionTypeTestGenerated.java b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/HLExpressionTypeTestGenerated.java
index 7251c17423a..702d5432c45 100644
--- a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/HLExpressionTypeTestGenerated.java
+++ b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/HLExpressionTypeTestGenerated.java
@@ -90,6 +90,12 @@ public class HLExpressionTypeTestGenerated extends AbstractHLExpressionTypeTest
runTest("analysis/analysis-api/testData/components/expressionType/property.kt");
}
+ @Test
+ @TestMetadata("resolvedSuper.kt")
+ public void testResolvedSuper() throws Exception {
+ runTest("analysis/analysis-api/testData/components/expressionType/resolvedSuper.kt");
+ }
+
@Test
@TestMetadata("returnExpression.kt")
public void testReturnExpression() throws Exception {
@@ -102,6 +108,24 @@ public class HLExpressionTypeTestGenerated extends AbstractHLExpressionTypeTest
runTest("analysis/analysis-api/testData/components/expressionType/stringLiteral.kt");
}
+ @Test
+ @TestMetadata("unresolvedSuper_multipleSuperTypes.kt")
+ public void testUnresolvedSuper_multipleSuperTypes() throws Exception {
+ runTest("analysis/analysis-api/testData/components/expressionType/unresolvedSuper_multipleSuperTypes.kt");
+ }
+
+ @Test
+ @TestMetadata("unresolvedSuper_noSuperType.kt")
+ public void testUnresolvedSuper_noSuperType() throws Exception {
+ runTest("analysis/analysis-api/testData/components/expressionType/unresolvedSuper_noSuperType.kt");
+ }
+
+ @Test
+ @TestMetadata("unresolvedSuper_singleSuperType.kt")
+ public void testUnresolvedSuper_singleSuperType() throws Exception {
+ runTest("analysis/analysis-api/testData/components/expressionType/unresolvedSuper_singleSuperType.kt");
+ }
+
@Test
@TestMetadata("whileExpression.kt")
public void testWhileExpression() throws Exception {
diff --git a/analysis/analysis-api/testData/components/expressionType/resolvedSuper.kt b/analysis/analysis-api/testData/components/expressionType/resolvedSuper.kt
new file mode 100644
index 00000000000..f4ea169dfe1
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionType/resolvedSuper.kt
@@ -0,0 +1,9 @@
+interface A {
+ fun foo() {}
+}
+
+class B : A {
+ fun test() {
+ super.foo()
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/expressionType/resolvedSuper.txt b/analysis/analysis-api/testData/components/expressionType/resolvedSuper.txt
new file mode 100644
index 00000000000..71ed2e6db70
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionType/resolvedSuper.txt
@@ -0,0 +1,2 @@
+expression: super
+type: A
diff --git a/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_multipleSuperTypes.kt b/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_multipleSuperTypes.kt
new file mode 100644
index 00000000000..e2b63ff5076
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_multipleSuperTypes.kt
@@ -0,0 +1,13 @@
+interface A {
+ fun foo() {}
+}
+
+interface B {
+ fun bar() {}
+}
+
+class C : A, B {
+ fun test() {
+ super.unresolved()
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_multipleSuperTypes.txt b/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_multipleSuperTypes.txt
new file mode 100644
index 00000000000..af0255678cd
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_multipleSuperTypes.txt
@@ -0,0 +1,2 @@
+expression: super
+type: (A&B)
diff --git a/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_noSuperType.kt b/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_noSuperType.kt
new file mode 100644
index 00000000000..92f56f8890f
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_noSuperType.kt
@@ -0,0 +1,5 @@
+class Foo {
+ fun test() {
+ super.unresolved()
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_noSuperType.txt b/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_noSuperType.txt
new file mode 100644
index 00000000000..abd5b7f18ba
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_noSuperType.txt
@@ -0,0 +1,2 @@
+expression: super
+type: kotlin.Any
diff --git a/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_singleSuperType.kt b/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_singleSuperType.kt
new file mode 100644
index 00000000000..6fdcb9676ad
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_singleSuperType.kt
@@ -0,0 +1,9 @@
+interface A {
+ fun foo() {}
+}
+
+class B : A {
+ fun test() {
+ super.unresolved()
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_singleSuperType.txt b/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_singleSuperType.txt
new file mode 100644
index 00000000000..71ed2e6db70
--- /dev/null
+++ b/analysis/analysis-api/testData/components/expressionType/unresolvedSuper_singleSuperType.txt
@@ -0,0 +1,2 @@
+expression: super
+type: A