[FIR] Prohibit statement-like expressions in expression context

^KT-61067 Fixed
This commit is contained in:
Nikolay Lunyak
2023-08-11 14:56:02 +03:00
parent 5c19cb3fcb
commit b25a67a50e
19 changed files with 183 additions and 91 deletions
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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)
) )
} }
@@ -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)
} }
} }
@@ -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 {
@@ -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,3 +1,3 @@
fun test() { fun test() {
(d@ val bar = 2) (d@ <!EXPRESSION_EXPECTED!>val bar = 2<!>)
} }
@@ -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
@@ -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<!>) -> {}
} }
} }
@@ -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<!>) -> {}
} }
} }
@@ -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 {