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<String>.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.
This commit is contained in:
Tianyu Geng
2021-06-23 16:15:02 -07:00
committed by Ivan Kochurkin
parent bcf6202863
commit 280c445783
45 changed files with 257 additions and 189 deletions
@@ -37,7 +37,7 @@ class F(var a: Int, b: Int, closure: () -> Unit, instance: F?) {
val a = 10
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>
test(<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>)
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>a<!> = 20
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.a = 20
}, <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>) {
this.a = 30
}
@@ -14,7 +14,7 @@ FILE: notASupertype.kt
}
public final fun g(): R|kotlin/Unit| {
this@R|/B|.super<R|kotlin/String|>.<Unresolved name: f>#()
this@R|/B|.super<<ERROR TYPE REF: Not a super type>>.<Unresolved name: f>#()
this@R|/B|.super<R|A|>.R|/A.f|()
}
@@ -4,7 +4,7 @@ open class A {
class B : <!SUPERTYPE_NOT_INITIALIZED!>A<!> {
fun g() {
<!NOT_A_SUPERTYPE!>super<String><!>.<!UNRESOLVED_REFERENCE!>f<!>()
super<<!NOT_A_SUPERTYPE!>String<!>>.f()
super<A>.f()
}
}
@@ -1,12 +1,12 @@
FILE: superNotAvailable.kt
public final fun R|kotlin/String|.f(): R|kotlin/Unit| {
super<<ERROR TYPE REF: No super type>>@f#.<Unresolved name: compareTo>#(String())
super<<ERROR TYPE REF: No super type>>.<Unresolved name: compareTo>#(String())
<Super not available>#.<Unresolved name: compareTo>#(String())
<Super not available>#.<Unresolved name: compareTo>#(String())
}
public final fun foo(): R|kotlin/Unit| {
super<<ERROR TYPE REF: No super type>>
super<<ERROR TYPE REF: No super type>>.<Unresolved name: foo>#()
super<R|kotlin/Nothing|>.<Unresolved name: foo>#()
<Super not allowed>#
<Super not available>#.<Unresolved name: foo>#()
<Super not available>#.<Unresolved name: foo>#()
}
public final class A : R|kotlin/Any| {
public constructor(): R|A| {
@@ -1,12 +1,12 @@
fun String.f() {
<!SUPER_NOT_AVAILABLE!>super@f<!>.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
<!SUPER_NOT_AVAILABLE!>super<!>.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
<!SUPER_NOT_AVAILABLE!>super@f<!>.compareTo("")
<!SUPER_NOT_AVAILABLE!>super<!>.compareTo("")
}
fun foo() {
<!SUPER_NOT_AVAILABLE!>super<!>
<!SUPER_NOT_AVAILABLE!>super<!>.<!UNRESOLVED_REFERENCE!>foo<!>()
<!SUPER_NOT_AVAILABLE!>super<Nothing><!>.<!UNRESOLVED_REFERENCE!>foo<!>()
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>
<!SUPER_NOT_AVAILABLE!>super<!>.foo()
<!SUPER_NOT_AVAILABLE!>super<Nothing><!>.foo()
}
class A {
@@ -141,6 +141,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val SUPERTYPES by object : DiagnosticGroup("Supertypes") {
val NOT_A_SUPERTYPE by error<PsiElement>()
val TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER by warning<KtElement>()
val SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE by error<PsiElement>()
val QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE by error<KtTypeReference> {
parameter<Symbol>("otherSuperType")
@@ -151,6 +151,7 @@ object FirErrors {
// Supertypes
val NOT_A_SUPERTYPE by error0<PsiElement>()
val TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER by warning0<KtElement>()
val SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE by error0<PsiElement>()
val QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE by error1<KtTypeReference, FirBasedSymbol<*>>()
val SUPERTYPE_INITIALIZED_IN_INTERFACE by error0<KtTypeReference>()
@@ -29,8 +29,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
get() = setOf(
FirCallableReferenceChecker,
FirSuperNotAvailableChecker,
FirNotASupertypeChecker,
FirSuperReferenceChecker,
FirSuperclassNotAccessibleFromInterfaceChecker,
FirAbstractSuperCallChecker,
FirQualifiedSupertypeExtendedByOtherSupertypeChecker,
@@ -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<FirSuperReference>()?.hadExplicitTypeInSource() != true) return
val isInsideClass = context.containingDeclarations.any {
it is FirClass
}
if (!isInsideClass) {
reporter.reportOn(expression.source, FirErrors.SUPER_NOT_AVAILABLE, context)
}
}
}
@@ -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<FirSuperReference>()?.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)
}
}
}
@@ -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
}
@@ -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
}
}
@@ -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,
@@ -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?
@@ -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("<super>")
} 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<ConeClassLikeType>()?.fullyExpandedType(session) ?: return@let superType
}?.coneTypeSafe<ConeClassLikeType>()?.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 <T> withContainingSafeCallExpression(safeCallExpression: FirSafeCallExpression, block: () -> T): T {
val old = containingSafeCallExpression
try {
containingSafeCallExpression = safeCallExpression
return block()
} finally {
containingSafeCallExpression = old
}
}
override fun transformCheckedSafeCallSubject(
@@ -153,6 +153,11 @@ sealed class FirFakeSourceElementKind : FirSourceElementKind() {
// where `Supertype` has a fake source
object SuperCallImplicitType : FirFakeSourceElementKind()
// Consider `super<Supertype>.foo()`. The source PSI `Supertype` is referenced by both the qualified access expression
// `super<Supertype>` and the calleeExpression `super<Supertype>`. 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()
@@ -46,6 +46,8 @@ enum class DiagnosticKind {
CannotInferParameterType,
IllegalProjectionUsage,
MissingStdlibClass,
NotASupertype,
SuperNotAvailable,
LoopInSupertype,
RecursiveTypealiasExpansion,
@@ -1,11 +0,0 @@
// http://youtrack.jetbrains.net/issue/KT-413
open class A {
fun f() {}
}
class B : A() {
fun g() {
super?.<!UNRESOLVED_REFERENCE!>f<!>()
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// http://youtrack.jetbrains.net/issue/KT-413
open class A {
@@ -6,12 +6,12 @@ interface Trait {
class Outer : Trait {
class Nested {
val t = this<!UNRESOLVED_LABEL!>@Outer<!>.<!UNRESOLVED_REFERENCE!>bar<!>()
val s = super@Outer.<!UNRESOLVED_REFERENCE!>bar<!>()
val t = this<!UNRESOLVED_LABEL!>@Outer<!>.bar()
val s = super<!UNRESOLVED_LABEL!>@Outer<!>.bar()
inner class NestedInner {
val t = this<!UNRESOLVED_LABEL!>@Outer<!>.<!UNRESOLVED_REFERENCE!>bar<!>()
val s = super@Outer.<!UNRESOLVED_REFERENCE!>bar<!>()
val t = this<!UNRESOLVED_LABEL!>@Outer<!>.bar()
val s = super<!UNRESOLVED_LABEL!>@Outer<!>.bar()
}
}
@@ -7,8 +7,8 @@ class Outer {
class Nested {
fun f() = <!UNRESOLVED_REFERENCE!>function<!>()
fun g() = <!UNRESOLVED_REFERENCE!>property<!>
fun h() = this<!UNRESOLVED_LABEL!>@Outer<!>.<!UNRESOLVED_REFERENCE!>function<!>()
fun i() = this<!UNRESOLVED_LABEL!>@Outer<!>.<!UNRESOLVED_REFERENCE!>property<!>
fun h() = this<!UNRESOLVED_LABEL!>@Outer<!>.function()
fun i() = this<!UNRESOLVED_LABEL!>@Outer<!>.property
}
inner class Inner {
@@ -4,10 +4,10 @@ interface Iterator<out T> {
fun <R> map(transform: (element: T) -> R) : Iterator<R> =
object : Iterator<R> {
override fun next() : R = transform(this<!UNRESOLVED_LABEL!>@map<!>.<!UNRESOLVED_REFERENCE!>next<!>())
override fun next() : R = transform(this<!UNRESOLVED_LABEL!>@map<!>.next())
override val hasNext : Boolean
// There's no 'this' associated with the map() function, only this of the Iterator class
get() = this<!UNRESOLVED_LABEL!>@map<!>.<!UNRESOLVED_REFERENCE!>hasNext<!>
get() = this<!UNRESOLVED_LABEL!>@map<!>.hasNext
}
}
@@ -7,7 +7,7 @@ open class Base<T>(p: Any?) {
class D: Base<Int>(1) {
inner class B : Base<Int> {
constructor() : super(foo1(1))
constructor(x: Int) : super(this<!UNRESOLVED_LABEL!>@B<!>.<!UNRESOLVED_REFERENCE!>foo1<!>(1))
constructor(x: Int) : super(this<!UNRESOLVED_LABEL!>@B<!>.foo1(1))
constructor(x: Int, y: Int) : super(this@D.foo1(1))
}
}
@@ -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<!UNRESOLVED_LABEL!>@B<!>.<!UNRESOLVED_REFERENCE!>foo1<!>())
constructor(x: Int, y: Int) : super(this<!UNRESOLVED_LABEL!>@B<!>.foo1())
}
}
@@ -8,6 +8,6 @@ fun Base<Int>.foo() {
constructor() : super(foo1(<!ARGUMENT_TYPE_MISMATCH!>""<!>))
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<!UNRESOLVED_LABEL!>@B<!>.<!UNRESOLVED_REFERENCE!>foo1<!>(""))
constructor(x: Int, y: Int, z: Int) : super(this<!UNRESOLVED_LABEL!>@B<!>.foo1(""))
}
}
@@ -6,6 +6,6 @@ class Outer {
}
constructor(x: Int)
constructor(x: Int, y: Int, z: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!RESOLUTION_TO_CLASSIFIER!>Inner<!>().<!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>Inner<!>().prop<!>) :
this(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!RESOLUTION_TO_CLASSIFIER!>Inner<!>().<!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>Inner<!>().prop<!>)
constructor(x: Int, y: Int, z: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!RESOLUTION_TO_CLASSIFIER!>Inner<!>().<!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.Inner().prop<!>) :
this(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!RESOLUTION_TO_CLASSIFIER!>Inner<!>().<!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.Inner().prop<!>)
}
@@ -8,8 +8,8 @@ class A {
constructor() : this(
{
<!ARGUMENT_TYPE_MISMATCH, TYPE_MISMATCH!><!UNRESOLVED_REFERENCE!>foo<!>() +
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>foo<!>() +
this<!UNRESOLVED_LABEL!>@A<!>.<!UNRESOLVED_REFERENCE!>foo<!>() +
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.foo() +
this<!UNRESOLVED_LABEL!>@A<!>.foo() +
<!UNRESOLVED_REFERENCE!>foobar<!>()<!>
})
}
@@ -2,6 +2,6 @@
class A {
fun foo() = 1
constructor(x: Int)
constructor(x: Int, y: Int, z: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>foo<!>()<!>) :
this(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>foo<!>()<!>)
constructor(x: Int, y: Int, z: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.foo()<!>) :
this(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.foo()<!>)
}
@@ -6,7 +6,7 @@ class A {
fun foo() = 1
constructor(x: Any?)
constructor() : this(object {
fun bar() = <!UNRESOLVED_REFERENCE!>foo<!>() + this<!UNRESOLVED_LABEL!>@A<!>.<!UNRESOLVED_REFERENCE!>foo<!>() +
<!INAPPLICABLE_CANDIDATE!>foobar<!>() + super@A.<!UNRESOLVED_REFERENCE!>hashCode<!>()
fun bar() = <!UNRESOLVED_REFERENCE!>foo<!>() + this<!UNRESOLVED_LABEL!>@A<!>.foo() +
<!INAPPLICABLE_CANDIDATE!>foobar<!>() + super<!UNRESOLVED_LABEL!>@A<!>.hashCode()
})
}
@@ -5,7 +5,7 @@ fun A.foobar() = 3
class A {
fun foo() = 1
constructor( x: Any = object {
fun bar() = <!UNRESOLVED_REFERENCE!>foo<!>() + this<!UNRESOLVED_LABEL!>@A<!>.<!UNRESOLVED_REFERENCE!>foo<!>() +
fun bar() = <!UNRESOLVED_REFERENCE!>foo<!>() + this<!UNRESOLVED_LABEL!>@A<!>.foo() +
<!INAPPLICABLE_CANDIDATE!>foobar<!>()
})
}
@@ -2,6 +2,6 @@
class A {
val prop = 1
constructor(x: Int)
constructor(x: Int, y: Int, z: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>prop<!><!>) :
this(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>prop<!><!>)
constructor(x: Int, y: Int, z: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.prop<!>) :
this(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.prop<!>)
}
@@ -2,6 +2,6 @@
open class B(x: Int)
class A : B {
val prop = 1
constructor(x: Int, y: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>prop<!><!>) :
super(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>prop<!><!>)
constructor(x: Int, y: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.prop<!>) :
super(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.prop<!>)
}
@@ -3,6 +3,6 @@ open class B(x: Int) {
fun foo() = 1
}
class A : B {
constructor(x: Int, y: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>foo<!>() + super.<!UNRESOLVED_REFERENCE!>foo<!>()<!>) :
super(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>foo<!>() + super.<!UNRESOLVED_REFERENCE!>foo<!>()<!>)
constructor(x: Int, y: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.foo() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>super<!>.foo()<!>) :
super(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.foo() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>super<!>.foo()<!>)
}
@@ -4,6 +4,6 @@ open class B(x: Int) {
}
class A : B {
override fun foo() = 2
constructor(x: Int, y: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>foo<!>() + super.<!UNRESOLVED_REFERENCE!>foo<!>()<!>) :
super(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>foo<!>() + super.<!UNRESOLVED_REFERENCE!>foo<!>()<!>)
constructor(x: Int, y: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.foo() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>super<!>.foo()<!>) :
super(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>foo<!>() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.foo() + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>super<!>.foo()<!>)
}
@@ -1,6 +1,6 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
open class B(val prop: Int)
class A : B {
constructor(x: Int, y: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>prop<!> + super.<!UNRESOLVED_REFERENCE!>prop<!><!>) :
super(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>prop<!> + super.<!UNRESOLVED_REFERENCE!>prop<!><!>)
constructor(x: Int, y: Int = <!TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.prop + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>super<!>.prop<!>) :
super(<!ARGUMENT_TYPE_MISMATCH!>x <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> <!UNRESOLVED_REFERENCE!>prop<!> + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.prop + <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>super<!>.prop<!>)
}
+16 -16
View File
@@ -10,34 +10,34 @@ open class C() {
class A<E>() : C(), T {
fun test() {
super
super<T>
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>
<!SUPER_IS_NOT_AN_EXPRESSION!>super<T><!>
super.foo()
super<T>.foo()
super<C>.bar()
super<T>@A.foo()
super<C>@A.bar()
super<<!OTHER_ERROR, OTHER_ERROR!>E<!>>.<!UNRESOLVED_REFERENCE!>bar<!>()
super<<!OTHER_ERROR, OTHER_ERROR!>E<!>>@A.<!UNRESOLVED_REFERENCE!>bar<!>()
<!NOT_A_SUPERTYPE!>super<Int><!>.<!UNRESOLVED_REFERENCE!>foo<!>()
super<<!NOT_A_SUPERTYPE!>E<!>>.bar()
super<<!NOT_A_SUPERTYPE!>E<!>>@A.bar()
super<<!NOT_A_SUPERTYPE!>Int<!>>.foo()
super<<!SYNTAX!><!>>.<!UNRESOLVED_REFERENCE!>foo<!>()
<!NOT_A_SUPERTYPE!>super<() -> Unit><!>.<!UNRESOLVED_REFERENCE!>foo<!>()
<!NOT_A_SUPERTYPE!>super<Unit><!>.<!UNRESOLVED_REFERENCE!>foo<!>()
super<T>@B.foo()
super<C>@B.bar()
super<<!NOT_A_SUPERTYPE!>() -> Unit<!>>.foo()
super<<!NOT_A_SUPERTYPE!>Unit<!>>.foo()
super<T><!UNRESOLVED_LABEL!>@B<!>.foo()
super<C><!UNRESOLVED_LABEL!>@B<!>.bar()
}
inner class B : T {
fun test() {
super<T>.foo();
<!NOT_A_SUPERTYPE!>super<C><!>.bar()
super<<!NOT_A_SUPERTYPE!>C<!>>.bar()
super<C>@A.bar()
super<T>@A.foo()
super<T>@B.foo()
<!NOT_A_SUPERTYPE!>super<C>@B<!>.<!UNRESOLVED_REFERENCE!>foo<!>()
super<<!NOT_A_SUPERTYPE!>C<!>>@B.foo()
super.foo()
super
super<T>
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>
<!SUPER_IS_NOT_AN_EXPRESSION!>super<T><!>
}
}
}
@@ -49,9 +49,9 @@ interface G<T> {
class CG : G<Int> {
fun test() {
super<G>.foo() // OK
super<G<Int>>.foo() // Warning
super<G<E>>.foo() // Error
super<G<String>>.foo() // Error
super<G<!TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER!><Int><!>>.foo() // Warning
super<<!NOT_A_SUPERTYPE!>G<E><!>>.foo() // Error
super<<!NOT_A_SUPERTYPE!>G<String><!>>.foo() // Error
}
}
@@ -1,4 +1,4 @@
fun String.f() {
<!SUPER_NOT_AVAILABLE!>super@f<!>.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
<!SUPER_NOT_AVAILABLE!>super<!>.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
}
<!SUPER_NOT_AVAILABLE!>super@f<!>.compareTo("")
<!SUPER_NOT_AVAILABLE!>super<!>.compareTo("")
}
@@ -1,5 +1,5 @@
fun foo() {
<!SUPER_NOT_AVAILABLE!>super<!>
<!SUPER_NOT_AVAILABLE!>super<!>.<!UNRESOLVED_REFERENCE!>foo<!>()
<!SUPER_NOT_AVAILABLE!>super<Nothing><!>.<!UNRESOLVED_REFERENCE!>foo<!>()
}
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>
<!SUPER_NOT_AVAILABLE!>super<!>.foo()
<!SUPER_NOT_AVAILABLE!>super<Nothing><!>.foo()
}
@@ -1,12 +0,0 @@
fun any(a : Any) {}
fun notAnExpression() {
any(<!SUPER_NOT_AVAILABLE!>super<!>) // not an expression
if (<!SUPER_NOT_AVAILABLE!>super<!>) {} else {} // not an expression
val x = <!SUPER_NOT_AVAILABLE!>super<!> // not an expression
when (1) {
<!SUPER_NOT_AVAILABLE!>super<!> -> 1 // not an expression
else -> {}
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
fun any(a : Any) {}
fun notAnExpression() {
@@ -22,8 +22,8 @@ class TestSuperForBase : B() {
override fun foo() {
super<Base>.foo()
super<B>.foo()
super<<!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>MyBase<!>>.<!UNRESOLVED_REFERENCE!>foo<!>()
<!NOT_A_SUPERTYPE!>super<U><!>.foo()
super<<!NOT_A_SUPERTYPE!>MyBase<!>>.foo()
super<<!NOT_A_SUPERTYPE!>U<!>>.foo()
}
}
@@ -34,8 +34,8 @@ class TestSuperForGenericBase<T> : GB<T>() {
override fun foo() {
super<GenericBase>.foo()
super<GB>.foo()
super<<!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>MyBase<!>>.<!UNRESOLVED_REFERENCE!>foo<!>()
super<<!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>MyBaseInt<!>>.<!UNRESOLVED_REFERENCE!>foo<!>() // Type arguments don't matter here
<!NOT_A_SUPERTYPE!>super<U><!>.foo()
super<<!NOT_A_SUPERTYPE!>MyBase<!>>.foo()
super<<!NOT_A_SUPERTYPE!>MyBaseInt<!>>.foo() // Type arguments don't matter here
super<<!NOT_A_SUPERTYPE!>U<!>>.foo()
}
}
}
@@ -32,7 +32,7 @@ fun case_2() {
class case_4 : ClassLevel3() {
fun <T : Number?>T.case_4_1(): Boolean {
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns(false) implies (<!UNRESOLVED_LABEL!>this@case_4<!> !is ClassLevel1)<!> }
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns(false) implies (this<!UNRESOLVED_LABEL!>@case_4<!> !is ClassLevel1)<!> }
return this == null
}
@@ -60,12 +60,12 @@ class case_4 : ClassLevel3() {
class case_5<T> : ClassLevel5() {
inner class case_5_1 {
fun <K : Number?>K.case_5_1_1() {
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (<!UNRESOLVED_LABEL!>this@case_5_1<!> !is ClassLevel1 && <!UNRESOLVED_LABEL!>this@case_5_1<!> != null || <!UNRESOLVED_LABEL!>this@case_5<!> is ClassLevel1 && this@case_5_1_1 is Float)<!> }
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (this<!UNRESOLVED_LABEL!>@case_5_1<!> !is ClassLevel1 && this<!UNRESOLVED_LABEL!>@case_5_1<!> != null || this<!UNRESOLVED_LABEL!>@case_5<!> is ClassLevel1 && this@case_5_1_1 is Float)<!> }
if (!(this@case_5_1 !is ClassLevel1 && <!SENSELESS_COMPARISON!>this@case_5_1 != null<!> || <!USELESS_IS_CHECK!>this@case_5 is ClassLevel1<!> && this is Float)) throw Exception()
}
fun case_5_1_2() {
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (<!UNRESOLVED_LABEL!>this@case_5_1<!> !is ClassLevel1 || <!UNRESOLVED_LABEL!>this@case_5<!> is ClassLevel1 || <!UNRESOLVED_LABEL!>this@case_5_1<!> == null)<!> }
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (this<!UNRESOLVED_LABEL!>@case_5_1<!> !is ClassLevel1 || this<!UNRESOLVED_LABEL!>@case_5<!> is ClassLevel1 || this<!UNRESOLVED_LABEL!>@case_5_1<!> == null)<!> }
if (!(this@case_5_1 !is ClassLevel1 || <!USELESS_IS_CHECK!>this@case_5 is ClassLevel1<!> || <!SENSELESS_COMPARISON!>this@case_5_1 == null<!>)) throw Exception()
}
}
@@ -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,
@@ -290,6 +290,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = NotASupertype::class
}
abstract class TypeArgumentsRedundantInSuperQualifier : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = TypeArgumentsRedundantInSuperQualifier::class
}
abstract class SuperclassNotAccessibleFromInterface : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = SuperclassNotAccessibleFromInterface::class
}
@@ -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<KtElement> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class SuperclassNotAccessibleFromInterfaceImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,