[FIR] Print operator keyword and token to unresolved diagnostic message

#KT-55672 Fixed
This commit is contained in:
Kirill Rakhman
2023-08-23 13:29:16 +02:00
committed by Space Team
parent 85bb7faf10
commit c30ce4aabe
33 changed files with 257 additions and 49 deletions
@@ -296,6 +296,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
add(FirErrors.UNRESOLVED_REFERENCE) { firDiagnostic ->
UnresolvedReferenceImpl(
firDiagnostic.a,
firDiagnostic.b,
firDiagnostic as KtPsiDiagnostic,
token,
)
@@ -251,6 +251,7 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
interface UnresolvedReference : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = UnresolvedReference::class
val reference: String
val operator: String?
}
interface UnresolvedLabel : KtFirDiagnostic<PsiElement> {
@@ -285,6 +285,7 @@ internal class InvisibleReferenceImpl(
internal class UnresolvedReferenceImpl(
override val reference: String,
override val operator: String?,
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.UnresolvedReference
@@ -13,6 +13,6 @@ FILE: [ResolvedTo(IMPORTS)] arrayIndexExpressionWithInc.kt
[ResolvedTo(BODY_RESOLVE)] lval <array>: <ERROR TYPE REF: Unresolved name: ArrayList> = R|<local>/a|
[ResolvedTo(BODY_RESOLVE)] lval <index_0>: R|kotlin/Int| = Int(0)
[ResolvedTo(BODY_RESOLVE)] lval <unary>: <ERROR TYPE REF: Unresolved name: get> = R|<local>/<array>|.<Unresolved name: get>#(R|<local>/<index_0>|)
R|<local>/<array>|.<Unresolved name: set>#(R|<local>/<index_0>|, R|<local>/<unary>|.<Unresolved name: inc>#())
R|<local>/<array>|.<Unresolved name: set>#(R|<local>/<index_0>|, R|<local>/<unary>|.<Unresolved name: inc (++)>#())
R|<local>/<unary>|
}
@@ -13,6 +13,6 @@ FILE: [ResolvedTo(IMPORTS)] arrayIndexExpressionWithInc.kt
[ResolvedTo(BODY_RESOLVE)] lval <array>: R|java/util/ArrayList<kotlin/String>| = R|<local>/a|
[ResolvedTo(BODY_RESOLVE)] lval <index_0>: R|kotlin/Int| = Int(0)
[ResolvedTo(BODY_RESOLVE)] lval <unary>: R|kotlin/String| = R|<local>/<array>|.R|SubstitutionOverride<java/util/ArrayList.get: R|@EnhancedNullability kotlin/String|>|(R|<local>/<index_0>|)
R|<local>/<array>|.R|SubstitutionOverride<java/util/ArrayList.set: R|@EnhancedNullability kotlin/String|>|(R|<local>/<index_0>|, R|<local>/<unary>|.<Unresolved name: inc>#())
R|<local>/<array>|.R|SubstitutionOverride<java/util/ArrayList.set: R|@EnhancedNullability kotlin/String|>|(R|<local>/<index_0>|, R|<local>/<unary>|.<Unresolved name: inc (++)>#())
R|<local>/<unary>|
}
@@ -17,6 +17,6 @@ FILE: [ResolvedTo(IMPORTS)] arrayIndexExpressionWithIncScript.kts
[ResolvedTo(BODY_RESOLVE)] lval <array>: R|java/util/ArrayList<kotlin/String>| = R|<local>/a|
[ResolvedTo(BODY_RESOLVE)] lval <index_0>: R|kotlin/Int| = Int(0)
[ResolvedTo(BODY_RESOLVE)] lval <unary>: R|kotlin/String| = R|<local>/<array>|.R|SubstitutionOverride<java/util/ArrayList.get: R|@EnhancedNullability kotlin/String|>|(R|<local>/<index_0>|)
R|<local>/<array>|.R|SubstitutionOverride<java/util/ArrayList.set: R|@EnhancedNullability kotlin/String|>|(R|<local>/<index_0>|, R|<local>/<unary>|.<Unresolved name: inc>#())
R|<local>/<array>|.R|SubstitutionOverride<java/util/ArrayList.set: R|@EnhancedNullability kotlin/String|>|(R|<local>/<index_0>|, R|<local>/<unary>|.<Unresolved name: inc (++)>#())
R|<local>/<unary>|
}
}
@@ -16,7 +16,7 @@ FILE: [ResolvedTo(IMPORTS)] qualifiedPartOfQualifiedCallUnresolved.kt
{
[ResolvedTo(BODY_RESOLVE)] lval <receiver>: R|ERROR CLASS: Unresolved name: peek| = <Unresolved name: peek>#()
[ResolvedTo(BODY_RESOLVE)] lval <unary>: <ERROR TYPE REF: Unresolved name: braceBalance> = R|<local>/<receiver>|.<Unresolved name: braceBalance>#
R|<local>/<receiver>|.<Unresolved name: braceBalance># = R|<local>/<unary>|.<Unresolved name: inc>#()
R|<local>/<receiver>|.<Unresolved name: braceBalance># = R|<local>/<unary>|.<Unresolved name: inc (++)>#()
R|<local>/<unary>|
}
@@ -20,10 +20,10 @@ FILE: [ResolvedTo(IMPORTS)] qualifiedPartOfQualifiedCallUnresolvedScript.kts
{
[ResolvedTo(BODY_RESOLVE)] lval <receiver>: R|ERROR CLASS: Unresolved name: peek| = <Unresolved name: peek>#()
[ResolvedTo(BODY_RESOLVE)] lval <unary>: <ERROR TYPE REF: Unresolved name: braceBalance> = R|<local>/<receiver>|.<Unresolved name: braceBalance>#
R|<local>/<receiver>|.<Unresolved name: braceBalance># = R|<local>/<unary>|.<Unresolved name: inc>#()
R|<local>/<receiver>|.<Unresolved name: braceBalance># = R|<local>/<unary>|.<Unresolved name: inc (++)>#()
R|<local>/<unary>|
}
}
}
}
@@ -23958,6 +23958,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnVarAndCollections.kt");
}
@Test
@TestMetadata("unresolvedOperator.kt")
public void testUnresolvedOperator() throws Exception {
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/unresolvedOperator.kt");
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/operatorsOverloading/until")
@TestDataPath("$PROJECT_ROOT")
@@ -23958,6 +23958,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnVarAndCollections.kt");
}
@Test
@TestMetadata("unresolvedOperator.kt")
public void testUnresolvedOperator() throws Exception {
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/unresolvedOperator.kt");
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/operatorsOverloading/until")
@TestDataPath("$PROJECT_ROOT")
@@ -15,7 +15,7 @@ FILE: plusAssign.kt
}
public final fun test_1(): R|kotlin/Unit| {
lval f: R|Foo| = R|/Foo.Foo|()
R|<local>/f|.<Unresolved name: plus>#(R|<local>/f|)
R|<local>/f|.<Unresolved name: plus (+)>#(R|<local>/f|)
}
public final fun test_2(): R|kotlin/Unit| {
lval f: R|Foo| = R|/Foo.Foo|()
@@ -24,22 +24,22 @@ FILE: A.kt
public final fun rest(): R|kotlin/Unit| {
lval aI: R|kotlin/Int| = R|/A.A|().R|/A.a|.R|kotlin/Int.plus|(Int(10))
lval bI: R|kotlin/Int| = R|/A.A|().R|/A.b|.R|kotlin/Int.plus|(Int(20))
lval cI: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.c|.<Unresolved name: plus>#(Int(30))
lval dI: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.d|.<Unresolved name: plus>#(Int(40))
lval cI: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.c|.<Unresolved name: plus (+)>#(Int(30))
lval dI: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.d|.<Unresolved name: plus (+)>#(Int(40))
}
}
public final fun test(): R|kotlin/Unit| {
lval aA: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.a|.<Unresolved name: plus>#(Int(10))
lval aA: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.a|.<Unresolved name: plus (+)>#(Int(10))
lval bA: R|kotlin/Int| = R|/A.A|().R|/A.b|.R|kotlin/Int.plus|(Int(20))
lval cA: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.c|.<Unresolved name: plus>#(Int(30))
lval dA: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.d|.<Unresolved name: plus>#(Int(40))
lval cA: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.c|.<Unresolved name: plus (+)>#(Int(30))
lval dA: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.d|.<Unresolved name: plus (+)>#(Int(40))
}
Module: main
FILE: B.kt
public final fun main(): R|kotlin/Unit| {
lval aB: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.a|.<Unresolved name: plus>#(Int(10))
lval bB: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.b|.<Unresolved name: plus>#(Int(20))
lval cB: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.c|.<Unresolved name: plus>#(Int(30))
lval dB: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.d|.<Unresolved name: plus>#(Int(40))
lval aB: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.a|.<Unresolved name: plus (+)>#(Int(10))
lval bB: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.b|.<Unresolved name: plus (+)>#(Int(20))
lval cB: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.c|.<Unresolved name: plus (+)>#(Int(30))
lval dB: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.d|.<Unresolved name: plus (+)>#(Int(40))
}
@@ -22,24 +22,24 @@ FILE: A.kt
public get(): R|kotlin/Number|
public final fun rest(): R|kotlin/Unit| {
lval aI: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.a|.<Unresolved name: plus>#(Int(10))
lval bI: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.b|.<Unresolved name: plus>#(Int(20))
lval cI: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.c|.<Unresolved name: plus>#(Int(30))
lval dI: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.d|.<Unresolved name: plus>#(Int(40))
lval aI: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.a|.<Unresolved name: plus (+)>#(Int(10))
lval bI: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.b|.<Unresolved name: plus (+)>#(Int(20))
lval cI: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.c|.<Unresolved name: plus (+)>#(Int(30))
lval dI: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.d|.<Unresolved name: plus (+)>#(Int(40))
}
}
public final fun test(): R|kotlin/Unit| {
lval aA: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.a|.<Unresolved name: plus>#(Int(10))
lval bA: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.b|.<Unresolved name: plus>#(Int(20))
lval cA: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.c|.<Unresolved name: plus>#(Int(30))
lval dA: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.d|.<Unresolved name: plus>#(Int(40))
lval aA: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.a|.<Unresolved name: plus (+)>#(Int(10))
lval bA: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.b|.<Unresolved name: plus (+)>#(Int(20))
lval cA: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.c|.<Unresolved name: plus (+)>#(Int(30))
lval dA: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.d|.<Unresolved name: plus (+)>#(Int(40))
}
Module: main
FILE: B.kt
public final fun main(): R|kotlin/Unit| {
lval aB: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.a|.<Unresolved name: plus>#(Int(10))
lval bB: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.b|.<Unresolved name: plus>#(Int(20))
lval cB: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.c|.<Unresolved name: plus>#(Int(30))
lval dB: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.d|.<Unresolved name: plus>#(Int(40))
lval aB: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.a|.<Unresolved name: plus (+)>#(Int(10))
lval bB: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.b|.<Unresolved name: plus (+)>#(Int(20))
lval cB: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.c|.<Unresolved name: plus (+)>#(Int(30))
lval dB: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.d|.<Unresolved name: plus (+)>#(Int(40))
}
@@ -12,7 +12,7 @@ FILE: overriddenPropertiesWithExplicitBackingFields.kt
}
public final fun test(): R|kotlin/Unit| {
<Ambiguity: println, [kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println]>#(this@R|/A|.R|/A.it|.<Unresolved name: plus>#(Int(1)))
<Ambiguity: println, [kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println, kotlin/io/println]>#(this@R|/A|.R|/A.it|.<Unresolved name: plus (+)>#(Int(1)))
}
}
@@ -19,7 +19,7 @@ FILE: propertyTypeNarrowing.kt
}
public final fun test(): R|kotlin/Unit| {
lval c: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.it|.<Unresolved name: plus>#(Int(1))
lval c: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.it|.<Unresolved name: plus (+)>#(Int(1))
lval d: R|kotlin/Unit| = R|/test|()
lval b: R|kotlin/Int| = R|/A.A|().R|/A.p|.R|kotlin/Int.plus|(Int(2))
}
@@ -8,8 +8,8 @@ FILE: propertyTypeNarrowing.reversed.kt
private <explicit backing field>: R|kotlin/Int| = Int(4)
public get(): R|kotlin/Number|
public final fun test(): <ERROR TYPE REF: Unresolved name: plus> {
^test this@R|/A|.R|/A.it|.<Unresolved name: plus>#(Int(3))
public final fun test(): <ERROR TYPE REF: Unresolved name: plus (+)> {
^test this@R|/A|.R|/A.it|.<Unresolved name: plus (+)>#(Int(3))
}
public final val p: R|kotlin/Int| = Int(5)
@@ -19,7 +19,7 @@ FILE: propertyTypeNarrowing.reversed.kt
}
public final fun test(): R|kotlin/Unit| {
lval c: <ERROR TYPE REF: Unresolved name: plus> = R|/A.A|().R|/A.it|.<Unresolved name: plus>#(Int(1))
lval c: <ERROR TYPE REF: Unresolved name: plus (+)> = R|/A.A|().R|/A.it|.<Unresolved name: plus (+)>#(Int(1))
lval d: R|kotlin/Unit| = R|/test|()
lval b: R|kotlin/Int| = R|/A.A|().R|/A.p|.R|kotlin/Int.plus|(Int(2))
}
@@ -23958,6 +23958,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnVarAndCollections.kt");
}
@Test
@TestMetadata("unresolvedOperator.kt")
public void testUnresolvedOperator() throws Exception {
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/unresolvedOperator.kt");
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/operatorsOverloading/until")
@TestDataPath("$PROJECT_ROOT")
@@ -23964,6 +23964,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnVarAndCollections.kt");
}
@Test
@TestMetadata("unresolvedOperator.kt")
public void testUnresolvedOperator() throws Exception {
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/unresolvedOperator.kt");
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/operatorsOverloading/until")
@TestDataPath("$PROJECT_ROOT")
@@ -118,6 +118,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
}
val UNRESOLVED_REFERENCE by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
parameter<String>("reference")
parameter<String?>("operator")
}
val UNRESOLVED_LABEL by error<PsiElement>(PositioningStrategy.LABEL)
val DESERIALIZATION_ERROR by error<PsiElement>()
@@ -158,7 +158,7 @@ object FirErrors {
// Unresolved
val INVISIBLE_REFERENCE by error3<PsiElement, FirBasedSymbol<*>, Visibility, ClassId?>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val UNRESOLVED_REFERENCE by error1<PsiElement, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val UNRESOLVED_REFERENCE by error2<PsiElement, String, String?>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val UNRESOLVED_LABEL by error0<PsiElement>(SourceElementPositioningStrategies.LABEL)
val DESERIALIZATION_ERROR by error0<PsiElement>()
val ERROR_FROM_JAVA_RESOLUTION by error0<PsiElement>()
@@ -189,4 +189,8 @@ object FirDiagnosticRenderers {
val OPTIONAL_SENTENCE = Renderer { it: String? ->
if (!it.isNullOrBlank()) " $it." else ""
}
val FOR_OPTIONAL_OPERATOR = Renderer { it: String? ->
if (!it.isNullOrBlank()) " for operator '$it'" else ""
}
}
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.diagnostics.rendering.LanguageFeatureMessageRenderer
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.AMBIGUOUS_CALLS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.CALLEE_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.DECLARATION_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FOR_OPTIONAL_OPERATOR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FQ_NAMES_IN_TYPES
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FUNCTIONAL_TYPE_KINDS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.MODULE_DATA
@@ -771,7 +772,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
TO_STRING
)
map.put(MISSING_CONSTRUCTOR_KEYWORD, "Use the 'constructor' keyword after the modifiers of the primary constructor.")
map.put(UNRESOLVED_REFERENCE, "Unresolved reference ''{0}''.", NULLABLE_STRING)
map.put(UNRESOLVED_REFERENCE, "Unresolved reference ''{0}''{1}.", NULLABLE_STRING, FOR_OPTIONAL_OPERATOR)
map.put(UNRESOLVED_IMPORT, "Unresolved reference ''{0}''.", NULLABLE_STRING) // &
map.put(DUPLICATE_PARAMETER_NAME_IN_FUNCTION_TYPE, "Duplicate parameter name in a function type.")
map.put(UNRESOLVED_LABEL, "Unresolved label.")
@@ -50,12 +50,13 @@ private fun ConeDiagnostic.toKtDiagnostic(
): KtDiagnostic? = when (this) {
is ConeUnresolvedReferenceError -> FirErrors.UNRESOLVED_REFERENCE.createOn(
source,
this.name.asString()
this.name.asString(),
null,
)
is ConeUnresolvedSymbolError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.classId.asString())
is ConeUnresolvedNameError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.name.asString())
is ConeUnresolvedTypeQualifierError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.qualifier)
is ConeUnresolvedSymbolError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.classId.asString(), null)
is ConeUnresolvedNameError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, name.asString(), operatorToken)
is ConeUnresolvedTypeQualifierError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.qualifier, null)
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)
@@ -73,7 +74,8 @@ private fun ConeDiagnostic.toKtDiagnostic(
// See: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-deprecated/
FirErrors.UNRESOLVED_REFERENCE.createOn(
source,
((this.candidateSymbol as? FirCallableSymbol)?.name ?: SpecialNames.NO_NAME_PROVIDED).asString()
((this.candidateSymbol as? FirCallableSymbol)?.name ?: SpecialNames.NO_NAME_PROVIDED).asString(),
null,
)
}
@@ -53,6 +53,8 @@ import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.CodeFragmentAdjustment
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.runIf
class FirCallResolver(
private val components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents,
@@ -700,6 +702,9 @@ class FirCallResolver(
expectedCandidates: Collection<Candidate>? = null
): FirNamedReference {
val source = reference.source
val operatorToken = runIf(callInfo.origin == FirFunctionCallOrigin.Operator) {
OperatorNameConventions.TOKENS_BY_OPERATOR_NAME[name]
}
val diagnostic = when {
expectedCallKind != null -> {
@@ -738,7 +743,7 @@ class FirCallResolver(
singleExpectedCandidate
)
}
else -> ConeUnresolvedNameError(name)
else -> ConeUnresolvedNameError(name, operatorToken)
}
}
}
@@ -754,7 +759,7 @@ class FirCallResolver(
explicitReceiver.resolvedType,
)
reference is FirSuperReference && (reference.superTypeRef.firClassLike(session) as? FirClass)?.isInterface == true -> ConeNoConstructorError
else -> ConeUnresolvedNameError(name)
else -> ConeUnresolvedNameError(name, operatorToken)
}
}
@@ -65,9 +65,18 @@ class ConeUnresolvedTypeQualifierError(val qualifiers: List<FirQualifierPart>, o
override val reason: String get() = "Symbol not found for $qualifier${if (isNullable) "?" else ""}"
}
class ConeUnresolvedNameError(val name: Name) : ConeUnresolvedError {
class ConeUnresolvedNameError(
val name: Name,
val operatorToken: String? = null,
) : ConeUnresolvedError {
override val qualifier: String get() = name.asString()
override val reason: String get() = "Unresolved name: $name"
override val reason: String get() = "Unresolved name: $prettyReference"
private val prettyReference: String
get() = when (val token = operatorToken) {
null -> name.toString()
else -> "$name ($token)"
}
}
class ConeFunctionCallExpectedError(
@@ -0,0 +1,37 @@
/unresolvedOperator.kt:6:6: error: unresolved reference: ++
a++
^
/unresolvedOperator.kt:7:6: error: unresolved reference: --
a--
^
/unresolvedOperator.kt:8:5: error: unresolved reference: +
+a
^
/unresolvedOperator.kt:9:5: error: unresolved reference: -
-a
^
/unresolvedOperator.kt:10:5: error: unresolved reference: !
!a
^
/unresolvedOperator.kt:11:7: error: unresolved reference: *
a * a
^
/unresolvedOperator.kt:12:10: error: unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public operator fun String?.plus(other: Any?): String defined in kotlin
true + false
^
/unresolvedOperator.kt:13:7: error: unresolved reference: -
a - a
^
/unresolvedOperator.kt:14:7: error: unresolved reference: /
a / a
^
/unresolvedOperator.kt:15:7: error: unresolved reference: %
a % a
^
/unresolvedOperator.kt:16:7: error: unresolved reference: ..
a .. a
^
/unresolvedOperator.kt:17:7: error: unresolved reference: ..<
a ..< a
^
@@ -0,0 +1,23 @@
/unresolvedOperator.fir.kt:(67,69): error: Unresolved reference 'inc' for operator '++'.
/unresolvedOperator.fir.kt:(75,77): error: Unresolved reference 'dec' for operator '--'.
/unresolvedOperator.fir.kt:(82,83): error: Unresolved reference 'unaryPlus' for operator '+'.
/unresolvedOperator.fir.kt:(89,90): error: Unresolved reference 'unaryMinus' for operator '-'.
/unresolvedOperator.fir.kt:(96,97): error: Unresolved reference 'not' for operator '!'.
/unresolvedOperator.fir.kt:(105,106): error: Unresolved reference 'times' for operator '*'.
/unresolvedOperator.fir.kt:(118,119): error: Unresolved reference 'plus' for operator '+'.
/unresolvedOperator.fir.kt:(132,133): error: Unresolved reference 'minus' for operator '-'.
/unresolvedOperator.fir.kt:(142,143): error: Unresolved reference 'div' for operator '/'.
/unresolvedOperator.fir.kt:(152,153): error: Unresolved reference 'rem' for operator '%'.
/unresolvedOperator.fir.kt:(162,164): error: Unresolved reference 'rangeTo' for operator '..'.
/unresolvedOperator.fir.kt:(173,176): error: Unresolved reference 'rangeUntil' for operator '..<'.
@@ -0,0 +1,18 @@
// RENDER_DIAGNOSTICS_FULL_TEXT
fun test() {
var a = ""
a<!UNRESOLVED_REFERENCE!>++<!>
a<!UNRESOLVED_REFERENCE!>--<!>
<!UNRESOLVED_REFERENCE!>+<!>a
<!UNRESOLVED_REFERENCE!>-<!>a
<!UNRESOLVED_REFERENCE!>!<!>a
a <!UNRESOLVED_REFERENCE!>*<!> a
true <!UNRESOLVED_REFERENCE!>+<!> false
a <!UNRESOLVED_REFERENCE!>-<!> a
a <!UNRESOLVED_REFERENCE!>/<!> a
a <!UNRESOLVED_REFERENCE!>%<!> a
a <!UNRESOLVED_REFERENCE!>..<!> a
a <!UNRESOLVED_REFERENCE!>..<<!> a
}
@@ -0,0 +1,18 @@
// RENDER_DIAGNOSTICS_FULL_TEXT
fun test() {
var a = ""
a<!UNRESOLVED_REFERENCE!>++<!>
a<!UNRESOLVED_REFERENCE!>--<!>
<!UNRESOLVED_REFERENCE!>+<!>a
<!UNRESOLVED_REFERENCE!>-<!>a
<!UNRESOLVED_REFERENCE!>!<!>a
a <!UNRESOLVED_REFERENCE!>*<!> a
true <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>+<!> false
a <!UNRESOLVED_REFERENCE!>-<!> a
a <!UNRESOLVED_REFERENCE!>/<!> a
a <!UNRESOLVED_REFERENCE!>%<!> a
a <!UNRESOLVED_REFERENCE!>..<!> a
a <!UNRESOLVED_REFERENCE!>..<<!> a
}
@@ -25578,6 +25578,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnVarAndCollections.kt");
}
@Test
@TestMetadata("unresolvedOperator.kt")
public void testUnresolvedOperator() throws Exception {
runTest("compiler/testData/diagnostics/tests/operatorsOverloading/unresolvedOperator.kt");
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/operatorsOverloading/until")
@TestDataPath("$PROJECT_ROOT")
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2023 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.psi
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
class OperatorNamesToSymbolsTest {
@Test
fun testAllOperatorsMapped() {
val allEntries = OperatorNameConventions.TOKENS_BY_OPERATOR_NAME.toMutableMap()
val mapName = "${OperatorNameConventions::class.java.simpleName}.${OperatorNameConventions::TOKENS_BY_OPERATOR_NAME.name}"
fun check(token: KtSingleValueToken, name: Name) {
val mappedToken = allEntries.remove(name)
assertNotNull(mappedToken, "'$name' not in $mapName")
assertEquals(token.value, mappedToken, "Token not matching")
}
for ((token, name) in OperatorConventions.UNARY_OPERATION_NAMES) {
check(token, name)
}
for ((token, name) in OperatorConventions.BINARY_OPERATION_NAMES) {
check(token, name)
}
assertTrue(
allEntries.isEmpty(),
"Entries in $mapName that were not in ${OperatorConventions::class.java.simpleName}: ${allEntries.entries.joinToString()}"
)
}
}
@@ -98,4 +98,19 @@ object OperatorNameConventions {
@JvmField
val STATEMENT_LIKE_OPERATORS = setOf(SET) + ASSIGNMENT_OPERATIONS
val TOKENS_BY_OPERATOR_NAME = mapOf(
INC to "++",
DEC to "--",
UNARY_PLUS to "+",
UNARY_MINUS to "-",
NOT to "!",
TIMES to "*",
PLUS to "+",
MINUS to "-",
DIV to "/",
REM to "%",
RANGE_TO to "..",
RANGE_UNTIL to "..<",
)
}
@@ -10,8 +10,8 @@ FILE: receiverInjection.kt
public final fun <T> injectAlgebra(): R|kotlin/Unit| {
}
public final fun test_1(a1: R|A|, a2: R|A|, b1: R|B|, b2: R|B|): R|kotlin/Unit| {
R|<local>/a1|.<Unresolved name: plus>#(R|<local>/a2|)
R|<local>/b1|.<Unresolved name: plus>#(R|<local>/b2|)
R|<local>/a1|.<Unresolved name: plus (+)>#(R|<local>/a2|)
R|<local>/b1|.<Unresolved name: plus (+)>#(R|<local>/b2|)
R|/injectAlgebra|<R|A|>()
(this@R|/test_1|, R|<local>/a1|).R|SubstitutionOverride</Algebra.plus: R|A|>|(R|<local>/a2|)
(this@R|/test_1|, R|<local>/b1|).R|SubstitutionOverride</Algebra.plus: R|A|><None of the following candidates is applicable because of receiver type mismatch: [/Algebra.plus]>#|(R|<local>/b2|)
@@ -20,7 +20,7 @@ FILE: receiverInjection.kt
(this@R|/test_1|, R|<local>/b1|).R|SubstitutionOverride</Algebra.plus: R|B|>|(R|<local>/b2|)
}
public final fun test_2(a1: R|A|, a2: R|A|, cond: R|kotlin/Boolean|): R|kotlin/Unit| {
R|<local>/a1|.<Unresolved name: plus>#(R|<local>/a2|)
R|<local>/a1|.<Unresolved name: plus (+)>#(R|<local>/a2|)
when () {
R|<local>/cond| -> {
R|/injectAlgebra|<R|A|>()
@@ -28,5 +28,5 @@ FILE: receiverInjection.kt
}
}
R|<local>/a1|.<Unresolved name: plus>#(R|<local>/a2|)
R|<local>/a1|.<Unresolved name: plus (+)>#(R|<local>/a2|)
}