From 2f02024c247780b00b72870137b0cc52278d69bf Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Wed, 1 Apr 2015 14:18:53 +0300 Subject: [PATCH] checkLValue for array indexing expression should resolve set method #KT-7218 Fixed --- .../BasicExpressionTypingVisitor.java | 30 ++++++++++++++----- .../ExpressionTypingVisitorForStatements.java | 9 +++--- .../diagnostics/tests/AssignToArrayElement.kt | 10 +++++++ .../tests/AssignToArrayElement.txt | 5 ++++ .../diagnostics/tests/LValueAssignment.kt | 6 ++-- .../checkers/JetDiagnosticsTestGenerated.java | 6 ++++ 6 files changed, 52 insertions(+), 14 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/AssignToArrayElement.kt create mode 100644 compiler/testData/diagnostics/tests/AssignToArrayElement.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index d8eaaa7b240..01c7578e30e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -835,8 +835,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } else { context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression); - - checkLValue(context.trace, baseExpression); + JetExpression stubExpression = ExpressionTypingUtils.createFakeExpressionOfType(baseExpression.getProject(), context.trace, "$e", type); + checkLValue(context.trace, context, baseExpression, stubExpression); } // TODO : Maybe returnType? result = receiverType; @@ -939,18 +939,34 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { /** * @return {@code true} iff expression can be assigned to */ - public static boolean checkLValue(@NotNull BindingTrace trace, @NotNull JetExpression expression) { - return checkLValue(trace, expression, false); + public boolean checkLValue( + @NotNull BindingTrace trace, + @NotNull ExpressionTypingContext context, + @NotNull JetExpression expression, + @NotNull JetExpression rightHandSide + ) { + return checkLValue(trace, context, expression, rightHandSide, false); } - private static boolean checkLValue(@NotNull BindingTrace trace, @NotNull JetExpression expressionWithParenthesis, boolean canBeThis) { + private boolean checkLValue( + @NotNull BindingTrace trace, + @NotNull ExpressionTypingContext context, + @NotNull JetExpression expressionWithParenthesis, + @NotNull JetExpression rightHandSide, + boolean canBeThis + ) { JetExpression expression = JetPsiUtil.deparenthesize(expressionWithParenthesis); if (expression instanceof JetArrayAccessExpression) { - JetExpression arrayExpression = ((JetArrayAccessExpression) expression).getArrayExpression(); + JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) expression; + JetExpression arrayExpression = arrayAccessExpression.getArrayExpression(); if (arrayExpression == null) return false; - return checkLValue(trace, arrayExpression, true); + TemporaryBindingTrace ignoreReportsTrace = TemporaryBindingTrace.create(trace, "Trace for checking set function"); + ExpressionTypingContext findSetterContext = context.replaceBindingTrace(ignoreReportsTrace); + JetTypeInfo info = resolveArrayAccessSetMethod(arrayAccessExpression, rightHandSide, findSetterContext, ignoreReportsTrace); + return info.getType() != null; } + if (canBeThis && expression instanceof JetThisExpression) return true; VariableDescriptor variable = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), expression, true); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java index 710aa07870c..43de648074a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java @@ -269,7 +269,8 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito JetType binaryOperationType; TemporaryTraceAndCache temporaryForBinaryOperation = TemporaryTraceAndCache.create( context, "trace to check binary operation like '+' for", expression); - boolean lhsAssignable = BasicExpressionTypingVisitor.checkLValue(TemporaryBindingTrace.create(context.trace, "Trace for checking assignability"), left); + TemporaryBindingTrace ignoreReportsTrace = TemporaryBindingTrace.create(context.trace, "Trace for checking assignability"); + boolean lhsAssignable = basic.checkLValue(ignoreReportsTrace, context, left, right); if (assignmentOperationType == null || lhsAssignable) { // Check for '+' Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType)); @@ -314,7 +315,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito } dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); DataFlowUtils.checkType(binaryOperationType, expression, context.replaceExpectedType(leftType).replaceDataFlowInfo(dataFlowInfo)); - BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand); + basic.checkLValue(context.trace, context, leftOperand, right); } temporary.commit(); return JetTypeInfo.create(checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo); @@ -331,7 +332,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left; if (right == null) return JetTypeInfo.create(null, context.dataFlowInfo); JetTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace); - BasicExpressionTypingVisitor.checkLValue(context.trace, arrayAccessExpression); + basic.checkLValue(context.trace, context, arrayAccessExpression, right); return JetTypeInfo.create(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType), typeInfo.getDataFlowInfo()); } @@ -349,7 +350,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito } } if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated - BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand); + basic.checkLValue(context.trace, context, leftOperand, right); } return DataFlowUtils.checkStatementType(expression, contextWithExpectedType, dataFlowInfo); } diff --git a/compiler/testData/diagnostics/tests/AssignToArrayElement.kt b/compiler/testData/diagnostics/tests/AssignToArrayElement.kt new file mode 100644 index 00000000000..43f8284a476 --- /dev/null +++ b/compiler/testData/diagnostics/tests/AssignToArrayElement.kt @@ -0,0 +1,10 @@ +fun getArray(): Array = throw Exception() +fun getList(): MutableList = throw Exception() +fun fn() { + getArray()[1] = 2 + getList()[1] = 2 + getArray()[1]++ + getList()[1]++ + getArray()[1] += 2 + getList()[1] += 2 +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/AssignToArrayElement.txt b/compiler/testData/diagnostics/tests/AssignToArrayElement.txt new file mode 100644 index 00000000000..eb9477f5653 --- /dev/null +++ b/compiler/testData/diagnostics/tests/AssignToArrayElement.txt @@ -0,0 +1,5 @@ +package + +internal fun fn(): kotlin.Unit +internal fun getArray(): kotlin.Array +internal fun getList(): kotlin.MutableList diff --git a/compiler/testData/diagnostics/tests/LValueAssignment.kt b/compiler/testData/diagnostics/tests/LValueAssignment.kt index c5bd66ba5c9..baf5760f486 100644 --- a/compiler/testData/diagnostics/tests/LValueAssignment.kt +++ b/compiler/testData/diagnostics/tests/LValueAssignment.kt @@ -127,12 +127,12 @@ class Test() { a[4]++ a[6] += 43 - ab.getArray()[54] = 23 - ab.getArray()[54]++ + ab.getArray()[54] = 23 + ab.getArray()[54]++ (@f a)[3] = 4 (a : Array)[4]++ - (ab.getArray() : Array)[54] += 43 + (ab.getArray() : Array)[54] += 43 this[54] = 34 } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index caf84ceb3f0..ffb65f42f40 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -144,6 +144,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("AssignToArrayElement.kt") + public void testAssignToArrayElement() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/AssignToArrayElement.kt"); + doTest(fileName); + } + @TestMetadata("AutoCreatedIt.kt") public void testAutoCreatedIt() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/AutoCreatedIt.kt");