checkLValue for array indexing expression should resolve set method #KT-7218 Fixed

This commit is contained in:
Ilya Ryzhenkov
2015-04-01 14:18:53 +03:00
parent a986d913c3
commit 2f02024c24
6 changed files with 52 additions and 14 deletions
@@ -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);
@@ -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);
}
@@ -0,0 +1,10 @@
fun getArray(): Array<Int> = throw Exception()
fun getList(): MutableList<Int> = throw Exception()
fun fn() {
getArray()[1] = 2
getList()[1] = 2
getArray()[1]++
getList()[1]++
getArray()[1] += 2
getList()[1] += 2
}
@@ -0,0 +1,5 @@
package
internal fun fn(): kotlin.Unit
internal fun getArray(): kotlin.Array<kotlin.Int>
internal fun getList(): kotlin.MutableList<kotlin.Int>
@@ -127,12 +127,12 @@ class Test() {
a[4]++
a[6] += 43
<!VARIABLE_EXPECTED!>ab.getArray()<!>[54] = 23
<!VARIABLE_EXPECTED!>ab.getArray()<!>[54]++
ab.getArray()[54] = 23
ab.getArray()[54]++
(@f a)[3] = 4
(a : Array<Int>)[4]++
(<!VARIABLE_EXPECTED!>ab.getArray()<!> : Array<Int>)[54] += 43
(ab.getArray() : Array<Int>)[54] += 43
this<!NO_SET_METHOD!><!UNRESOLVED_REFERENCE!>[<!>54<!UNRESOLVED_REFERENCE!>]<!><!> = 34
}
@@ -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");