[FIR] Report separate error for delegated constructor call to interface

#KT-59216 Fixed
This commit is contained in:
Kirill Rakhman
2023-06-23 13:50:34 +02:00
committed by Space Team
parent 5abab2197b
commit e7c213e06e
19 changed files with 78 additions and 21 deletions
@@ -363,6 +363,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.NO_CONSTRUCTOR) { firDiagnostic ->
NoConstructorImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.FUNCTION_CALL_EXPECTED) { firDiagnostic ->
FunctionCallExpectedImpl(
firDiagnostic.a,
@@ -295,6 +295,10 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = CreatingAnInstanceOfAbstractClass::class
}
interface NoConstructor : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = NoConstructor::class
}
interface FunctionCallExpected : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = FunctionCallExpected::class
val functionName: String
@@ -339,6 +339,11 @@ internal class CreatingAnInstanceOfAbstractClassImpl(
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtExpression>(firDiagnostic, token), KtFirDiagnostic.CreatingAnInstanceOfAbstractClass
internal class NoConstructorImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.NoConstructor
internal class FunctionCallExpectedImpl(
override val functionName: String,
override val hasValueParameters: Boolean,
@@ -1,3 +1,3 @@
KtErrorCallInfo:
candidateCalls = []
diagnostic = ERROR<UNRESOLVED_REFERENCE: Unresolved reference: <init>>
diagnostic = ERROR<NO_CONSTRUCTOR: This type does not have a constructor.>
@@ -152,6 +152,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val CALL_RESOLUTION by object : DiagnosticGroup("Call resolution") {
val CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS by error<KtExpression>()
val NO_CONSTRUCTOR by error<PsiElement>(PositioningStrategy.VALUE_ARGUMENTS_LIST)
val FUNCTION_CALL_EXPECTED by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
parameter<String>("functionName")
parameter<Boolean>("hasValueParameters")
@@ -76,6 +76,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
USELESS_ELVIS,
NAME_OF_NAMED_ARGUMENT,
VALUE_ARGUMENTS,
VALUE_ARGUMENTS_LIST,
SUPERTYPES_LIST,
RETURN_WITH_LABEL,
PROPERTY_INITIALIZER,
@@ -165,6 +165,7 @@ object FirErrors {
// Call resolution
val CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS by error0<KtExpression>()
val NO_CONSTRUCTOR by error0<PsiElement>(SourceElementPositioningStrategies.VALUE_ARGUMENTS_LIST)
val FUNCTION_CALL_EXPECTED by error2<PsiElement, String, Boolean>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val ILLEGAL_SELECTOR by error0<PsiElement>()
val NO_RECEIVER_ALLOWED by error0<PsiElement>()
@@ -139,6 +139,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_GE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_NON_CONST_INITIALIZER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONTRACT_NOT_ALLOWED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_CONSTRUCTOR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CYCLE_IN_ANNOTATION_PARAMETER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CYCLIC_CONSTRUCTOR_DELEGATION_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CYCLIC_GENERIC_UPPER_BOUND
@@ -736,6 +737,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
TO_STRING
)
map.put(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, "Cannot create an instance of an abstract class")
map.put(NO_CONSTRUCTOR, "This type does not have a constructor.")
map.put(FUNCTION_CALL_EXPECTED, "Function invocation ''{0}({1})'' expected", TO_STRING, FUNCTION_PARAMETERS)
map.put(
FUNCTION_EXPECTED,
@@ -58,6 +58,7 @@ private fun ConeDiagnostic.toKtDiagnostic(
is ConeUnresolvedTypeQualifierError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.qualifier)
is ConeFunctionCallExpectedError -> FirErrors.FUNCTION_CALL_EXPECTED.createOn(source, this.name.asString(), this.hasValueParameters)
is ConeFunctionExpectedError -> FirErrors.FUNCTION_EXPECTED.createOn(source, this.expression, this.type)
is ConeNoConstructorError -> FirErrors.NO_CONSTRUCTOR.createOn(callOrAssignmentSource ?: source)
is ConeResolutionToClassifierError -> when (this.candidateSymbol.classKind) {
ClassKind.INTERFACE -> FirErrors.INTERFACE_AS_FUNCTION.createOn(source, this.candidateSymbol)
ClassKind.CLASS -> when {
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.hasExplicitBackingField
import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
import org.jetbrains.kotlin.fir.declarations.utils.isReferredViaField
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
@@ -697,10 +698,14 @@ class FirCallResolver(
}
candidates.isEmpty() -> {
if (name.asString() == "invoke" && explicitReceiver is FirConstExpression<*>) {
ConeFunctionExpectedError(explicitReceiver.value?.toString() ?: "", explicitReceiver.typeRef.coneType)
} else {
ConeUnresolvedNameError(name)
when {
name.asString() == "invoke" && explicitReceiver is FirConstExpression<*> ->
ConeFunctionExpectedError(
explicitReceiver.value?.toString() ?: "",
explicitReceiver.typeRef.coneType,
)
reference is FirSuperReference && (reference.superTypeRef.firClassLike(session) as? FirClass)?.isInterface == true -> ConeNoConstructorError
else -> ConeUnresolvedNameError(name)
}
}
@@ -82,6 +82,10 @@ class ConeFunctionExpectedError(val expression: String, val type: ConeKotlinType
override val reason: String get() = "Expression '$expression' of type '$type' cannot be invoked as a function"
}
object ConeNoConstructorError : ConeDiagnostic {
override val reason: String get() = "This type does not have a constructor"
}
class ConeResolutionToClassifierError(
override val candidate: AbstractCandidate,
override val candidateSymbol: FirRegularClassSymbol
@@ -558,6 +558,23 @@ object LightTreePositioningStrategies {
}
}
val VALUE_ARGUMENTS_LIST: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
override fun mark(
node: LighterASTNode,
startOffset: Int,
endOffset: Int,
tree: FlyweightCapableTreeStructure<LighterASTNode>,
): List<TextRange> {
return markElement(
tree.findChildByType(node, KtNodeTypes.VALUE_ARGUMENT_LIST) ?: node,
startOffset,
endOffset,
tree,
node
)
}
}
val VALUE_ARGUMENTS: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
override fun mark(
node: LighterASTNode,
@@ -707,6 +707,13 @@ object PositioningStrategies {
}
}
@JvmField
val VALUE_ARGUMENTS_LIST: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
override fun mark(element: KtElement): List<TextRange> {
return markElement(element.getChildOfType<KtValueArgumentList>() ?: element)
}
}
@JvmField
val FUNCTION_PARAMETERS: PositioningStrategy<KtFunction> = object : PositioningStrategy<KtFunction>() {
override fun mark(element: KtFunction): List<TextRange> {
@@ -163,6 +163,11 @@ object SourceElementPositioningStrategies {
PositioningStrategies.VALUE_ARGUMENTS
)
val VALUE_ARGUMENTS_LIST = SourceElementPositioningStrategy(
LightTreePositioningStrategies.VALUE_ARGUMENTS_LIST,
PositioningStrategies.VALUE_ARGUMENTS_LIST
)
val SUPERTYPES_LIST = SourceElementPositioningStrategy(
LightTreePositioningStrategies.SUPERTYPES_LIST,
PositioningStrategies.SUPERTYPES_LIST
@@ -2,12 +2,12 @@
// LANGUAGE: +ProhibitConstructorCallOnFunctionalSupertype
// ISSUE: KT-46344
abstract class A : <!UNRESOLVED_REFERENCE!>() -> Int<!>()
abstract class B : <!UNRESOLVED_REFERENCE!>(() -> Int)<!>()
abstract class C : <!UNRESOLVED_REFERENCE!>Function0<Int><!>()
abstract class D : <!UNRESOLVED_REFERENCE!>suspend () -> Int<!>()
abstract class E : <!UNRESOLVED_REFERENCE!>(suspend () -> Int)<!>()
abstract class F : <!UNRESOLVED_REFERENCE!>kotlin.coroutines.SuspendFunction0<Int><!>()
abstract class A : () -> Int<!NO_CONSTRUCTOR!>()<!>
abstract class B : (() -> Int)<!NO_CONSTRUCTOR!>()<!>
abstract class C : Function0<Int><!NO_CONSTRUCTOR!>()<!>
abstract class D : suspend () -> Int<!NO_CONSTRUCTOR!>()<!>
abstract class E : (suspend () -> Int)<!NO_CONSTRUCTOR!>()<!>
abstract class F : kotlin.coroutines.SuspendFunction0<Int><!NO_CONSTRUCTOR!>()<!>
interface IA : <!SUPERTYPE_INITIALIZED_IN_INTERFACE!>() -> Int<!>()
interface IB : <!SUPERTYPE_INITIALIZED_IN_INTERFACE!>(() -> Int)<!>()
@@ -2,12 +2,12 @@
// LANGUAGE: -ProhibitConstructorCallOnFunctionalSupertype
// ISSUE: KT-46344
abstract class A : <!UNRESOLVED_REFERENCE!>() -> Int<!>()
abstract class B : <!UNRESOLVED_REFERENCE!>(() -> Int)<!>()
abstract class C : <!UNRESOLVED_REFERENCE!>Function0<Int><!>()
abstract class D : <!UNRESOLVED_REFERENCE!>suspend () -> Int<!>()
abstract class E : <!UNRESOLVED_REFERENCE!>(suspend () -> Int)<!>()
abstract class F : <!UNRESOLVED_REFERENCE!>kotlin.coroutines.SuspendFunction0<Int><!>()
abstract class A : () -> Int<!NO_CONSTRUCTOR!>()<!>
abstract class B : (() -> Int)<!NO_CONSTRUCTOR!>()<!>
abstract class C : Function0<Int><!NO_CONSTRUCTOR!>()<!>
abstract class D : suspend () -> Int<!NO_CONSTRUCTOR!>()<!>
abstract class E : (suspend () -> Int)<!NO_CONSTRUCTOR!>()<!>
abstract class F : kotlin.coroutines.SuspendFunction0<Int><!NO_CONSTRUCTOR!>()<!>
interface IA : <!SUPERTYPE_INITIALIZED_IN_INTERFACE!>() -> Int<!>()
interface IB : <!SUPERTYPE_INITIALIZED_IN_INTERFACE!>(() -> Int)<!>()
@@ -1,8 +1,7 @@
// COMPARE_WITH_LIGHT_TREE
// FILE: test.kt
enum class MyEnum(): <!CLASS_IN_SUPERTYPE_FOR_ENUM!>MyClass<!>() {}
enum class MyEnum2(): MyTrait {}
enum class MyEnum2_1(): <!UNRESOLVED_REFERENCE!>MyTrait<!>() {}
enum class MyEnum2_1(): MyTrait<!NO_CONSTRUCTOR!>()<!> {}
enum class MyEnum3(): <!CLASS_IN_SUPERTYPE_FOR_ENUM, FINAL_SUPERTYPE, INVISIBLE_REFERENCE!>MyEnumBase<!>() {}
open class MyClass() {}
@@ -1,4 +1,3 @@
// COMPARE_WITH_LIGHT_TREE
// FILE: test.kt
enum class MyEnum(): <!CLASS_IN_SUPERTYPE_FOR_ENUM!>MyClass<!>() {}
enum class MyEnum2(): MyTrait {}
@@ -1,3 +1,3 @@
package typeReferenceError
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class Pair<!><<!SYNTAX!><!>:<!UNRESOLVED_REFERENCE!>(<!UNSUPPORTED!>val<!> c: <!SYNTAX!><!SYNTAX!><!>fun<!><!SYNTAX!><!> <!UNRESOLVED_REFERENCE!>main<!><!>()
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class Pair<!><<!SYNTAX!><!>:(<!UNSUPPORTED!>val<!> c: <!SYNTAX!><!SYNTAX!><!>fun<!><!SYNTAX!><!> <!UNRESOLVED_REFERENCE!>main<!><!NO_CONSTRUCTOR!>()<!>