From 280c44578301df47e60ea74269d00b91f72c7ed5 Mon Sep 17 00:00:00 2001 From: Tianyu Geng Date: Wed, 23 Jun 2021 16:15:02 -0700 Subject: [PATCH] FIR checker: check super reference This change touches the following diagnostics to make them behave closer to FE1.0 * SUPER_NOT_AVAILABLE * SUPER_IS_NOT_AN_EXPRESSION * INSTANCE_ACCESS_BEFORE_SUPER_CALL * NOT_A_SUPERTYPE Other than tweaking the diagnostics, this change also alters resolution by consider marking `super` with mismatched type parameter as errorenous. As a result, the following code no longer resolves. ``` class A: B() { fun test() { super.length // ^^^^^^ FIR currently resolves this to `String.length`. // With this change, `length` becomes unresolved // instead } } ``` Also, now we report `UNRESOLVED_LABEL` on unresolved label on `super` reference, though FE1.0 reports `UNRESOLVED_REFERENCE`. All the errors above are reported as ConeDiagnostics and hence some checkers are deleted. In addition, it also suppresses more downstream (mostly unresolved) errors if the receiver has errors. FE1.0 doesn't do it for all the cases we have here. But it seems nicer to reduce these "redundant" unresolved errors. --- .../instanceAccessBeforeSuperCall.kt | 2 +- .../resolve/diagnostics/notASupertype.fir.txt | 2 +- .../resolve/diagnostics/notASupertype.kt | 2 +- .../diagnostics/superNotAvailable.fir.txt | 10 +- .../resolve/diagnostics/superNotAvailable.kt | 10 +- .../diagnostics/FirDiagnosticsList.kt | 1 + .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../checkers/CommonExpressionCheckers.kt | 3 +- .../expression/FirSuperNotAvailableChecker.kt | 29 ---- .../expression/FirSuperReferenceChecker.kt | 31 ++++ .../FirUnnecessarySafeCallChecker.kt | 3 +- .../ErrorNodeDiagnosticCollectorComponent.kt | 16 +- .../diagnostics/FirDefaultErrorMessages.kt | 2 + .../coneDiagnosticToFirDiagnostic.kt | 4 +- .../FirExpressionsResolveTransformer.kt | 157 ++++++++++++------ .../jetbrains/kotlin/fir/FirSourceElement.kt | 5 + .../fir/diagnostics/ConeSimpleDiagnostic.kt | 2 + .../tests/SafeCallOnSuperReceiver.fir.kt | 11 -- .../tests/SafeCallOnSuperReceiver.kt | 1 + .../tests/inner/innerThisSuper.fir.kt | 8 +- .../nestedVsInnerAccessOuterMember.fir.kt | 4 +- .../UnavaliableQualifiedThis.fir.kt | 4 +- ...eGenericFromInnerExtendingSameBase2.fir.kt | 2 +- .../accessBaseWithSameExtension.fir.kt | 2 +- .../accessGenericBaseWithSameExtension.fir.kt | 2 +- .../innerInstanceCreation.fir.kt | 4 +- .../headerCallChecker/lambdaAsArgument.fir.kt | 4 +- .../headerCallChecker/memberFunAccess.fir.kt | 4 +- .../objectLiteralAsArgument.fir.kt | 4 +- ...bjectLiteralAsDefaultValueParameter.fir.kt | 2 +- .../headerCallChecker/propertyAccess.fir.kt | 4 +- .../propertyAccessUnitialized.fir.kt | 4 +- .../headerCallChecker/superFunAccess.fir.kt | 4 +- .../superFunAccessOverriden.fir.kt | 4 +- .../superPropertyAccess.fir.kt | 4 +- .../tests/thisAndSuper/Super.fir.kt | 32 ++-- .../superInExtensionFunction.fir.kt | 6 +- .../superInToplevelFunction.fir.kt | 8 +- .../superIsNotAnExpression.fir.kt | 12 -- .../thisAndSuper/superIsNotAnExpression.kt | 1 + .../typeAliasAsSuperQualifier.fir.kt | 12 +- .../contractFunction/neg/2.fir.kt | 6 +- .../diagnostics/KtFirDataClassConverters.kt | 6 + .../api/fir/diagnostics/KtFirDiagnostics.kt | 4 + .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 7 + 45 files changed, 257 insertions(+), 189 deletions(-) delete mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperNotAvailableChecker.kt create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirSuperReferenceChecker.kt delete mode 100644 compiler/testData/diagnostics/tests/SafeCallOnSuperReceiver.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/thisAndSuper/superIsNotAnExpression.fir.kt 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,