KT-437 Support assignability checks
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.jet.lang.resolve;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
@@ -14,7 +15,7 @@ public class BindingContextUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiElement resolveToDeclarationPsiElement(BindingContext bindingContext, JetReferenceExpression referenceExpression) {
|
||||
public static PsiElement resolveToDeclarationPsiElement(@NotNull BindingContext bindingContext, @Nullable JetReferenceExpression referenceExpression) {
|
||||
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, referenceExpression);
|
||||
if (declarationDescriptor == null) {
|
||||
return bindingContext.get(BindingContext.LABEL_TARGET, referenceExpression);
|
||||
@@ -23,7 +24,7 @@ public class BindingContextUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static VariableDescriptor extractVariableDescriptorIfAny(BindingContext bindingContext, JetElement element, boolean onlyReference) {
|
||||
public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable JetElement element, boolean onlyReference) {
|
||||
DeclarationDescriptor descriptor = null;
|
||||
if (!onlyReference && (element instanceof JetProperty || element instanceof JetParameter)) {
|
||||
descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
|
||||
|
||||
+19
@@ -579,6 +579,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
else {
|
||||
context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression);
|
||||
ExpressionTypingUtils.checkWrappingInRef(baseExpression, context);
|
||||
|
||||
checkLValue(context.trace, baseExpression);
|
||||
}
|
||||
// TODO : Maybe returnType?
|
||||
result = receiverType;
|
||||
@@ -591,6 +593,23 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
return DataFlowUtils.checkType(result, expression, context);
|
||||
}
|
||||
|
||||
protected void checkLValue(BindingTrace trace, JetExpression expression) {
|
||||
checkLValue(trace, expression, false);
|
||||
}
|
||||
|
||||
private void checkLValue(BindingTrace trace, JetExpression expressionWithParenthesis, boolean canBeThis) {
|
||||
JetExpression expression = JetPsiUtil.deparenthesize(expressionWithParenthesis);
|
||||
if (expression instanceof JetArrayAccessExpression) {
|
||||
checkLValue(trace, ((JetArrayAccessExpression) expressionWithParenthesis).getArrayExpression(), true);
|
||||
return;
|
||||
}
|
||||
if (canBeThis && expression instanceof JetThisExpression) return;
|
||||
VariableDescriptor variable = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), expression, true);
|
||||
if (variable == null) {
|
||||
trace.report(VARIABLE_EXPECTED.on(expression != null ? expression : expressionWithParenthesis));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetType visitBinaryExpression(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
|
||||
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE);
|
||||
|
||||
+7
-5
@@ -117,11 +117,11 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
||||
TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(context.trace);
|
||||
JetType assignmentOperationType = getTypeForBinaryCall(scope, name, context.replaceBindingTrace(temporaryBindingTrace), expression);
|
||||
|
||||
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
||||
// If there isn't, we call plus (or like) and then assign
|
||||
if (assignmentOperationType == null) {
|
||||
String counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
|
||||
|
||||
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
||||
if (left instanceof JetArrayAccessExpression) {
|
||||
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
||||
resolveArrayAccessToLValue(arrayAccessExpression, expression.getRight(), operationSign, context);
|
||||
@@ -135,6 +135,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
||||
else {
|
||||
temporaryBindingTrace.commit();
|
||||
}
|
||||
checkLValue(context.trace, expression.getLeft());
|
||||
return checkExpectedType(expression, context);
|
||||
}
|
||||
|
||||
@@ -144,15 +145,16 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
||||
JetExpression right = expression.getRight();
|
||||
if (left instanceof JetArrayAccessExpression) {
|
||||
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
||||
return resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference(), context);
|
||||
JetType resultType = resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference(), context);
|
||||
checkLValue(context.trace, arrayAccessExpression);
|
||||
return resultType;
|
||||
}
|
||||
JetType leftType = facade.getType(expression.getLeft(), context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(scope));
|
||||
if (right != null) {
|
||||
JetType rightType = facade.getType(right, context.replaceExpectedType(leftType).replaceScope(scope));
|
||||
}
|
||||
VariableDescriptor variable = BindingContextUtils.extractVariableDescriptorIfAny(context.trace.getBindingContext(), left, true);
|
||||
if (variable == null && leftType != null) { //if leftType == null, some another error has been generated
|
||||
context.trace.report(VARIABLE_EXPECTED.on(left != null ? left : expression.getLeft()));
|
||||
if (leftType != null) { //if leftType == null, some another error has been generated
|
||||
checkLValue(context.trace, expression.getLeft());
|
||||
}
|
||||
if (left instanceof JetSimpleNameExpression) {
|
||||
JetSimpleNameExpression simpleName = (JetSimpleNameExpression) left;
|
||||
|
||||
@@ -56,3 +56,74 @@ fun canBe(var i: Int, val j: Int) {
|
||||
class A() {
|
||||
var a: Int = 3
|
||||
}
|
||||
|
||||
class Test() {
|
||||
fun testIllegalValues() {
|
||||
<!VARIABLE_EXPECTED!>1<!> += 23
|
||||
(<!VARIABLE_EXPECTED!>1<!> : Int) += 43
|
||||
(@l <!VARIABLE_EXPECTED!>1<!>) += 23
|
||||
|
||||
<!VARIABLE_EXPECTED!>getInt()<!> += 343
|
||||
(@f <!VARIABLE_EXPECTED!>getInt()<!>) += 343
|
||||
(<!VARIABLE_EXPECTED!>getInt()<!> : Int) += 343
|
||||
|
||||
<!VARIABLE_EXPECTED!>1<!>++
|
||||
(@r <!VARIABLE_EXPECTED!>1<!>)++
|
||||
(<!VARIABLE_EXPECTED!>1<!> : Int)++
|
||||
|
||||
<!VARIABLE_EXPECTED!>getInt()<!>++
|
||||
(@m <!VARIABLE_EXPECTED!>getInt()<!>)++
|
||||
(<!VARIABLE_EXPECTED!>getInt()<!> : Int)++
|
||||
|
||||
this<!UNRESOLVED_REFERENCE!>++<!>
|
||||
|
||||
var s : String = "r"
|
||||
s += "ss"
|
||||
s += this
|
||||
s += (@a 2)
|
||||
}
|
||||
|
||||
fun testVariables() {
|
||||
var a: Int = 34
|
||||
val b: Int = 34
|
||||
|
||||
a += 34
|
||||
(@l a) += 34
|
||||
(a : Int) += 34
|
||||
|
||||
<!VAL_REASSIGNMENT!>b<!> += 34
|
||||
(@l <!VAL_REASSIGNMENT!>b<!>) += 34
|
||||
(<!VAL_REASSIGNMENT!>b<!> : Int) += 34
|
||||
(<!VAL_REASSIGNMENT!>b<!>) += 3
|
||||
|
||||
a++
|
||||
(@ a)++
|
||||
(a : Int)++
|
||||
(a)++
|
||||
}
|
||||
|
||||
fun testArrays(a: Array<Int>, ab: Ab) {
|
||||
a[3] = 4
|
||||
a[4]++
|
||||
a[6] += 43
|
||||
|
||||
<!VARIABLE_EXPECTED!>ab.getArray()<!>[54] = 23
|
||||
<!VARIABLE_EXPECTED!>ab.getArray()<!>[54]++
|
||||
|
||||
(@f a)[3] = 4
|
||||
(a : Array<Int>)[4]++
|
||||
(<!VARIABLE_EXPECTED!>ab.getArray()<!> : Array<Int>)[54] += 43
|
||||
|
||||
<!UNRESOLVED_REFERENCE!>this[54]<!> = 34
|
||||
}
|
||||
}
|
||||
|
||||
fun Array<Int>.checkThis() {
|
||||
this[45] = 34
|
||||
this[352]++
|
||||
this[35] += 234
|
||||
}
|
||||
|
||||
abstract class Ab {
|
||||
abstract fun getArray() : Array<Int>
|
||||
}
|
||||
Reference in New Issue
Block a user