diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/instanceAccessBeforeSuperCall.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/instanceAccessBeforeSuperCall.kt index 637a3ec9786..529f0673e09 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/instanceAccessBeforeSuperCall.kt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/instanceAccessBeforeSuperCall.kt @@ -37,7 +37,7 @@ class F(var a: Int, b: Int, closure: () -> Unit, instance: F?) { val a = 10 this test(this) - this.a = 20 + this.a = 20 }, this) { this.a = 30 } diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.fir.txt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.fir.txt index 8a2c1d6414b..7f357f54019 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.fir.txt @@ -14,7 +14,7 @@ FILE: notASupertype.kt } public final fun g(): R|kotlin/Unit| { - this@R|/B|.super.#() + this@R|/B|.super<>.#() this@R|/B|.super.R|/A.f|() } diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.kt index a30ba429c4a..782a8021eb7 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.kt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.kt @@ -4,7 +4,7 @@ open class A { class B : A { fun g() { - super.f() + super<String>.f() super.f() } } diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/superNotAvailable.fir.txt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/superNotAvailable.fir.txt index f91daa17e8c..cd4e93a7aee 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/superNotAvailable.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/superNotAvailable.fir.txt @@ -1,12 +1,12 @@ FILE: superNotAvailable.kt public final fun R|kotlin/String|.f(): R|kotlin/Unit| { - super<>@f#.#(String()) - super<>.#(String()) + #.#(String()) + #.#(String()) } public final fun foo(): R|kotlin/Unit| { - super<> - super<>.#() - super.#() + # + #.#() + #.#() } public final class A : R|kotlin/Any| { public constructor(): R|A| { diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/superNotAvailable.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/superNotAvailable.kt index 62de59fefa9..617761bad58 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/superNotAvailable.kt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/superNotAvailable.kt @@ -1,12 +1,12 @@ fun String.f() { - super@f.compareTo("") - super.compareTo("") + super@f.compareTo("") + super.compareTo("") } fun foo() { - super - super.foo() - super.foo() + super + super.foo() + super.foo() } class A { 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 09d4c9904f6..a4302a09992 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 @@ -141,6 +141,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val SUPERTYPES by object : DiagnosticGroup("Supertypes") { val NOT_A_SUPERTYPE by error() + val TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER by warning() val SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE by error() val QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE by error { parameter("otherSuperType") 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 573fc0eb599..9a4a7ec961b 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 @@ -151,6 +151,7 @@ object FirErrors { // Supertypes val NOT_A_SUPERTYPE by error0() + val TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER by warning0() val SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE by error0() val QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE by error1>() val SUPERTYPE_INITIALIZED_IN_INTERFACE by error0() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt index 44307994f85..4c27673813d 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt @@ -29,8 +29,7 @@ object CommonExpressionCheckers : ExpressionCheckers() { override val qualifiedAccessExpressionCheckers: Set get() = setOf( FirCallableReferenceChecker, - FirSuperNotAvailableChecker, - FirNotASupertypeChecker, + FirSuperReferenceChecker, FirSuperclassNotAccessibleFromInterfaceChecker, FirAbstractSuperCallChecker, FirQualifiedSupertypeExtendedByOtherSupertypeChecker, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperNotAvailableChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperNotAvailableChecker.kt deleted file mode 100644 index 54fbffc7655..00000000000 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperNotAvailableChecker.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.fir.analysis.checkers.expression - -import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext -import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors -import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn -import org.jetbrains.kotlin.fir.declarations.FirClass -import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression -import org.jetbrains.kotlin.fir.references.FirSuperReference -import org.jetbrains.kotlin.utils.addToStdlib.safeAs - -object FirSuperNotAvailableChecker : FirQualifiedAccessExpressionChecker() { - override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { - if (expression.calleeReference.safeAs()?.hadExplicitTypeInSource() != true) return - - val isInsideClass = context.containingDeclarations.any { - it is FirClass - } - - if (!isInsideClass) { - reporter.reportOn(expression.source, FirErrors.SUPER_NOT_AVAILABLE, context) - } - } -} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperReferenceChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperReferenceChecker.kt new file mode 100644 index 00000000000..ac5f35b88b4 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperReferenceChecker.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.analysis.checkers.expression + +import org.jetbrains.kotlin.KtNodeTypes.TYPE_ARGUMENT_LIST +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.getChild +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression +import org.jetbrains.kotlin.fir.references.FirSuperReference +import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType +import org.jetbrains.kotlin.fir.types.coneType +import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes.TYPE_ELEMENT_TYPES +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +object FirSuperReferenceChecker : FirQualifiedAccessExpressionChecker() { + override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { + val superReference = expression.calleeReference.safeAs()?.takeIf { it.hadExplicitTypeInSource() } ?: return + + val typeArgumentListSource = superReference.superTypeRef.source?.getChild(TYPE_ELEMENT_TYPES)?.getChild(TYPE_ARGUMENT_LIST) + val superType = superReference.superTypeRef.coneType + if (typeArgumentListSource != null && superType !is ConeKotlinErrorType && superType.typeArguments.all { it !is ConeKotlinErrorType }) { + reporter.reportOn(typeArgumentListSource, FirErrors.TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER, context) + } + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUnnecessarySafeCallChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUnnecessarySafeCallChecker.kt index 2c0f1c9621c..501fbececeb 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUnnecessarySafeCallChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUnnecessarySafeCallChecker.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression +import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors @@ -18,7 +19,7 @@ import org.jetbrains.kotlin.fir.types.isUnit object FirUnnecessarySafeCallChecker : FirSafeCallExpressionChecker() { override fun check(expression: FirSafeCallExpression, context: CheckerContext, reporter: DiagnosticReporter) { val receiverType = expression.receiver.typeRef.coneType.fullyExpandedType(context.session) - if (receiverType.isUnit) { + if (receiverType.isUnit || expression.receiver.source?.elementType == KtNodeTypes.SUPER_EXPRESSION) { reporter.reportOn(expression.source, FirErrors.UNEXPECTED_SAFE_CALL, context) return } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ErrorNodeDiagnosticCollectorComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ErrorNodeDiagnosticCollectorComponent.kt index 83aec399eb3..4f275e8bc38 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ErrorNodeDiagnosticCollectorComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ErrorNodeDiagnosticCollectorComponent.kt @@ -15,10 +15,13 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.toFirDiagnostics import org.jetbrains.kotlin.fir.declarations.FirErrorFunction import org.jetbrains.kotlin.fir.declarations.FirErrorImport import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic +import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic +import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.references.FirErrorNamedReference import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInstanceAccessBeforeSuperCall import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType import org.jetbrains.kotlin.fir.types.FirErrorTypeRef @@ -64,18 +67,19 @@ class ErrorNodeDiagnosticCollectorComponent( // If the receiver cannot be resolved, we skip reporting any further problems for this call. if (qualifiedAccessOrAnnotationCall is FirQualifiedAccess) { - if (qualifiedAccessOrAnnotationCall.dispatchReceiver.hasUnresolvedNameError() || - qualifiedAccessOrAnnotationCall.extensionReceiver.hasUnresolvedNameError() || - qualifiedAccessOrAnnotationCall.explicitReceiver.hasUnresolvedNameError() + if (qualifiedAccessOrAnnotationCall.dispatchReceiver.cannotBeResolved() || + qualifiedAccessOrAnnotationCall.extensionReceiver.cannotBeResolved() || + qualifiedAccessOrAnnotationCall.explicitReceiver.cannotBeResolved() ) return } reportFirDiagnostic(errorNamedReference.diagnostic, source, reporter, data, qualifiedAccessOrAnnotationCall?.source) } - private fun FirExpression?.hasUnresolvedNameError(): Boolean { - return when ((this?.typeRef as? FirErrorTypeRef)?.diagnostic) { - is ConeUnresolvedNameError -> true + private fun FirExpression?.cannotBeResolved(): Boolean { + return when (val diagnostic = (this?.typeRef as? FirErrorTypeRef)?.diagnostic) { + is ConeUnresolvedNameError, is ConeInstanceAccessBeforeSuperCall -> true + is ConeSimpleDiagnostic -> diagnostic.kind == DiagnosticKind.NotASupertype || diagnostic.kind == DiagnosticKind.SuperNotAvailable || diagnostic.kind == DiagnosticKind.UnresolvedLabel else -> false } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index c8d6b5b93ab..570611d7848 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -390,6 +390,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOO_MANY_ARGUMENT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOPLEVEL_TYPEALIASES_ONLY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPEALIAS_SHOULD_EXPAND_TO_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_CANT_BE_USED_FOR_CONST_VAL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_MISMATCH import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_ENUM @@ -540,6 +541,7 @@ class FirDefaultErrorMessages { // Supertypes map.put(NOT_A_SUPERTYPE, "Not an immediate supertype") + map.put(TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER, "Type arguments do not need to be specified in a 'super' qualifier") map.put(SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE, "Superclass is not accessible from interface") map.put( QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE, 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 3d314302814..38ad6b93322 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 @@ -370,13 +370,15 @@ private fun ConeSimpleDiagnostic.getFactory(source: FirSourceElement): FirDiagno DiagnosticKind.NoReceiverAllowed -> FirErrors.NO_RECEIVER_ALLOWED DiagnosticKind.IsEnumEntry -> FirErrors.IS_ENUM_ENTRY DiagnosticKind.EnumEntryAsType -> FirErrors.ENUM_ENTRY_AS_TYPE + DiagnosticKind.NotASupertype -> FirErrors.NOT_A_SUPERTYPE + DiagnosticKind.SuperNotAvailable -> FirErrors.SUPER_NOT_AVAILABLE DiagnosticKind.UnresolvedSupertype, DiagnosticKind.UnresolvedExpandedType, DiagnosticKind.Other -> FirErrors.OTHER_ERROR - else -> throw IllegalArgumentException("Unsupported diagnostic kind: $kind at $javaClass") } } + @OptIn(InternalDiagnosticFactoryMethod::class) private fun FirDiagnosticFactory0.createOn( element: FirSourceElement? diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 1b341aa3328..042ae5a3052 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind @@ -49,6 +50,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform private inline val builtinTypes: BuiltinTypes get() = session.builtinTypes private val arrayOfCallTransformer = FirArrayOfCallTransformer() var enableArrayOfCallTransformation = false + var containingSafeCallExpression: FirSafeCallExpression? = null init { @Suppress("LeakingThis") @@ -106,7 +108,11 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform qualifiedAccessExpression } is FirSuperReference -> { - transformSuperReceiver(callee, qualifiedAccessExpression, null) + transformSuperReceiver( + callee, + qualifiedAccessExpression, + containingSafeCallExpression?.takeIf { qualifiedAccessExpression == it.receiver }?.regularQualifiedAccess + ) } is FirDelegateFieldReference -> { val delegateFieldSymbol = callee.resolvedSymbol @@ -157,17 +163,45 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform containingCall: FirQualifiedAccess? ): FirQualifiedAccessExpression { val labelName = superReference.labelName + val lastDispatchReceiver = implicitReceiverStack.lastDispatchReceiver() val implicitReceiver = - if (labelName != null) implicitReceiverStack[labelName] as? ImplicitDispatchReceiverValue - else implicitReceiverStack.lastDispatchReceiver() + // Only report label issues if the label is set and the receiver stack is not empty + if (labelName != null && lastDispatchReceiver != null) { + val labeledReceiver = implicitReceiverStack[labelName] as? ImplicitDispatchReceiverValue + if (labeledReceiver == null) { + return markSuperReferenceError( + ConeSimpleDiagnostic("Unresolved label", DiagnosticKind.UnresolvedLabel), + superReferenceContainer, + superReference + ) + } + labeledReceiver + } else { + lastDispatchReceiver + } implicitReceiver?.receiverExpression?.let { superReferenceContainer.transformDispatchReceiver(StoreReceiver, it) } - when (val superTypeRef = superReference.superTypeRef) { - is FirResolvedTypeRef -> { - superReferenceContainer.resultType = superTypeRef + val superTypeRefs = implicitReceiver?.boundSymbol?.fir?.superTypeRefs + val superTypeRef = superReference.superTypeRef + when { + containingCall == null -> { + val superNotAllowedDiagnostic = ConeSimpleDiagnostic("Super not allowed", DiagnosticKind.SuperNotAllowed) + return markSuperReferenceError(superNotAllowedDiagnostic, superReferenceContainer, superReference) } - !is FirImplicitTypeRef -> { + implicitReceiver == null || superTypeRefs == null || superTypeRefs.isEmpty() -> { + val diagnostic = + if (implicitReceiverStack.lastOrNull() is InaccessibleImplicitReceiverValue) { + ConeInstanceAccessBeforeSuperCall("") + } else { + ConeSimpleDiagnostic("Super not available", DiagnosticKind.SuperNotAvailable) + } + return markSuperReferenceError(diagnostic, superReferenceContainer, superReference) + } + superTypeRef is FirResolvedTypeRef -> { + superReferenceContainer.resultType = superTypeRef.copyWithNewSourceKind(FirFakeSourceElementKind.SuperCallExplicitType) + } + superTypeRef !is FirImplicitTypeRef -> { components.typeResolverTransformer.withAllowedBareTypes { superReference.transformChildren(transformer, ResolutionMode.ContextIndependent) } @@ -175,15 +209,16 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform val actualSuperType = (superReference.superTypeRef.coneType as? ConeClassLikeType) ?.fullyExpandedType(session)?.let { superType -> val classId = superType.lookupTag.classId - val superTypeRefs = implicitReceiver?.boundSymbol?.fir?.superTypeRefs - val correspondingDeclaredSuperType = superTypeRefs?.firstOrNull { + val correspondingDeclaredSuperType = superTypeRefs.firstOrNull { it.coneType.fullyExpandedType(session).classId == classId - }?.coneTypeSafe()?.fullyExpandedType(session) ?: return@let superType + }?.coneTypeSafe()?.fullyExpandedType(session) ?: return@let null - if (superType.typeArguments.isEmpty() && correspondingDeclaredSuperType.typeArguments.isNotEmpty()) { - superType.withArguments(correspondingDeclaredSuperType.typeArguments) + if (superType.typeArguments.isEmpty() && correspondingDeclaredSuperType.typeArguments.isNotEmpty() || + superType == correspondingDeclaredSuperType + ) { + correspondingDeclaredSuperType } else { - superType + null } } /* @@ -191,48 +226,54 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform * DiagnosticsTestGenerated$Tests$ThisAndSuper.testGenericQualifiedSuperOverridden * DiagnosticsTestGenerated$Tests$ThisAndSuper.testQualifiedSuperOverridden */ - val actualSuperTypeRef = actualSuperType?.let { - it.toFirResolvedTypeRef(superTypeRef.source) - } ?: buildErrorTypeRef { + val actualSuperTypeRef = actualSuperType?.toFirResolvedTypeRef(superTypeRef.source) ?: buildErrorTypeRef { source = superTypeRef.source - diagnostic = ConeSimpleDiagnostic("Not a super type", DiagnosticKind.Other) + diagnostic = ConeSimpleDiagnostic("Not a super type", DiagnosticKind.NotASupertype) } + superReferenceContainer.resultType = + actualSuperTypeRef.copyWithNewSourceKind(FirFakeSourceElementKind.SuperCallExplicitType) superReference.replaceSuperTypeRef(actualSuperTypeRef) - - superReferenceContainer.resultType = actualSuperTypeRef } else -> { - val superTypeRefs = implicitReceiver?.boundSymbol?.fir?.superTypeRefs - val resultType = when { - superTypeRefs?.isNotEmpty() != true || containingCall == null -> { - buildErrorTypeRef { - source = superReferenceContainer.source - // NB: NOT_A_SUPERTYPE is reported by a separate checker - diagnostic = ConeStubDiagnostic(ConeSimpleDiagnostic("No super type", DiagnosticKind.Other)) - } + val types = components.findTypesForSuperCandidates(superTypeRefs, containingCall) + val resultType = if (types.size == 1) { + // NB: NOT_A_SUPERTYPE is reported by a separate checker + buildResolvedTypeRef { + source = superReferenceContainer.source?.fakeElement(FirFakeSourceElementKind.SuperCallImplicitType) + type = types.single() } - else -> { - val types = components.findTypesForSuperCandidates(superTypeRefs, containingCall) - if (types.size == 1) - buildResolvedTypeRef { - source = superReferenceContainer.source?.fakeElement(FirFakeSourceElementKind.SuperCallImplicitType) - type = types.single() - } - else - buildErrorTypeRef { - source = superReferenceContainer.source - // NB: NOT_A_SUPERTYPE is reported by a separate checker - diagnostic = ConeStubDiagnostic(ConeSimpleDiagnostic("Ambiguous supertype", DiagnosticKind.Other)) - } + } else { + buildErrorTypeRef { + source = superReferenceContainer.source + // NB: NOT_A_SUPERTYPE is reported by a separate checker + diagnostic = ConeStubDiagnostic(ConeSimpleDiagnostic("Ambiguous supertype", DiagnosticKind.Other)) } } - superReferenceContainer.resultType = resultType + superReferenceContainer.resultType = + resultType.copyWithNewSourceKind(FirFakeSourceElementKind.SuperCallExplicitType) superReference.replaceSuperTypeRef(resultType) } } return superReferenceContainer } + private fun markSuperReferenceError( + superNotAvailableDiagnostic: ConeDiagnostic, + superReferenceContainer: FirQualifiedAccessExpression, + superReference: FirSuperReference + ): FirQualifiedAccessExpression { + val resultType = buildErrorTypeRef { + diagnostic = superNotAvailableDiagnostic + } + superReferenceContainer.resultType = resultType + superReference.replaceSuperTypeRef(resultType) + superReferenceContainer.replaceCalleeReference(buildErrorNamedReference { + source = superReferenceContainer.source?.fakeElement(FirFakeSourceElementKind.ReferenceInAtomicQualifiedAccess) + diagnostic = superNotAvailableDiagnostic + }) + return superReferenceContainer + } + protected open fun FirQualifiedAccessExpression.isAcceptableResolvedQualifiedAccess(): Boolean { return true } @@ -241,22 +282,34 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform safeCallExpression: FirSafeCallExpression, data: ResolutionMode ): FirStatement { - safeCallExpression.transformAnnotations(this, ResolutionMode.ContextIndependent) - safeCallExpression.transformReceiver(this, ResolutionMode.ContextIndependent) + withContainingSafeCallExpression(safeCallExpression) { + safeCallExpression.transformAnnotations(this, ResolutionMode.ContextIndependent) + safeCallExpression.transformReceiver(this, ResolutionMode.ContextIndependent) - val receiver = safeCallExpression.receiver + val receiver = safeCallExpression.receiver - dataFlowAnalyzer.enterSafeCallAfterNullCheck(safeCallExpression) + dataFlowAnalyzer.enterSafeCallAfterNullCheck(safeCallExpression) - safeCallExpression.apply { - checkedSubjectRef.value.propagateTypeFromOriginalReceiver(receiver, components.session) - transformRegularQualifiedAccess(this@FirExpressionsResolveTransformer, data) - propagateTypeFromQualifiedAccessAfterNullCheck(receiver, session) + safeCallExpression.apply { + checkedSubjectRef.value.propagateTypeFromOriginalReceiver(receiver, components.session) + transformRegularQualifiedAccess(this@FirExpressionsResolveTransformer, data) + propagateTypeFromQualifiedAccessAfterNullCheck(receiver, session) + } + + dataFlowAnalyzer.exitSafeCall(safeCallExpression) + + return safeCallExpression } + } - dataFlowAnalyzer.exitSafeCall(safeCallExpression) - - return safeCallExpression + private inline fun withContainingSafeCallExpression(safeCallExpression: FirSafeCallExpression, block: () -> T): T { + val old = containingSafeCallExpression + try { + containingSafeCallExpression = safeCallExpression + return block() + } finally { + containingSafeCallExpression = old + } } override fun transformCheckedSafeCallSubject( diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSourceElement.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSourceElement.kt index 72aded81481..50cefe14bd6 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSourceElement.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSourceElement.kt @@ -153,6 +153,11 @@ sealed class FirFakeSourceElementKind : FirSourceElementKind() { // where `Supertype` has a fake source object SuperCallImplicitType : FirFakeSourceElementKind() + // Consider `super.foo()`. The source PSI `Supertype` is referenced by both the qualified access expression + // `super` and the calleeExpression `super`. To avoid having two FIR elements sharing the same source, this fake + // source is assigned to the qualified access expression. + object SuperCallExplicitType : FirFakeSourceElementKind() + // fun foo(vararg args: Int) {} // fun bar(1, 2, 3) --> [resolved] fun bar(VarargArgument(1, 2, 3)) object VarargArgument : FirFakeSourceElementKind() diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt index 37831c7d857..85f6b0c1520 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt @@ -46,6 +46,8 @@ enum class DiagnosticKind { CannotInferParameterType, IllegalProjectionUsage, MissingStdlibClass, + NotASupertype, + SuperNotAvailable, LoopInSupertype, RecursiveTypealiasExpansion, diff --git a/compiler/testData/diagnostics/tests/SafeCallOnSuperReceiver.fir.kt b/compiler/testData/diagnostics/tests/SafeCallOnSuperReceiver.fir.kt deleted file mode 100644 index 4051b477f9f..00000000000 --- a/compiler/testData/diagnostics/tests/SafeCallOnSuperReceiver.fir.kt +++ /dev/null @@ -1,11 +0,0 @@ -// http://youtrack.jetbrains.net/issue/KT-413 - -open class A { - fun f() {} -} - -class B : A() { - fun g() { - super?.f() - } -} diff --git a/compiler/testData/diagnostics/tests/SafeCallOnSuperReceiver.kt b/compiler/testData/diagnostics/tests/SafeCallOnSuperReceiver.kt index c9aeabb196d..db936668888 100644 --- a/compiler/testData/diagnostics/tests/SafeCallOnSuperReceiver.kt +++ b/compiler/testData/diagnostics/tests/SafeCallOnSuperReceiver.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // http://youtrack.jetbrains.net/issue/KT-413 open class A { diff --git a/compiler/testData/diagnostics/tests/inner/innerThisSuper.fir.kt b/compiler/testData/diagnostics/tests/inner/innerThisSuper.fir.kt index b9b5193177f..9f496d17392 100644 --- a/compiler/testData/diagnostics/tests/inner/innerThisSuper.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/innerThisSuper.fir.kt @@ -6,12 +6,12 @@ interface Trait { class Outer : Trait { class Nested { - val t = this@Outer.bar() - val s = super@Outer.bar() + val t = this@Outer.bar() + val s = super@Outer.bar() inner class NestedInner { - val t = this@Outer.bar() - val s = super@Outer.bar() + val t = this@Outer.bar() + val s = super@Outer.bar() } } diff --git a/compiler/testData/diagnostics/tests/inner/nestedVsInnerAccessOuterMember.fir.kt b/compiler/testData/diagnostics/tests/inner/nestedVsInnerAccessOuterMember.fir.kt index 63afb185698..53c29de216e 100644 --- a/compiler/testData/diagnostics/tests/inner/nestedVsInnerAccessOuterMember.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/nestedVsInnerAccessOuterMember.fir.kt @@ -7,8 +7,8 @@ class Outer { class Nested { fun f() = function() fun g() = property - fun h() = this@Outer.function() - fun i() = this@Outer.property + fun h() = this@Outer.function() + fun i() = this@Outer.property } inner class Inner { diff --git a/compiler/testData/diagnostics/tests/regressions/UnavaliableQualifiedThis.fir.kt b/compiler/testData/diagnostics/tests/regressions/UnavaliableQualifiedThis.fir.kt index b9d2dfba40b..3b0392243ae 100644 --- a/compiler/testData/diagnostics/tests/regressions/UnavaliableQualifiedThis.fir.kt +++ b/compiler/testData/diagnostics/tests/regressions/UnavaliableQualifiedThis.fir.kt @@ -4,10 +4,10 @@ interface Iterator { fun map(transform: (element: T) -> R) : Iterator = object : Iterator { - override fun next() : R = transform(this@map.next()) + override fun next() : R = transform(this@map.next()) override val hasNext : Boolean // There's no 'this' associated with the map() function, only this of the Iterator class - get() = this@map.hasNext + get() = this@map.hasNext } } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase2.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase2.fir.kt index d8a5107d63a..3e2b78700fd 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase2.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase2.fir.kt @@ -7,7 +7,7 @@ open class Base(p: Any?) { class D: Base(1) { inner class B : Base { constructor() : super(foo1(1)) - constructor(x: Int) : super(this@B.foo1(1)) + constructor(x: Int) : super(this@B.foo1(1)) constructor(x: Int, y: Int) : super(this@D.foo1(1)) } } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseWithSameExtension.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseWithSameExtension.fir.kt index f9f5e038a0f..a0c8a3bab39 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseWithSameExtension.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseWithSameExtension.fir.kt @@ -7,6 +7,6 @@ fun Base.foo() { class B : Base { constructor() : super(foo1()) constructor(x: Int) : super(this@foo.foo1()) - constructor(x: Int, y: Int) : super(this@B.foo1()) + constructor(x: Int, y: Int) : super(this@B.foo1()) } } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessGenericBaseWithSameExtension.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessGenericBaseWithSameExtension.fir.kt index b9089da2834..5d004a9c48b 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessGenericBaseWithSameExtension.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessGenericBaseWithSameExtension.fir.kt @@ -8,6 +8,6 @@ fun Base.foo() { constructor() : super(foo1("")) constructor(x: Int) : super(foo1(1)) constructor(x: Int, y: Int) : super(this@foo.foo1(12)) - constructor(x: Int, y: Int, z: Int) : super(this@B.foo1("")) + constructor(x: Int, y: Int, z: Int) : super(this@B.foo1("")) } } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/innerInstanceCreation.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/innerInstanceCreation.fir.kt index b96e3951189..4a0377caebc 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/innerInstanceCreation.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/innerInstanceCreation.fir.kt @@ -6,6 +6,6 @@ class Outer { } constructor(x: Int) - constructor(x: Int, y: Int, z: Int = x + Inner().prop + this.Inner().prop) : - this(x + Inner().prop + this.Inner().prop) + constructor(x: Int, y: Int, z: Int = x + Inner().prop + this.Inner().prop) : + this(x + Inner().prop + this.Inner().prop) } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/lambdaAsArgument.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/lambdaAsArgument.fir.kt index 71491bcdd96..7da36c3d4ee 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/lambdaAsArgument.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/lambdaAsArgument.fir.kt @@ -8,8 +8,8 @@ class A { constructor() : this( { foo() + - this.foo() + - this@A.foo() + + this.foo() + + this@A.foo() + foobar() }) } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/memberFunAccess.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/memberFunAccess.fir.kt index 4efd51ca5a8..32e6f820d1c 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/memberFunAccess.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/memberFunAccess.fir.kt @@ -2,6 +2,6 @@ class A { fun foo() = 1 constructor(x: Int) - constructor(x: Int, y: Int, z: Int = x + foo() + this.foo()) : - this(x + foo() + this.foo()) + constructor(x: Int, y: Int, z: Int = x + foo() + this.foo()) : + this(x + foo() + this.foo()) } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/objectLiteralAsArgument.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/objectLiteralAsArgument.fir.kt index f7a300636db..615ece5d687 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/objectLiteralAsArgument.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/objectLiteralAsArgument.fir.kt @@ -6,7 +6,7 @@ class A { fun foo() = 1 constructor(x: Any?) constructor() : this(object { - fun bar() = foo() + this@A.foo() + - foobar() + super@A.hashCode() + fun bar() = foo() + this@A.foo() + + foobar() + super@A.hashCode() }) } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/objectLiteralAsDefaultValueParameter.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/objectLiteralAsDefaultValueParameter.fir.kt index 268fe821043..ab43688cbf9 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/objectLiteralAsDefaultValueParameter.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/objectLiteralAsDefaultValueParameter.fir.kt @@ -5,7 +5,7 @@ fun A.foobar() = 3 class A { fun foo() = 1 constructor( x: Any = object { - fun bar() = foo() + this@A.foo() + + fun bar() = foo() + this@A.foo() + foobar() }) } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccess.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccess.fir.kt index 6b6896fbc09..90ab3adca7f 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccess.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccess.fir.kt @@ -2,6 +2,6 @@ class A { val prop = 1 constructor(x: Int) - constructor(x: Int, y: Int, z: Int = x + prop + this.prop) : - this(x + prop + this.prop) + constructor(x: Int, y: Int, z: Int = x + prop + this.prop) : + this(x + prop + this.prop) } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccessUnitialized.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccessUnitialized.fir.kt index cdb18f2fbc1..d67992b080f 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccessUnitialized.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccessUnitialized.fir.kt @@ -2,6 +2,6 @@ open class B(x: Int) class A : B { val prop = 1 - constructor(x: Int, y: Int = x + prop + this.prop) : - super(x + prop + this.prop) + constructor(x: Int, y: Int = x + prop + this.prop) : + super(x + prop + this.prop) } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccess.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccess.fir.kt index b977fd05e96..6da0ba5e407 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccess.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccess.fir.kt @@ -3,6 +3,6 @@ open class B(x: Int) { fun foo() = 1 } class A : B { - constructor(x: Int, y: Int = x + foo() + this.foo() + super.foo()) : - super(x + foo() + this.foo() + super.foo()) + constructor(x: Int, y: Int = x + foo() + this.foo() + super.foo()) : + super(x + foo() + this.foo() + super.foo()) } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccessOverriden.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccessOverriden.fir.kt index 7e9f5bc6d8f..899a4e42928 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccessOverriden.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccessOverriden.fir.kt @@ -4,6 +4,6 @@ open class B(x: Int) { } class A : B { override fun foo() = 2 - constructor(x: Int, y: Int = x + foo() + this.foo() + super.foo()) : - super(x + foo() + this.foo() + super.foo()) + constructor(x: Int, y: Int = x + foo() + this.foo() + super.foo()) : + super(x + foo() + this.foo() + super.foo()) } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superPropertyAccess.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superPropertyAccess.fir.kt index 4e2fc08a2fc..ef877e454d8 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superPropertyAccess.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superPropertyAccess.fir.kt @@ -1,6 +1,6 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER open class B(val prop: Int) class A : B { - constructor(x: Int, y: Int = x + prop + this.prop + super.prop) : - super(x + prop + this.prop + super.prop) + constructor(x: Int, y: Int = x + prop + this.prop + super.prop) : + super(x + prop + this.prop + super.prop) } diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/Super.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/Super.fir.kt index 6cc779c744b..71098431df8 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/Super.fir.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/Super.fir.kt @@ -10,34 +10,34 @@ open class C() { class A() : C(), T { fun test() { - super - super + super + super super.foo() super.foo() super.bar() super@A.foo() super@A.bar() - super<E>.bar() - super<E>@A.bar() - super.foo() + super<E>.bar() + super<E>@A.bar() + super<Int>.foo() super<>.foo() - super<() -> Unit>.foo() - super.foo() - super@B.foo() - super@B.bar() + super<() -> Unit>.foo() + super<Unit>.foo() + super@B.foo() + super@B.bar() } inner class B : T { fun test() { super.foo(); - super.bar() + super<C>.bar() super@A.bar() super@A.foo() super@B.foo() - super@B.foo() + super<C>@B.foo() super.foo() - super - super + super + super } } } @@ -49,9 +49,9 @@ interface G { class CG : G { fun test() { super.foo() // OK - super>.foo() // Warning - super>.foo() // Error - super>.foo() // Error + super>.foo() // Warning + super<G>.foo() // Error + super<G>.foo() // Error } } diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/superInExtensionFunction.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/superInExtensionFunction.fir.kt index f5aba60cce7..e73d50a5554 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/superInExtensionFunction.fir.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/superInExtensionFunction.fir.kt @@ -1,4 +1,4 @@ fun String.f() { - super@f.compareTo("") - super.compareTo("") -} \ No newline at end of file + super@f.compareTo("") + super.compareTo("") +} diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/superInToplevelFunction.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/superInToplevelFunction.fir.kt index bb1e91ecd86..1336b489601 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/superInToplevelFunction.fir.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/superInToplevelFunction.fir.kt @@ -1,5 +1,5 @@ fun foo() { - super - super.foo() - super.foo() -} \ No newline at end of file + super + super.foo() + super.foo() +} diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/superIsNotAnExpression.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/superIsNotAnExpression.fir.kt deleted file mode 100644 index 925c8b1ca7f..00000000000 --- a/compiler/testData/diagnostics/tests/thisAndSuper/superIsNotAnExpression.fir.kt +++ /dev/null @@ -1,12 +0,0 @@ -fun any(a : Any) {} - -fun notAnExpression() { - any(super) // not an expression - if (super) {} else {} // not an expression - val x = super // not an expression - when (1) { - super -> 1 // not an expression - else -> {} - } - -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/superIsNotAnExpression.kt b/compiler/testData/diagnostics/tests/thisAndSuper/superIsNotAnExpression.kt index 373a27ce618..df7fe6175b0 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/superIsNotAnExpression.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/superIsNotAnExpression.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL fun any(a : Any) {} fun notAnExpression() { diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasAsSuperQualifier.fir.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasAsSuperQualifier.fir.kt index 639922c7ed6..2689a2a135c 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasAsSuperQualifier.fir.kt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasAsSuperQualifier.fir.kt @@ -22,8 +22,8 @@ class TestSuperForBase : B() { override fun foo() { super.foo() super.foo() - super<MyBase>.foo() - super.foo() + super<MyBase>.foo() + super<U>.foo() } } @@ -34,8 +34,8 @@ class TestSuperForGenericBase : GB() { override fun foo() { super.foo() super.foo() - super<MyBase>.foo() - super<MyBaseInt>.foo() // Type arguments don't matter here - super.foo() + super<MyBase>.foo() + super<MyBaseInt>.foo() // Type arguments don't matter here + super<U>.foo() } -} \ No newline at end of file +} diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/neg/2.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/neg/2.fir.kt index 620d224608b..0607ff9a661 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/neg/2.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/contracts/declarations/contractFunction/neg/2.fir.kt @@ -32,7 +32,7 @@ fun case_2() { class case_4 : ClassLevel3() { fun T.case_4_1(): Boolean { - contract { returns(false) implies (this@case_4 !is ClassLevel1) } + contract { returns(false) implies (this@case_4 !is ClassLevel1) } return this == null } @@ -60,12 +60,12 @@ class case_4 : ClassLevel3() { class case_5 : ClassLevel5() { inner class case_5_1 { fun K.case_5_1_1() { - contract { returns() implies (this@case_5_1 !is ClassLevel1 && this@case_5_1 != null || this@case_5 is ClassLevel1 && this@case_5_1_1 is Float) } + contract { returns() implies (this@case_5_1 !is ClassLevel1 && this@case_5_1 != null || this@case_5 is ClassLevel1 && this@case_5_1_1 is Float) } if (!(this@case_5_1 !is ClassLevel1 && this@case_5_1 != null || this@case_5 is ClassLevel1 && this is Float)) throw Exception() } fun case_5_1_2() { - contract { returns() implies (this@case_5_1 !is ClassLevel1 || this@case_5 is ClassLevel1 || this@case_5_1 == null) } + contract { returns() implies (this@case_5_1 !is ClassLevel1 || this@case_5 is ClassLevel1 || this@case_5_1 == null) } if (!(this@case_5_1 !is ClassLevel1 || this@case_5 is ClassLevel1 || this@case_5_1 == null)) throw Exception() } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index f4d214b854d..5a80db35f21 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -375,6 +375,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER) { firDiagnostic -> + TypeArgumentsRedundantInSuperQualifierImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE) { firDiagnostic -> SuperclassNotAccessibleFromInterfaceImpl( firDiagnostic as FirPsiDiagnostic, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index 681f861b8e0..9a02f3aa921 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -290,6 +290,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = NotASupertype::class } + abstract class TypeArgumentsRedundantInSuperQualifier : KtFirDiagnostic() { + override val diagnosticClass get() = TypeArgumentsRedundantInSuperQualifier::class + } + abstract class SuperclassNotAccessibleFromInterface : KtFirDiagnostic() { override val diagnosticClass get() = SuperclassNotAccessibleFromInterface::class } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index d83652959da..96a235207c4 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -435,6 +435,13 @@ internal class NotASupertypeImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class TypeArgumentsRedundantInSuperQualifierImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.TypeArgumentsRedundantInSuperQualifier(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class SuperclassNotAccessibleFromInterfaceImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken,