[FIR] Prohibit statement-like expressions in expression context
^KT-61067 Fixed
This commit is contained in:
+6
@@ -93,6 +93,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
|||||||
runTest("compiler/testData/diagnostics/tests/AssignToArrayElement.kt");
|
runTest("compiler/testData/diagnostics/tests/AssignToArrayElement.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("assigningAssignments.kt")
|
||||||
|
public void testAssigningAssignments() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/assigningAssignments.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("AutoCreatedIt.kt")
|
@TestMetadata("AutoCreatedIt.kt")
|
||||||
public void testAutoCreatedIt() throws Exception {
|
public void testAutoCreatedIt() throws Exception {
|
||||||
|
|||||||
+6
@@ -93,6 +93,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
|||||||
runTest("compiler/testData/diagnostics/tests/AssignToArrayElement.kt");
|
runTest("compiler/testData/diagnostics/tests/AssignToArrayElement.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("assigningAssignments.kt")
|
||||||
|
public void testAssigningAssignments() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/assigningAssignments.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("AutoCreatedIt.kt")
|
@TestMetadata("AutoCreatedIt.kt")
|
||||||
public void testAutoCreatedIt() throws Exception {
|
public void testAutoCreatedIt() throws Exception {
|
||||||
|
|||||||
+6
@@ -93,6 +93,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
|||||||
runTest("compiler/testData/diagnostics/tests/AssignToArrayElement.kt");
|
runTest("compiler/testData/diagnostics/tests/AssignToArrayElement.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("assigningAssignments.kt")
|
||||||
|
public void testAssigningAssignments() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/assigningAssignments.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("AutoCreatedIt.kt")
|
@TestMetadata("AutoCreatedIt.kt")
|
||||||
public void testAutoCreatedIt() throws Exception {
|
public void testAutoCreatedIt() throws Exception {
|
||||||
|
|||||||
+6
@@ -93,6 +93,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
|||||||
runTest("compiler/testData/diagnostics/tests/AssignToArrayElement.kt");
|
runTest("compiler/testData/diagnostics/tests/AssignToArrayElement.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("assigningAssignments.kt")
|
||||||
|
public void testAssigningAssignments() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/assigningAssignments.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("AutoCreatedIt.kt")
|
@TestMetadata("AutoCreatedIt.kt")
|
||||||
public void testAutoCreatedIt() throws Exception {
|
public void testAutoCreatedIt() throws Exception {
|
||||||
|
|||||||
+2
-2
@@ -143,7 +143,7 @@ class LightTreeRawFirDeclarationBuilder(
|
|||||||
DESTRUCTURING_DECLARATION -> container += convertDestructingDeclaration(node).toFirDestructingDeclaration(baseModuleData)
|
DESTRUCTURING_DECLARATION -> container += convertDestructingDeclaration(node).toFirDestructingDeclaration(baseModuleData)
|
||||||
TYPEALIAS -> container += convertTypeAlias(node) as FirStatement
|
TYPEALIAS -> container += convertTypeAlias(node) as FirStatement
|
||||||
CLASS_INITIALIZER -> container += convertAnonymousInitializer(node) as FirStatement
|
CLASS_INITIALIZER -> container += convertAnonymousInitializer(node) as FirStatement
|
||||||
else -> if (node.isExpression()) container += expressionConverter.getAsFirExpression<FirStatement>(node)
|
else -> if (node.isExpression()) container += expressionConverter.getAsFirStatement(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return FirBlockBuilder().apply {
|
return FirBlockBuilder().apply {
|
||||||
@@ -1839,7 +1839,7 @@ class LightTreeRawFirDeclarationBuilder(
|
|||||||
if (block == null) return buildEmptyExpressionBlock()
|
if (block == null) return buildEmptyExpressionBlock()
|
||||||
if (block.tokenType != BLOCK) {
|
if (block.tokenType != BLOCK) {
|
||||||
return FirSingleExpressionBlock(
|
return FirSingleExpressionBlock(
|
||||||
expressionConverter.getAsFirExpression(block)
|
expressionConverter.getAsFirStatement(block)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+43
-10
@@ -60,15 +60,41 @@ class LightTreeRawFirExpressionBuilder(
|
|||||||
context: Context<LighterASTNode> = Context(),
|
context: Context<LighterASTNode> = Context(),
|
||||||
) : AbstractLightTreeRawFirBuilder(session, tree, context) {
|
) : AbstractLightTreeRawFirBuilder(session, tree, context) {
|
||||||
|
|
||||||
inline fun <reified R : FirElement> getAsFirExpression(expression: LighterASTNode?, errorReason: String = ""): R {
|
inline fun <reified R : FirExpression> getAsFirExpression(
|
||||||
|
expression: LighterASTNode?,
|
||||||
|
errorReason: String = "",
|
||||||
|
sourceWhenInvalidExpression: LighterASTNode? = expression,
|
||||||
|
isValidExpression: (R) -> Boolean = { !it.isStatementLikeExpression },
|
||||||
|
): R {
|
||||||
val converted = expression?.let { convertExpression(it, errorReason) }
|
val converted = expression?.let { convertExpression(it, errorReason) }
|
||||||
return converted as? R
|
|
||||||
?: buildErrorExpression(
|
return when {
|
||||||
expression?.toFirSourceElement(),
|
converted is R -> when {
|
||||||
|
isValidExpression(converted) -> converted
|
||||||
|
else -> buildErrorExpression(
|
||||||
|
sourceWhenInvalidExpression?.toFirSourceElement(),
|
||||||
|
ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionExpected),
|
||||||
|
converted,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> buildErrorExpression(
|
||||||
|
converted?.source?.withForcedKindFrom(context) ?: expression?.toFirSourceElement(),
|
||||||
if (expression == null) ConeSyntaxDiagnostic(errorReason)
|
if (expression == null) ConeSyntaxDiagnostic(errorReason)
|
||||||
else ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionExpected),
|
else ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionExpected),
|
||||||
converted,
|
converted,
|
||||||
) as R
|
)
|
||||||
|
} as R
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAsFirStatement(expression: LighterASTNode, errorReason: String = ""): FirStatement {
|
||||||
|
return when (val converted = convertExpression(expression, errorReason)) {
|
||||||
|
is FirStatement -> converted
|
||||||
|
else -> buildErrorExpression(
|
||||||
|
expression.toFirSourceElement(),
|
||||||
|
ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionExpected),
|
||||||
|
converted,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** EXPRESSIONS *****/
|
/***** EXPRESSIONS *****/
|
||||||
@@ -316,7 +342,14 @@ class LightTreeRawFirExpressionBuilder(
|
|||||||
firOperation,
|
firOperation,
|
||||||
leftArgAsFir.annotations,
|
leftArgAsFir.annotations,
|
||||||
rightArg,
|
rightArg,
|
||||||
) { getAsFirExpression(this) }
|
) {
|
||||||
|
getAsFirExpression<FirExpression>(
|
||||||
|
this,
|
||||||
|
"Incorrect expression in assignment: ${binaryExpression.asText}",
|
||||||
|
sourceWhenInvalidExpression = binaryExpression,
|
||||||
|
isValidExpression = { !it.isStatementLikeExpression || it.isArraySet },
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
buildEqualityOperatorCall {
|
buildEqualityOperatorCall {
|
||||||
source = binaryExpression.toFirSourceElement()
|
source = binaryExpression.toFirSourceElement()
|
||||||
@@ -379,7 +412,7 @@ class LightTreeRawFirExpressionBuilder(
|
|||||||
}
|
}
|
||||||
BLOCK -> firExpression = declarationBuilder.convertBlock(it)
|
BLOCK -> firExpression = declarationBuilder.convertBlock(it)
|
||||||
PROPERTY -> firExpression = declarationBuilder.convertPropertyDeclaration(it)
|
PROPERTY -> firExpression = declarationBuilder.convertPropertyDeclaration(it)
|
||||||
else -> if (it.isExpression()) firExpression = getAsFirExpression(it)
|
else -> if (it.isExpression()) firExpression = getAsFirStatement(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,7 +490,7 @@ class LightTreeRawFirExpressionBuilder(
|
|||||||
BLOCK -> firExpression = declarationBuilder.convertBlockExpression(it)
|
BLOCK -> firExpression = declarationBuilder.convertBlockExpression(it)
|
||||||
else -> if (it.isExpression()) {
|
else -> if (it.isExpression()) {
|
||||||
context.forwardLabelUsagePermission(annotatedExpression, it)
|
context.forwardLabelUsagePermission(annotatedExpression, it)
|
||||||
firExpression = getAsFirExpression(it)
|
firExpression = getAsFirStatement(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1209,10 +1242,10 @@ class LightTreeRawFirExpressionBuilder(
|
|||||||
if (it.getChildNodeByType(BLOCK) != null) {
|
if (it.getChildNodeByType(BLOCK) != null) {
|
||||||
firBlock = getAsFirExpression(it)
|
firBlock = getAsFirExpression(it)
|
||||||
} else {
|
} else {
|
||||||
firStatement = getAsFirExpression(it)
|
firStatement = getAsFirStatement(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> if (it.isExpression()) firStatement = getAsFirExpression(it)
|
else -> if (it.isExpression()) firStatement = getAsFirStatement(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-19
@@ -47,10 +47,7 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
|||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.*
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
|
|
||||||
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
|
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
|
||||||
import org.jetbrains.kotlin.utils.exceptions.requireWithAttachment
|
import org.jetbrains.kotlin.utils.exceptions.requireWithAttachment
|
||||||
import org.jetbrains.kotlin.utils.exceptions.withPsiEntry
|
import org.jetbrains.kotlin.utils.exceptions.withPsiEntry
|
||||||
@@ -297,28 +294,33 @@ open class PsiRawFirBuilder(
|
|||||||
): FirExpression = toFirExpression { ConeSimpleDiagnostic(errorReason, kind) }
|
): FirExpression = toFirExpression { ConeSimpleDiagnostic(errorReason, kind) }
|
||||||
|
|
||||||
private inline fun KtElement?.toFirExpression(
|
private inline fun KtElement?.toFirExpression(
|
||||||
sourceWhenThisIsNull: PsiElement? = null,
|
sourceWhenThisIsNull: KtElement? = null,
|
||||||
|
sourceWhenInvalidExpression: KtElement? = this,
|
||||||
|
isValidExpression: (FirExpression) -> Boolean = { !it.isStatementLikeExpression },
|
||||||
diagnosticFn: () -> ConeDiagnostic,
|
diagnosticFn: () -> ConeDiagnostic,
|
||||||
): FirExpression {
|
): FirExpression {
|
||||||
if (this == null) {
|
if (this == null) {
|
||||||
return buildErrorExpression(source = sourceWhenThisIsNull?.toFirSourceElement(), diagnosticFn())
|
return buildErrorExpression(source = sourceWhenThisIsNull?.toFirSourceElement(), diagnosticFn())
|
||||||
}
|
}
|
||||||
|
|
||||||
val result = when (val fir = convertElement(this, null)) {
|
return when (val fir = convertElement(this, null)) {
|
||||||
is FirExpression -> fir
|
is FirExpression -> when {
|
||||||
else -> {
|
isValidExpression(fir) -> checkSelectorInvariant(fir)
|
||||||
return buildErrorExpression {
|
else -> buildErrorExpression {
|
||||||
nonExpressionElement = fir
|
nonExpressionElement = fir
|
||||||
diagnostic = diagnosticFn()
|
diagnostic = diagnosticFn()
|
||||||
source = toFirSourceElement()
|
source = sourceWhenInvalidExpression?.toFirSourceElement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else -> buildErrorExpression {
|
||||||
|
nonExpressionElement = fir
|
||||||
|
diagnostic = diagnosticFn()
|
||||||
|
source = fir?.source?.withForcedKindFrom(this@PsiRawFirBuilder.context) ?: toFirSourceElement()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return toFirExpression(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtElement.toFirExpression(result: FirExpression): FirExpression {
|
private fun KtElement.checkSelectorInvariant(result: FirExpression): FirExpression {
|
||||||
val callExpressionCallee = (this as? KtCallExpression)?.calleeExpression?.unwrapParenthesesLabelsAndAnnotations()
|
val callExpressionCallee = (this as? KtCallExpression)?.calleeExpression?.unwrapParenthesesLabelsAndAnnotations()
|
||||||
|
|
||||||
if (this is KtNameReferenceExpression ||
|
if (this is KtNameReferenceExpression ||
|
||||||
@@ -2700,7 +2702,15 @@ open class PsiRawFirBuilder(
|
|||||||
leftArgument.annotations,
|
leftArgument.annotations,
|
||||||
expression.right,
|
expression.right,
|
||||||
) {
|
) {
|
||||||
(this as KtExpression).toFirExpression("Incorrect expression in assignment: ${expression.text}")
|
(this as KtExpression).toFirExpression(
|
||||||
|
sourceWhenInvalidExpression = expression,
|
||||||
|
isValidExpression = { !it.isStatementLikeExpression || it.isArraySet },
|
||||||
|
) {
|
||||||
|
ConeSimpleDiagnostic(
|
||||||
|
"Incorrect expression in assignment: ${expression.text}",
|
||||||
|
DiagnosticKind.ExpressionExpected
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buildEqualityOperatorCall {
|
buildEqualityOperatorCall {
|
||||||
@@ -2926,11 +2936,7 @@ open class PsiRawFirBuilder(
|
|||||||
|
|
||||||
override fun visitParenthesizedExpression(expression: KtParenthesizedExpression, data: FirElement?): FirElement {
|
override fun visitParenthesizedExpression(expression: KtParenthesizedExpression, data: FirElement?): FirElement {
|
||||||
context.forwardLabelUsagePermission(expression, expression.expression)
|
context.forwardLabelUsagePermission(expression, expression.expression)
|
||||||
return expression.expression?.accept(this, data)
|
return expression.expression.toFirExpression("Empty parentheses")
|
||||||
?: buildErrorExpression(
|
|
||||||
expression.toFirSourceElement(),
|
|
||||||
ConeSyntaxDiagnostic("Empty parentheses")
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLabeledExpression(expression: KtLabeledExpression, data: FirElement?): FirElement {
|
override fun visitLabeledExpression(expression: KtLabeledExpression, data: FirElement?): FirElement {
|
||||||
|
|||||||
+9
@@ -51,6 +51,7 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
|
import org.jetbrains.kotlin.realElement
|
||||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
@@ -696,3 +697,11 @@ fun AnnotationUseSiteTarget?.appliesToPrimaryConstructorParameter() = this == nu
|
|||||||
this == AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER ||
|
this == AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER ||
|
||||||
this == AnnotationUseSiteTarget.RECEIVER ||
|
this == AnnotationUseSiteTarget.RECEIVER ||
|
||||||
this == AnnotationUseSiteTarget.FILE
|
this == AnnotationUseSiteTarget.FILE
|
||||||
|
|
||||||
|
fun KtSourceElement.withForcedKindFrom(context: Context<*>): KtSourceElement {
|
||||||
|
return when (val forcedKind = context.forcedElementSourceKind) {
|
||||||
|
kind -> this
|
||||||
|
is KtFakeSourceElementKind -> fakeElement(forcedKind)
|
||||||
|
else -> this.realElement()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
|||||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||||
import org.jetbrains.kotlin.types.SmartcastStability
|
import org.jetbrains.kotlin.types.SmartcastStability
|
||||||
import org.jetbrains.kotlin.types.model.safeSubstitute
|
import org.jetbrains.kotlin.types.model.safeSubstitute
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
|
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
|
||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
@@ -490,7 +489,7 @@ fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck(
|
|||||||
val selector = selector
|
val selector = selector
|
||||||
|
|
||||||
val resultingType = when {
|
val resultingType = when {
|
||||||
selector is FirExpression && !selector.isCallToStatementLikeFunction -> {
|
selector is FirExpression && !selector.isStatementLikeExpression -> {
|
||||||
val type = selector.coneTypeSafe<ConeKotlinType>() ?: return
|
val type = selector.coneTypeSafe<ConeKotlinType>() ?: return
|
||||||
type.withNullability(ConeNullability.NULLABLE, session.typeContext)
|
type.withNullability(ConeNullability.NULLABLE, session.typeContext)
|
||||||
}
|
}
|
||||||
@@ -506,12 +505,6 @@ fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck(
|
|||||||
session.lookupTracker?.recordTypeResolveAsLookup(independentInstance, source, file.source)
|
session.lookupTracker?.recordTypeResolveAsLookup(independentInstance, source, file.source)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val FirExpression.isCallToStatementLikeFunction: Boolean
|
|
||||||
get() {
|
|
||||||
val symbol = (this as? FirFunctionCall)?.calleeReference?.toResolvedNamedFunctionSymbol() ?: return false
|
|
||||||
return origin == FirFunctionCallOrigin.Operator && symbol.name in OperatorNameConventions.STATEMENT_LIKE_OPERATORS
|
|
||||||
}
|
|
||||||
|
|
||||||
fun FirAnnotation.getCorrespondingClassSymbolOrNull(session: FirSession): FirRegularClassSymbol? {
|
fun FirAnnotation.getCorrespondingClassSymbolOrNull(session: FirSession): FirRegularClassSymbol? {
|
||||||
return annotationTypeRef.coneType.fullyExpandedType(session).toRegularClassSymbol(session)
|
return annotationTypeRef.coneType.fullyExpandedType(session).toRegularClassSymbol(session)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,12 +17,16 @@ import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass
|
|||||||
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirBlock
|
import org.jetbrains.kotlin.fir.expressions.FirBlock
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCallOrigin
|
||||||
import org.jetbrains.kotlin.fir.renderer.FirRenderer
|
import org.jetbrains.kotlin.fir.renderer.FirRenderer
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.builder.*
|
import org.jetbrains.kotlin.fir.types.builder.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.*
|
import org.jetbrains.kotlin.fir.types.impl.*
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions.STATEMENT_LIKE_OPERATORS
|
||||||
import org.jetbrains.kotlin.util.wrapIntoFileAnalysisExceptionIfNeeded
|
import org.jetbrains.kotlin.util.wrapIntoFileAnalysisExceptionIfNeeded
|
||||||
import org.jetbrains.kotlin.util.wrapIntoSourceCodeAnalysisExceptionIfNeeded
|
import org.jetbrains.kotlin.util.wrapIntoSourceCodeAnalysisExceptionIfNeeded
|
||||||
|
|
||||||
@@ -254,3 +258,18 @@ fun <T> List<T>.smartPlus(other: List<T>): List<T> = when {
|
|||||||
|
|
||||||
// Source element may be missing if the class came from a library
|
// Source element may be missing if the class came from a library
|
||||||
fun FirVariable.isEnumEntries(containingClass: FirClass) = isStatic && name == StandardNames.ENUM_ENTRIES && containingClass.isEnumClass
|
fun FirVariable.isEnumEntries(containingClass: FirClass) = isStatic && name == StandardNames.ENUM_ENTRIES && containingClass.isEnumClass
|
||||||
|
|
||||||
|
val FirExpression.isArraySet: Boolean
|
||||||
|
get() {
|
||||||
|
val name = (this as? FirFunctionCall)?.calleeReference?.name ?: return false
|
||||||
|
return origin == FirFunctionCallOrigin.Operator && name == OperatorNameConventions.SET
|
||||||
|
}
|
||||||
|
|
||||||
|
val FirExpression.isStatementLikeExpression: Boolean
|
||||||
|
get() = when (this) {
|
||||||
|
is FirFunctionCall -> origin == FirFunctionCallOrigin.Operator && calleeReference.name in STATEMENT_LIKE_OPERATORS
|
||||||
|
else -> isIndexedAssignment
|
||||||
|
}
|
||||||
|
|
||||||
|
private val FirExpression.isIndexedAssignment: Boolean
|
||||||
|
get() = this is FirBlock && statements.lastOrNull()?.source?.kind == KtFakeSourceElementKind.ImplicitUnit.IndexedAssignmentCoercion
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// ISSUE: KT-61067
|
||||||
|
// DIAGNOSTICS: -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val storages: HashMap<String, String> = HashMap<String, String>()
|
||||||
|
val a = <!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>storages<!NO_SET_METHOD!>["4"]<!> = ""<!> //K1 compile error - Kotlin: Assignments are not expressions, and only expressions are allowed in this context
|
||||||
|
storages<!NO_SET_METHOD!>["4"]<!> = ""
|
||||||
|
|
||||||
|
var nonStorages: Int = 10
|
||||||
|
val b = <!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>nonStorages = 20<!>
|
||||||
|
nonStorages = 20
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// ISSUE: KT-61067
|
||||||
|
// DIAGNOSTICS: -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val storages: HashMap<String, String> = HashMap<String, String>()
|
||||||
|
val a = <!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>storages<!NO_SET_METHOD!><!UNRESOLVED_REFERENCE!>[<!>"4"<!UNRESOLVED_REFERENCE!>]<!><!> = ""<!> //K1 compile error - Kotlin: Assignments are not expressions, and only expressions are allowed in this context
|
||||||
|
storages<!NO_SET_METHOD!><!UNRESOLVED_REFERENCE!>[<!>"4"<!UNRESOLVED_REFERENCE!>]<!><!> = ""
|
||||||
|
|
||||||
|
var nonStorages: Int = 10
|
||||||
|
val b = <!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>nonStorages = 20<!>
|
||||||
|
nonStorages = 20
|
||||||
|
}
|
||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
fun test() {
|
fun test() {
|
||||||
(d@ val bar = 2)
|
(d@ <!EXPRESSION_EXPECTED!>val bar = 2<!>)
|
||||||
}
|
}
|
||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
fun foo() {
|
fun foo() {
|
||||||
class A
|
class A
|
||||||
<!CONFLICTING_OVERLOADS!>fun bar()<!> {}
|
fun bar() {}
|
||||||
(<!CONFLICTING_OVERLOADS!>fun bar()<!> {})
|
(<!ANONYMOUS_FUNCTION_WITH_NAME!>fun bar() {}<!>)
|
||||||
<!CONFLICTING_OVERLOADS!>fun A.foo()<!> {}
|
fun A.foo() {}
|
||||||
(<!CONFLICTING_OVERLOADS!>fun A.foo()<!> {})
|
(<!ANONYMOUS_FUNCTION_WITH_NAME!>fun A.foo() {}<!>)
|
||||||
|
|
||||||
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>run<!>(<!ANONYMOUS_FUNCTION_WITH_NAME!>fun foo() {}<!>)
|
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>run<!>(<!ANONYMOUS_FUNCTION_WITH_NAME!>fun foo() {}<!>)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
//KT-629 Assignments are parsed as expressions.
|
|
||||||
|
|
||||||
package kt629
|
|
||||||
|
|
||||||
class A() {
|
|
||||||
var p = "yeah"
|
|
||||||
operator fun rem(other : A) : A {
|
|
||||||
return A();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun box() : Boolean {
|
|
||||||
var c = A()
|
|
||||||
val d = c;
|
|
||||||
c %= A();
|
|
||||||
return (c != d) && <!EXPRESSION_EXPECTED!>(c.p = "yeah")<!>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun box2() : Boolean {
|
|
||||||
var c = A()
|
|
||||||
return <!EXPRESSION_EXPECTED!>(c.p = "yeah")<!> && true
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
//KT-629 Assignments are parsed as expressions.
|
//KT-629 Assignments are parsed as expressions.
|
||||||
|
|
||||||
package kt629
|
package kt629
|
||||||
|
|||||||
+12
-12
@@ -122,12 +122,12 @@ fun testWithSubject_bad_4(b: B) {
|
|||||||
}
|
}
|
||||||
// also bad
|
// also bad
|
||||||
when (b) {
|
when (b) {
|
||||||
<!EXPRESSION_EXPECTED!>(x = b)<!> -> {}
|
(<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>x = b<!>) -> {}
|
||||||
<!EXPRESSION_EXPECTED!>(b += b)<!> -> {}
|
(<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b += b<!>) -> {}
|
||||||
<!EXPRESSION_EXPECTED!>(b -= b)<!> -> {}
|
(<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b -= b<!>) -> {}
|
||||||
<!EXPRESSION_EXPECTED!>(b *= b)<!> -> {}
|
(<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b *= b<!>) -> {}
|
||||||
<!EXPRESSION_EXPECTED!>(b /= b)<!> -> {}
|
(<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b /= b<!>) -> {}
|
||||||
<!EXPRESSION_EXPECTED!>(b %= b)<!> -> {}
|
(<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b %= b<!>) -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,11 +226,11 @@ fun testWithRange_bad_4(b: B) {
|
|||||||
}
|
}
|
||||||
// also bad
|
// also bad
|
||||||
when (b) {
|
when (b) {
|
||||||
in <!EXPRESSION_EXPECTED!>(x = b)<!> -> {}
|
in (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>x = b<!>) -> {}
|
||||||
in <!EXPRESSION_EXPECTED!>(b += b)<!> -> {}
|
in (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b += b<!>) -> {}
|
||||||
in <!EXPRESSION_EXPECTED!>(b -= b)<!> -> {}
|
in (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b -= b<!>) -> {}
|
||||||
in <!EXPRESSION_EXPECTED!>(b *= b)<!> -> {}
|
in (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b *= b<!>) -> {}
|
||||||
in <!EXPRESSION_EXPECTED!>(b /= b)<!> -> {}
|
in (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b /= b<!>) -> {}
|
||||||
in <!EXPRESSION_EXPECTED!>(b %= b)<!> -> {}
|
in (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b %= b<!>) -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-12
@@ -122,12 +122,12 @@ fun testWithSubject_bad_4(b: B) {
|
|||||||
}
|
}
|
||||||
// also bad
|
// also bad
|
||||||
when (b) {
|
when (b) {
|
||||||
<!EXPRESSION_EXPECTED!>(x = b)<!> -> {}
|
(<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>x = b<!>) -> {}
|
||||||
<!EXPRESSION_EXPECTED!>(b += b)<!> -> {}
|
(<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b += b<!>) -> {}
|
||||||
<!EXPRESSION_EXPECTED!>(b -= b)<!> -> {}
|
(<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b -= b<!>) -> {}
|
||||||
<!EXPRESSION_EXPECTED!>(b *= b)<!> -> {}
|
(<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b *= b<!>) -> {}
|
||||||
<!EXPRESSION_EXPECTED!>(b /= b)<!> -> {}
|
(<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b /= b<!>) -> {}
|
||||||
<!EXPRESSION_EXPECTED!>(b %= b)<!> -> {}
|
(<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b %= b<!>) -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,11 +226,11 @@ fun testWithRange_bad_4(b: B) {
|
|||||||
}
|
}
|
||||||
// also bad
|
// also bad
|
||||||
when (b) {
|
when (b) {
|
||||||
in <!EXPRESSION_EXPECTED!>(x = b)<!> -> {}
|
in (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>x = b<!>) -> {}
|
||||||
in <!EXPRESSION_EXPECTED!>(b += b)<!> -> {}
|
in (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b += b<!>) -> {}
|
||||||
in <!EXPRESSION_EXPECTED!>(b -= b)<!> -> {}
|
in (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b -= b<!>) -> {}
|
||||||
in <!EXPRESSION_EXPECTED!>(b *= b)<!> -> {}
|
in (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b *= b<!>) -> {}
|
||||||
in <!EXPRESSION_EXPECTED!>(b /= b)<!> -> {}
|
in (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b /= b<!>) -> {}
|
||||||
in <!EXPRESSION_EXPECTED!>(b %= b)<!> -> {}
|
in (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>b %= b<!>) -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+6
@@ -93,6 +93,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/AssignToArrayElement.kt");
|
runTest("compiler/testData/diagnostics/tests/AssignToArrayElement.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("assigningAssignments.kt")
|
||||||
|
public void testAssigningAssignments() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/assigningAssignments.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("AutoCreatedIt.kt")
|
@TestMetadata("AutoCreatedIt.kt")
|
||||||
public void testAutoCreatedIt() throws Exception {
|
public void testAutoCreatedIt() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user