FIR checker: report PROPERTY_AS_OPERATOR
This commit is contained in:
committed by
Mikhail Glukhikh
parent
4915d8dda3
commit
05fbed68e2
+3
@@ -1145,6 +1145,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<FirNamedFunctionSymbol>("functionSymbol")
|
||||
parameter<String>("operator")
|
||||
}
|
||||
val PROPERTY_AS_OPERATOR by error<PsiElement>(PositioningStrategy.OPERATOR) {
|
||||
parameter<FirPropertySymbol>("property")
|
||||
}
|
||||
}
|
||||
|
||||
val TYPE_ALIAS by object : DiagnosticGroup("Type alias") {
|
||||
|
||||
@@ -596,6 +596,7 @@ object FirErrors {
|
||||
val INCOMPATIBLE_ENUM_COMPARISON_ERROR by error2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||
val INC_DEC_SHOULD_NOT_RETURN_UNIT by error0<KtExpression>(SourceElementPositioningStrategies.OPERATOR)
|
||||
val ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT by error2<KtExpression, FirNamedFunctionSymbol, String>(SourceElementPositioningStrategies.OPERATOR)
|
||||
val PROPERTY_AS_OPERATOR by error1<PsiElement, FirPropertySymbol>(SourceElementPositioningStrategies.OPERATOR)
|
||||
|
||||
// Type alias
|
||||
val TOPLEVEL_TYPEALIASES_ONLY by error0<KtTypeAlias>()
|
||||
|
||||
+29
@@ -6,17 +6,26 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
|
||||
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.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
|
||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConePropertyAsOperator
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
|
||||
object FirConventionFunctionCallChecker : FirFunctionCallChecker() {
|
||||
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
// PROPERTY_AS_OPERATOR can only happen for function calls and it's reported on the receiver expression.
|
||||
checkPropertyAsOperator(expression, expression.dispatchReceiver, context, reporter)
|
||||
checkPropertyAsOperator(expression, expression.extensionReceiver, context, reporter)
|
||||
val calleeReference = expression.calleeReference as? FirErrorNamedReference ?: return
|
||||
val diagnostic = calleeReference.diagnostic as? ConeUnresolvedNameError ?: return
|
||||
|
||||
@@ -27,4 +36,24 @@ object FirConventionFunctionCallChecker : FirFunctionCallChecker() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkPropertyAsOperator(
|
||||
callExpression: FirFunctionCall,
|
||||
receiver: FirExpression,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
val sourceKind = callExpression.source?.kind
|
||||
if (sourceKind !is FirRealSourceElementKind &&
|
||||
sourceKind !is FirFakeSourceElementKind.GeneratedComparisonExpression &&
|
||||
sourceKind !is FirFakeSourceElementKind.DesugaredCompoundAssignment
|
||||
) return
|
||||
val unwrapped = when (receiver) {
|
||||
is FirExpressionWithSmartcast -> receiver.originalExpression
|
||||
else -> receiver
|
||||
}
|
||||
if (unwrapped !is FirPropertyAccessExpression) return
|
||||
val diagnostic = unwrapped.nonFatalDiagnostics.firstIsInstanceOrNull<ConePropertyAsOperator>() ?: return
|
||||
reporter.reportOn(callExpression.calleeReference.source, FirErrors.PROPERTY_AS_OPERATOR, diagnostic.symbol, context)
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -332,6 +332,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIVATE_SETTER_FO
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIVATE_SETTER_FOR_OPEN_PROPERTY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_AS_OPERATOR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_IN_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_NO_BACKING_FIELD
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_TYPE_MISMATCH_BY_DELEGATION
|
||||
@@ -1515,6 +1516,11 @@ class FirDefaultErrorMessages {
|
||||
SYMBOL,
|
||||
TO_STRING
|
||||
)
|
||||
map.put(
|
||||
PROPERTY_AS_OPERATOR,
|
||||
"Property ''{0}'' cannot be used as an operator.",
|
||||
SYMBOL
|
||||
)
|
||||
|
||||
// Type alias
|
||||
map.put(TOPLEVEL_TYPEALIASES_ONLY, "Nested and local type aliases are not supported")
|
||||
|
||||
@@ -84,11 +84,11 @@ class FirCallResolver(
|
||||
|
||||
return components.context.withIncrementedQualifierPartIndex {
|
||||
val name = functionCall.calleeReference.name
|
||||
val result = collectCandidates(functionCall, name)
|
||||
val result = collectCandidates(functionCall, name, origin = functionCall.origin)
|
||||
|
||||
var forceCandidates: Collection<Candidate>? = null
|
||||
if (result.candidates.isEmpty()) {
|
||||
val newResult = collectCandidates(functionCall, name, CallKind.VariableAccess)
|
||||
val newResult = collectCandidates(functionCall, name, CallKind.VariableAccess, origin = functionCall.origin)
|
||||
if (newResult.candidates.isNotEmpty()) {
|
||||
forceCandidates = newResult.candidates
|
||||
}
|
||||
@@ -152,7 +152,8 @@ class FirCallResolver(
|
||||
private fun <T : FirQualifiedAccess> collectCandidates(
|
||||
qualifiedAccess: T,
|
||||
name: Name,
|
||||
forceCallKind: CallKind? = null
|
||||
forceCallKind: CallKind? = null,
|
||||
origin: FirFunctionCallOrigin = FirFunctionCallOrigin.Regular
|
||||
): ResolutionResult {
|
||||
val explicitReceiver = qualifiedAccess.explicitReceiver
|
||||
val argumentList = (qualifiedAccess as? FirFunctionCall)?.argumentList ?: FirEmptyArgumentList
|
||||
@@ -172,6 +173,7 @@ class FirCallResolver(
|
||||
session,
|
||||
components.file,
|
||||
transformer.components.containingDeclarations,
|
||||
origin = origin
|
||||
)
|
||||
towerResolver.reset()
|
||||
val result = towerResolver.runResolver(info, transformer.resolutionContext)
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirArgumentList
|
||||
import org.jetbrains.kotlin.fir.expressions.FirEmptyArgumentList
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCallOrigin
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||
@@ -55,7 +56,8 @@ data class CallInfo(
|
||||
// Four properties for callable references only
|
||||
val expectedType: ConeKotlinType? = null,
|
||||
val outerCSBuilder: ConstraintSystemBuilder? = null,
|
||||
val lhs: DoubleColonLHS? = null
|
||||
val lhs: DoubleColonLHS? = null,
|
||||
val origin: FirFunctionCallOrigin = FirFunctionCallOrigin.Regular,
|
||||
) {
|
||||
val arguments: List<FirExpression> get() = argumentList.arguments
|
||||
|
||||
|
||||
@@ -82,6 +82,10 @@ class CandidateFactory private constructor(
|
||||
) {
|
||||
result.addDiagnostic(NoCompanionObject)
|
||||
}
|
||||
if (callInfo.origin == FirFunctionCallOrigin.Operator && symbol is FirPropertySymbol) {
|
||||
// Flag all property references that are resolved from an convention operator call.
|
||||
result.addDiagnostic(PropertyAsOperator)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -98,4 +98,6 @@ class ManyLambdaExpressionArguments(
|
||||
class InfixCallOfNonInfixFunction(val function: FirNamedFunctionSymbol) : ResolutionDiagnostic(INAPPLICABLE_MODIFIER)
|
||||
class OperatorCallOfNonOperatorFunction(val function: FirNamedFunctionSymbol) : ResolutionDiagnostic(INAPPLICABLE_MODIFIER)
|
||||
|
||||
class Unsupported(val message: String, val source: FirSourceElement? = null) : ResolutionDiagnostic(UNSUPPORTED)
|
||||
class Unsupported(val message: String, val source: FirSourceElement? = null) : ResolutionDiagnostic(UNSUPPORTED)
|
||||
|
||||
object PropertyAsOperator : ResolutionDiagnostic(PROPERTY_AS_OPERATOR)
|
||||
+7
-4
@@ -11,14 +11,13 @@ import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.FirPropertyAccessExpressionBuilder
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConePropertyAsOperator
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
||||
import org.jetbrains.kotlin.fir.types.isExtensionFunctionType
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
internal class FirInvokeResolveTowerExtension(
|
||||
@@ -291,6 +290,10 @@ private fun BodyResolveComponents.createExplicitReceiverForInvokeByCallable(
|
||||
// NB: this should fix problem in DFA (KT-36014)
|
||||
explicitReceiver = info.explicitReceiver
|
||||
}
|
||||
|
||||
if (candidate.currentApplicability == CandidateApplicability.PROPERTY_AS_OPERATOR) {
|
||||
nonFatalDiagnostics.add(ConePropertyAsOperator(candidate.symbol as FirPropertySymbol))
|
||||
}
|
||||
}.build().let(::transformQualifiedAccessUsingSmartcastInfo)
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -206,6 +206,10 @@ class ConeLocalVariableNoTypeOrInitializer(val variable: FirVariable) : ConeDiag
|
||||
override val reason: String get() = "Cannot infer variable type without initializer / getter / delegate"
|
||||
}
|
||||
|
||||
class ConePropertyAsOperator(val symbol: FirPropertySymbol) : ConeDiagnostic {
|
||||
override val reason: String get() = "Cannot use a property as an operator"
|
||||
}
|
||||
|
||||
private fun describeSymbol(symbol: FirBasedSymbol<*>): String {
|
||||
return when (symbol) {
|
||||
is FirClassLikeSymbol<*> -> symbol.classId.asString()
|
||||
|
||||
+7
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
|
||||
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.expressions.impl.FirPropertyAccessExpressionImpl
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedCallableReference
|
||||
@@ -26,6 +27,7 @@ import org.jetbrains.kotlin.fir.resolve.createFunctionalType
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.FirDataFlowAnalyzer
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeConstraintSystemHasContradiction
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConePropertyAsOperator
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeTypeParameterInQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.resolve.firProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.*
|
||||
@@ -39,6 +41,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
@@ -48,6 +51,7 @@ import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -126,6 +130,9 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
)
|
||||
.transformDispatchReceiver(StoreReceiver, subCandidate.dispatchReceiverExpression())
|
||||
.transformExtensionReceiver(StoreReceiver, subCandidate.extensionReceiverExpression()) as T
|
||||
if (result is FirPropertyAccessExpressionImpl && calleeReference.candidate.currentApplicability == CandidateApplicability.PROPERTY_AS_OPERATOR) {
|
||||
result.nonFatalDiagnostics.add(ConePropertyAsOperator(calleeReference.candidate.symbol as FirPropertySymbol))
|
||||
}
|
||||
|
||||
if (result is FirQualifiedAccessExpression) {
|
||||
result.replaceTypeRef(typeRef)
|
||||
|
||||
+1
@@ -20,6 +20,7 @@ enum class CandidateApplicability {
|
||||
UNSTABLE_SMARTCAST, // unstable smart cast
|
||||
CONVENTION_ERROR, // missing infix, operator etc
|
||||
RESOLVED_LOW_PRIORITY,
|
||||
PROPERTY_AS_OPERATOR, // using property of functional type as an operator. From resolution perspective, this is considered successful.
|
||||
RESOLVED_NEED_PRESERVE_COMPATIBILITY, // call resolved successfully, but using new features that changes resolve
|
||||
RESOLVED_WITH_ERROR, // call has error, but it is still successful from resolution perspective
|
||||
RESOLVED, // call success or has uncompleted inference or in other words possible successful candidate
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
|
||||
val Int.plusAssign: (Int) -> Unit
|
||||
get() = {}
|
||||
|
||||
fun main() {
|
||||
1 += 2
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: +NewInference
|
||||
|
||||
val Int.plusAssign: (Int) -> Unit
|
||||
|
||||
+32
-7
@@ -73,19 +73,44 @@ class Arifm() {
|
||||
operator fun invoke(i: Int) {}
|
||||
}
|
||||
|
||||
class Contains() {
|
||||
operator fun invoke(i: Int): Boolean = true
|
||||
}
|
||||
|
||||
class Getter() {
|
||||
operator fun invoke(i: Int): Int = 1
|
||||
}
|
||||
|
||||
class Setter() {
|
||||
operator fun invoke(i: Int, j: Int) {}
|
||||
}
|
||||
|
||||
class Unary<B>() {
|
||||
operator fun invoke(): B = TODO()
|
||||
}
|
||||
|
||||
class B() {
|
||||
val plus = Arifm()
|
||||
val minus = Arifm()
|
||||
val compareTo = Comp()
|
||||
val contains = Contains()
|
||||
val get = Getter()
|
||||
val set = Setter()
|
||||
val unaryPlus = Unary<B>()
|
||||
}
|
||||
|
||||
fun case3() {
|
||||
var b = B()
|
||||
b + 5
|
||||
b - 5
|
||||
b < 5
|
||||
b >= 5
|
||||
b <!PROPERTY_AS_OPERATOR!>+<!> 5
|
||||
b <!PROPERTY_AS_OPERATOR!>-<!> 5
|
||||
b <!PROPERTY_AS_OPERATOR!><<!> 5
|
||||
b <!PROPERTY_AS_OPERATOR!>>=<!> 5
|
||||
1 <!PROPERTY_AS_OPERATOR!>in<!> b
|
||||
<!PROPERTY_AS_OPERATOR!>b[2]<!>
|
||||
<!PROPERTY_AS_OPERATOR!>b[3]<!> = 4
|
||||
<!PROPERTY_AS_OPERATOR!>+<!>b
|
||||
}
|
||||
|
||||
// FILE: TestCase4.kt
|
||||
/*
|
||||
* TESTCASE NUMBER: 4
|
||||
@@ -102,8 +127,8 @@ class B(val minusAssign: Assign = Assign()) {
|
||||
|
||||
fun case3() {
|
||||
var b = B()
|
||||
b += 2
|
||||
b -= 3
|
||||
b <!PROPERTY_AS_OPERATOR!>+=<!> 2
|
||||
b <!PROPERTY_AS_OPERATOR!>-=<!> 3
|
||||
}
|
||||
|
||||
// FILE: TestCase5.kt
|
||||
@@ -142,7 +167,7 @@ class B(var a: Int = 0) {
|
||||
val plus :E =TODO()
|
||||
|
||||
fun foo(b: B){
|
||||
this + 1
|
||||
this <!PROPERTY_AS_OPERATOR!>+<!> 1
|
||||
}
|
||||
|
||||
operator fun invoke(value: Int) = B()
|
||||
|
||||
+25
@@ -82,10 +82,30 @@ class Arifm() {
|
||||
operator fun invoke(i: Int) {}
|
||||
}
|
||||
|
||||
class Contains() {
|
||||
operator fun invoke(i: Int): Boolean = true
|
||||
}
|
||||
|
||||
class Getter() {
|
||||
operator fun invoke(i: Int): Int = 1
|
||||
}
|
||||
|
||||
class Setter() {
|
||||
operator fun invoke(i: Int, j: Int) {}
|
||||
}
|
||||
|
||||
class Unary<B>() {
|
||||
operator fun invoke(): B = TODO()
|
||||
}
|
||||
|
||||
class B() {
|
||||
val plus = Arifm()
|
||||
val minus = Arifm()
|
||||
val compareTo = Comp()
|
||||
val contains = Contains()
|
||||
val get = Getter()
|
||||
val set = Setter()
|
||||
val unaryPlus = Unary<B>()
|
||||
}
|
||||
|
||||
fun case3() {
|
||||
@@ -94,7 +114,12 @@ fun case3() {
|
||||
b <!PROPERTY_AS_OPERATOR!>-<!> 5
|
||||
b <!PROPERTY_AS_OPERATOR!><<!> 5
|
||||
b <!PROPERTY_AS_OPERATOR!>>=<!> 5
|
||||
1 <!PROPERTY_AS_OPERATOR!>in<!> b
|
||||
<!PROPERTY_AS_OPERATOR!>b[2]<!>
|
||||
<!PROPERTY_AS_OPERATOR!>b[3]<!> = 4
|
||||
<!PROPERTY_AS_OPERATOR!>+<!>b
|
||||
}
|
||||
|
||||
// FILE: TestCase4.kt
|
||||
/*
|
||||
* TESTCASE NUMBER: 4
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ class B() {
|
||||
fun case7(){
|
||||
var b =B()
|
||||
<!ASSIGN_OPERATOR_AMBIGUITY!>b+=1<!> //ASSIGN_OPERATOR_AMBIGUITY
|
||||
this += 1 //ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT, PROPERTY_AS_OPERATOR
|
||||
this <!PROPERTY_AS_OPERATOR!>+=<!> 1 //ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT, PROPERTY_AS_OPERATOR
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@ class Case1() {
|
||||
fun foo(e: E) {
|
||||
|
||||
if (e.plus != null) {
|
||||
run { e + 1 }
|
||||
run { e <!PROPERTY_AS_OPERATOR!>+<!> 1 }
|
||||
|
||||
/*
|
||||
[PROPERTY_AS_OPERATOR] (ok)
|
||||
@@ -22,7 +22,7 @@ class Case1() {
|
||||
[UNSAFE_OPERATOR_CALL] (nok)
|
||||
Operator call corresponds to a dot-qualified call 'e.plus(1)' which is not allowed on a nullable receiver 'e'.
|
||||
*/
|
||||
e + 1
|
||||
e <!PROPERTY_AS_OPERATOR!>+<!> 1
|
||||
|
||||
e.plus.invoke(1) //ok
|
||||
}
|
||||
|
||||
+7
@@ -3131,6 +3131,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.PROPERTY_AS_OPERATOR) { firDiagnostic ->
|
||||
PropertyAsOperatorImpl(
|
||||
firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firDiagnostic.a.fir),
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.TOPLEVEL_TYPEALIASES_ONLY) { firDiagnostic ->
|
||||
ToplevelTypealiasesOnlyImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
|
||||
+5
@@ -2186,6 +2186,11 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val operator: String
|
||||
}
|
||||
|
||||
abstract class PropertyAsOperator : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = PropertyAsOperator::class
|
||||
abstract val property: KtVariableSymbol
|
||||
}
|
||||
|
||||
abstract class ToplevelTypealiasesOnly : KtFirDiagnostic<KtTypeAlias>() {
|
||||
override val diagnosticClass get() = ToplevelTypealiasesOnly::class
|
||||
}
|
||||
|
||||
+8
@@ -3522,6 +3522,14 @@ internal class AssignmentOperatorShouldReturnUnitImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class PropertyAsOperatorImpl(
|
||||
override val property: KtVariableSymbol,
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.PropertyAsOperator(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ToplevelTypealiasesOnlyImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
|
||||
Reference in New Issue
Block a user