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 3ec56755318..8e88b2ab2bb 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 @@ -524,6 +524,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE) { firDiagnostic -> + NestedClassAccessedViaInstanceReferenceImpl( + firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a), + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.SUPER_IS_NOT_AN_EXPRESSION) { firDiagnostic -> SuperIsNotAnExpressionImpl( firDiagnostic as KtPsiDiagnostic, 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 b9f829ab998..26d6e52e429 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 @@ -414,6 +414,11 @@ sealed interface KtFirDiagnostic : KtDiagnosticWithPsi { val suggestedFunction: String } + interface NestedClassAccessedViaInstanceReference : KtFirDiagnostic { + override val diagnosticClass get() = NestedClassAccessedViaInstanceReference::class + val symbol: KtClassLikeSymbol + } + interface SuperIsNotAnExpression : KtFirDiagnostic { override val diagnosticClass get() = SuperIsNotAnExpression::class } 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 1428f409ffe..012cfd67033 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 @@ -480,6 +480,12 @@ internal class DeprecatedBinaryModImpl( token: KtLifetimeToken, ) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.DeprecatedBinaryMod +internal class NestedClassAccessedViaInstanceReferenceImpl( + override val symbol: KtClassLikeSymbol, + firDiagnostic: KtPsiDiagnostic, + token: KtLifetimeToken, +) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.NestedClassAccessedViaInstanceReference + internal class SuperIsNotAnExpressionImpl( firDiagnostic: KtPsiDiagnostic, token: KtLifetimeToken, 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 72e490815b1..0cbb4b92257 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 @@ -225,6 +225,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { parameter>("forbiddenFunction") parameter("suggestedFunction") } + val NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE by error { + parameter>("symbol") + } } val SUPER by object : DiagnosticGroup("Super") { 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 ea9f0aaad3e..de89565fe91 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 @@ -194,6 +194,7 @@ object FirErrors { val AMBIGUOUS_ALTERED_ASSIGN by error1>() val FORBIDDEN_BINARY_MOD by error2, String>(SourceElementPositioningStrategies.OPERATOR_MODIFIER) val DEPRECATED_BINARY_MOD by error2, String>(SourceElementPositioningStrategies.OPERATOR_MODIFIER) + val NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE by error1>() // Super val SUPER_IS_NOT_AN_EXPRESSION by error0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt index 0d5a181277a..db2bb92a1d0 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt @@ -68,6 +68,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set = setOf( "AMBIGUOUS_ALTERED_ASSIGN", "FORBIDDEN_BINARY_MOD", "DEPRECATED_BINARY_MOD", + "NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE", "SUPER_IS_NOT_AN_EXPRESSION", "SUPER_NOT_AVAILABLE", "ABSTRACT_SUPER_CALL", diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index f7ad28ff8bf..1bfd996d9a0 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -127,6 +127,8 @@ private fun ConeDiagnostic.toKtDiagnostic( FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED.createOn(this.source) is ConeTypeArgumentsForOuterClassWhenNestedReferencedError -> FirErrors.TYPE_ARGUMENTS_FOR_OUTER_CLASS_WHEN_NESTED_REFERENCED.createOn(this.source) + is ConeNestedClassAccessedViaInstanceReference -> + FirErrors.NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE.createOn(this.source, this.symbol) is ConeOuterClassArgumentsRequired -> FirErrors.OUTER_CLASS_ARGUMENTS_REQUIRED.createOn(callOrAssignmentSource ?: source, this.symbol) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index e04cd4ca500..417045c6935 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -352,7 +352,7 @@ class FirCallResolver( referencedSymbol, qualifiedAccess.source, qualifiedAccess.typeArguments, - diagnostic, + diagnostic ?: extractNestedClassAccessDiagnostic(nameReference.source, qualifiedAccess.explicitReceiver, referencedSymbol), nonFatalDiagnostics = extractNonFatalDiagnostics( nameReference.source, qualifiedAccess.explicitReceiver, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/QualifiedNameResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/QualifiedNameResolution.kt index aad08313c6e..26ee9e55d29 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/QualifiedNameResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/QualifiedNameResolution.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents import org.jetbrains.kotlin.fir.resolve.calls.getSingleVisibleClassifier import org.jetbrains.kotlin.fir.resolve.createCurrentScopeList import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDeprecated +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeNestedClassAccessedViaInstanceReference import org.jetbrains.kotlin.fir.resolve.setTypeOfQualifier import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.name.ClassId @@ -184,6 +185,16 @@ private fun FqName.continueQualifierInPackage( } } +internal fun extractNestedClassAccessDiagnostic( + source: KtSourceElement?, + explicitReceiver: FirExpression?, + symbol: FirClassLikeSymbol<*> +): ConeDiagnostic? { + if ((explicitReceiver as? FirResolvedQualifier)?.typeArguments?.isNotEmpty() == true) + return ConeNestedClassAccessedViaInstanceReference(source!!, symbol) + return null +} + internal fun extractNonFatalDiagnostics( source: KtSourceElement?, explicitReceiver: FirExpression?, diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt index 53cea272c9c..ca80739192c 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt @@ -272,6 +272,13 @@ class ConeTypeArgumentsForOuterClassWhenNestedReferencedError(source: KtSourceEl override val reason: String get() = "Type arguments for outer class are redundant when nested class is referenced" } +class ConeNestedClassAccessedViaInstanceReference( + source: KtSourceElement, + val symbol: FirClassLikeSymbol<*>, +) : ConeDiagnosticWithSource(source) { + override val reason: String get() = "Nested ${symbol.classId} accessed via instance reference" +} + class ConeNoTypeArgumentsOnRhsError( override val desiredCount: Int, override val symbol: FirClassLikeSymbol<*> diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt34029.fir.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt34029.fir.kt index 98284406d5f..b3f9223dab7 100644 --- a/compiler/testData/diagnostics/tests/inference/regressions/kt34029.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt34029.fir.kt @@ -3,4 +3,4 @@ open class MyClass { } val foo1 = MyClass.MyObject // it's ok -val foo2 = MyClass.MyObject // here's stofl +val foo2 = MyClass.MyObject // here's stofl