New check rules for inc, plus & plusAssign
KT-1176 arrayList[0]++. Setter is stored for array access expression when it's needed
This commit is contained in:
@@ -556,7 +556,7 @@ public abstract class StackValue {
|
||||
}
|
||||
|
||||
public int receiverSize() {
|
||||
if(isStandardStack(resolvedGetCall) && isStandardStack(resolvedSetCall)) {
|
||||
if(isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) {
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
@@ -566,7 +566,7 @@ public abstract class StackValue {
|
||||
|
||||
@Override
|
||||
public void dupReceiver(InstructionAdapter v) {
|
||||
if(isStandardStack(resolvedGetCall) && isStandardStack(resolvedSetCall)) {
|
||||
if(isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) {
|
||||
v.dup2(); // collection and index
|
||||
}
|
||||
else {
|
||||
@@ -702,7 +702,7 @@ public abstract class StackValue {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isStandardStack(ResolvedCall call) {
|
||||
private boolean isStandardStack(ResolvedCall call, int valueParamsSize) {
|
||||
if(call == null)
|
||||
return true;
|
||||
|
||||
@@ -710,12 +710,15 @@ public abstract class StackValue {
|
||||
if(typeParameterDescriptor.isReified())
|
||||
return false;
|
||||
}
|
||||
|
||||
if(call.getResultingDescriptor().getValueParameters().size() != 1)
|
||||
|
||||
List<ValueParameterDescriptor> valueParameters = call.getResultingDescriptor().getValueParameters();
|
||||
if(valueParameters.size() != valueParamsSize)
|
||||
return false;
|
||||
|
||||
if(codegen.typeMapper.mapType(call.getResultingDescriptor().getValueParameters().get(0).getOutType()).getSize() != 1)
|
||||
return false;
|
||||
for (ValueParameterDescriptor valueParameter : valueParameters) {
|
||||
if (codegen.typeMapper.mapType(valueParameter.getOutType()).getSize() != 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
if(call.getThisObject().exists()) {
|
||||
if(call.getReceiverArgument().exists())
|
||||
|
||||
@@ -310,6 +310,16 @@ public class JetFlowInformationProvider {
|
||||
hasReassignMethodReturningUnit = true;
|
||||
}
|
||||
}
|
||||
if (descriptor == null) {
|
||||
Collection<? extends DeclarationDescriptor> descriptors = trace.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, operationReference);
|
||||
if (descriptors != null) {
|
||||
for (DeclarationDescriptor referenceDescriptor : descriptors) {
|
||||
if (JetStandardClasses.isUnit(((FunctionDescriptor) referenceDescriptor).getReturnType())) {
|
||||
hasReassignMethodReturningUnit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasReassignMethodReturningUnit) {
|
||||
trace.report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor));
|
||||
|
||||
@@ -199,6 +199,15 @@ public interface Errors {
|
||||
SimpleDiagnosticFactory NO_GET_METHOD = SimpleDiagnosticFactory.create(ERROR, "No get method providing array access");
|
||||
SimpleDiagnosticFactory NO_SET_METHOD = SimpleDiagnosticFactory.create(ERROR, "No set method providing array access");
|
||||
|
||||
SimpleDiagnosticFactory INC_DEC_SHOULD_NOT_RETURN_UNIT = SimpleDiagnosticFactory.create(ERROR, "Functions inc(), dec() shouldn't return Unit to be used by operators ++, --");
|
||||
ParameterizedDiagnosticFactory2<DeclarationDescriptor, JetSimpleNameExpression> ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT = new ParameterizedDiagnosticFactory2<DeclarationDescriptor, JetSimpleNameExpression>(ERROR, "Function ''{0}'' should return Unit to be used by corresponding operator ''{1}''", NAME) {
|
||||
@Override
|
||||
protected String makeMessageForB(@NotNull JetSimpleNameExpression expression) {
|
||||
return expression.getText();
|
||||
}
|
||||
};
|
||||
AmbiguousDescriptorDiagnosticFactory ASSIGN_OPERATOR_AMBIGUITY = AmbiguousDescriptorDiagnosticFactory.create("Assignment operators ambiguity: {0}");
|
||||
|
||||
SimpleDiagnosticFactory EQUALS_MISSING = SimpleDiagnosticFactory.create(ERROR, "No method 'equals(Any?) : Boolean' available");
|
||||
SimpleDiagnosticFactory ASSIGNMENT_IN_EXPRESSION_CONTEXT = SimpleDiagnosticFactory.create(ERROR, "Assignments are not expressions, and only expressions are allowed in this context");
|
||||
SimpleDiagnosticFactory NAMESPACE_IS_NOT_AN_EXPRESSION = SimpleDiagnosticFactory.create(ERROR, "'namespace' is not an expression, it can only be used on the left-hand side of a dot ('.')");
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author svtk
|
||||
*/
|
||||
public class OverloadResolutionResultsUtil {
|
||||
@NotNull
|
||||
public static <D extends CallableDescriptor> OverloadResolutionResults<D> ambiguity(OverloadResolutionResults<D> results1, OverloadResolutionResults<D> results2) {
|
||||
Collection<ResolvedCallImpl<D>> resultingCalls = Lists.newArrayList();
|
||||
resultingCalls.addAll((Collection<ResolvedCallImpl<D>>) results1.getResultingCalls());
|
||||
resultingCalls.addAll((Collection<ResolvedCallImpl<D>>) results2.getResultingCalls());
|
||||
return OverloadResolutionResultsImpl.ambiguity(resultingCalls);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <D extends CallableDescriptor> JetType getResultType(OverloadResolutionResults<D> results) {
|
||||
if (results.isSuccess()) {
|
||||
return results.getResultingDescriptor().getReturnType();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+58
-78
@@ -14,6 +14,7 @@ import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
|
||||
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
|
||||
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResultsUtil;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.resolve.constants.*;
|
||||
import org.jetbrains.jet.lang.resolve.constants.StringValue;
|
||||
@@ -27,6 +28,7 @@ import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import javax.naming.ldap.ExtendedResponse;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
@@ -661,24 +663,19 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
context.trace.report(UNSUPPORTED.on(operationSign, "visitUnaryExpression"));
|
||||
return null;
|
||||
}
|
||||
JetType type = null;
|
||||
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace);
|
||||
BindingTrace initialTrace = context.trace;
|
||||
context = context.replaceBindingTrace(temporaryTrace);
|
||||
JetType type = facade.getType(baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE));
|
||||
if (type == null) {
|
||||
temporaryTrace.commit();
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS) && baseExpression instanceof JetArrayAccessExpression) {
|
||||
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace);
|
||||
JetType expressionType = facade.getType(baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceBindingTrace(temporaryTrace));
|
||||
if (expressionType != null) {
|
||||
JetExpression stubExpression = ExpressionTypingUtils.createStubExpressionOfNecessaryType(baseExpression.getProject(), expressionType, context.trace);
|
||||
type = resolveArrayAccessToLValue((JetArrayAccessExpression) baseExpression, stubExpression, context, true);
|
||||
}
|
||||
else {
|
||||
temporaryTrace.commit();
|
||||
context.trace.report(UNRESOLVED_REFERENCE.on(operationSign));
|
||||
}
|
||||
JetExpression stubExpression = ExpressionTypingUtils.createStubExpressionOfNecessaryType(baseExpression.getProject(), type, context.trace);
|
||||
resolveArrayAccessSetMethod((JetArrayAccessExpression) baseExpression, stubExpression, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceBindingTrace(TemporaryBindingTrace.create(initialTrace)), context.trace);
|
||||
}
|
||||
else {
|
||||
type = facade.getType(baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE));
|
||||
}
|
||||
if (type == null) return null;
|
||||
|
||||
ExpressionReceiver receiver = new ExpressionReceiver(baseExpression, type);
|
||||
|
||||
@@ -687,12 +684,16 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
expression.getOperationReference(),
|
||||
name);
|
||||
|
||||
if (!functionDescriptor.isSuccess()) return null;
|
||||
if (!functionDescriptor.isSuccess()) {
|
||||
temporaryTrace.commit();
|
||||
return null;
|
||||
}
|
||||
JetType returnType = functionDescriptor.getResultingDescriptor().getReturnType();
|
||||
JetType result;
|
||||
if (operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS) {
|
||||
if (context.semanticServices.getTypeChecker().isSubtypeOf(returnType, JetStandardClasses.getUnitType())) {
|
||||
result = JetStandardClasses.getUnitType();
|
||||
context.trace.report(INC_DEC_SHOULD_NOT_RETURN_UNIT.on(operationSign));
|
||||
}
|
||||
else {
|
||||
JetType receiverType = receiver.getType();
|
||||
@@ -712,7 +713,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
else {
|
||||
result = returnType;
|
||||
}
|
||||
|
||||
temporaryTrace.commit();
|
||||
return DataFlowUtils.checkType(result, expression, context);
|
||||
}
|
||||
|
||||
@@ -849,13 +850,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
public boolean checkInExpression(JetElement callElement, @NotNull JetSimpleNameExpression operationSign, @Nullable JetExpression left, @NotNull JetExpression right, ExpressionTypingContext context) {
|
||||
String name = "contains";
|
||||
ExpressionReceiver receiver = safeGetExpressionReceiver(facade, right, context.replaceExpectedType(NO_EXPECTED_TYPE));
|
||||
OverloadResolutionResults<FunctionDescriptor> functionDescriptor = context.resolveCallWithGivenNameToDescriptor(
|
||||
OverloadResolutionResults<FunctionDescriptor> resolutionResult = context.resolveCallWithGivenNameToDescriptor(
|
||||
CallMaker.makeCallWithExpressions(callElement, receiver, null, operationSign, Collections.singletonList(left)),
|
||||
operationSign,
|
||||
name);
|
||||
JetType containsType = functionDescriptor.isSuccess() ? functionDescriptor.getResultingDescriptor().getReturnType() : null;
|
||||
JetType containsType = OverloadResolutionResultsUtil.getResultType(resolutionResult);
|
||||
ensureBooleanResult(operationSign, name, containsType, context);
|
||||
return functionDescriptor.isSuccess();
|
||||
return resolutionResult.isSuccess();
|
||||
}
|
||||
|
||||
private void ensureNonemptyIntersectionOfOperandTypes(JetBinaryExpression expression, ExpressionTypingContext context) {
|
||||
@@ -892,38 +893,24 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetType visitArrayAccessExpression(JetArrayAccessExpression expression, ExpressionTypingContext contextWithExpectedType) {
|
||||
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE);
|
||||
JetExpression arrayExpression = expression.getArrayExpression();
|
||||
ExpressionReceiver receiver = getExpressionReceiver(facade, arrayExpression, context.replaceScope(context.scope));
|
||||
|
||||
if (receiver != null) {
|
||||
OverloadResolutionResults<FunctionDescriptor> results = context.resolveCallWithGivenName(
|
||||
CallMaker.makeCallWithExpressions(expression, receiver, null, expression, expression.getIndexExpressions()),
|
||||
expression,
|
||||
"get"
|
||||
);
|
||||
if (results.isSuccess()) {
|
||||
context.trace.record(INDEXED_LVALUE_GET, expression, results.getResultingCall());
|
||||
return DataFlowUtils.checkType(results.getResultingDescriptor().getReturnType(), expression, contextWithExpectedType);
|
||||
}
|
||||
}
|
||||
context.trace.report(NO_GET_METHOD.on(expression.getIndicesNode()));
|
||||
return null;
|
||||
public JetType visitArrayAccessExpression(JetArrayAccessExpression expression, ExpressionTypingContext context) {
|
||||
return resolveArrayAccessGetMethod(expression, context.replaceExpectedType(NO_EXPECTED_TYPE));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JetType getTypeForBinaryCall(JetScope scope, String name, ExpressionTypingContext context, JetBinaryExpression binaryExpression) {
|
||||
ExpressionReceiver receiver = safeGetExpressionReceiver(facade, binaryExpression.getLeft(), context.replaceScope(scope));
|
||||
OverloadResolutionResults<FunctionDescriptor> results = context.replaceScope(scope).resolveCallWithGivenNameToDescriptor(
|
||||
return OverloadResolutionResultsUtil.getResultType(getResolutionResultsForBinaryCall(scope, name, context, binaryExpression, receiver));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/*package*/ OverloadResolutionResults<FunctionDescriptor> getResolutionResultsForBinaryCall(JetScope scope, String name, ExpressionTypingContext context, JetBinaryExpression binaryExpression, ExpressionReceiver receiver) {
|
||||
// ExpressionReceiver receiver = safeGetExpressionReceiver(facade, binaryExpression.getLeft(), context.replaceScope(scope));
|
||||
return context.replaceScope(scope).resolveCallWithGivenNameToDescriptor(
|
||||
CallMaker.makeCall(receiver, binaryExpression),
|
||||
binaryExpression.getOperationReference(),
|
||||
name
|
||||
);
|
||||
if (results.isSuccess()) {
|
||||
return results.getResultingDescriptor().getReturnType();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -999,45 +986,38 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
context.trace.report(UNSUPPORTED.on(element, getClass().getCanonicalName()));
|
||||
return null;
|
||||
}
|
||||
|
||||
/*package*/ JetType resolveArrayAccessToLValue(@NotNull JetArrayAccessExpression arrayAccessExpression, @NotNull JetExpression right, @NotNull ExpressionTypingContext context, final boolean getterNeeded) {
|
||||
ExpressionReceiver receiver = getExpressionReceiver(facade, arrayAccessExpression.getArrayExpression(), context.replaceExpectedType(NO_EXPECTED_TYPE));
|
||||
if (receiver == null) return null;
|
||||
|
||||
OverloadResolutionResults<FunctionDescriptor> getFunctionResults = null;
|
||||
if (getterNeeded) {
|
||||
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace);
|
||||
getFunctionResults = context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceBindingTrace(temporaryTrace).resolveCallWithGivenName(
|
||||
CallMaker.makeArrayGetCall(receiver, arrayAccessExpression),
|
||||
arrayAccessExpression,
|
||||
"get");
|
||||
if (!getFunctionResults.isSuccess()) {
|
||||
temporaryTrace.commit();
|
||||
context.trace.report(NO_GET_METHOD.on(arrayAccessExpression.getIndicesNode()));
|
||||
return null;
|
||||
}
|
||||
context.trace.record(INDEXED_LVALUE_GET, arrayAccessExpression, getFunctionResults.getResultingCall());
|
||||
}
|
||||
@Nullable
|
||||
/*package*/ JetType resolveArrayAccessSetMethod(@NotNull JetArrayAccessExpression arrayAccessExpression, @NotNull JetExpression rightHandSide, @NotNull ExpressionTypingContext context, @NotNull BindingTrace traceForResolveResult) {
|
||||
return resolveArrayAccessSpecialMethod(arrayAccessExpression, rightHandSide, context, traceForResolveResult, false);
|
||||
}
|
||||
|
||||
Call call = CallMaker.makeArraySetCall(receiver, arrayAccessExpression, right);
|
||||
OverloadResolutionResults<FunctionDescriptor> setFunctionResults = context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).resolveCallWithGivenName(
|
||||
call,
|
||||
@Nullable
|
||||
/*package*/ JetType resolveArrayAccessGetMethod(@NotNull JetArrayAccessExpression arrayAccessExpression, @NotNull ExpressionTypingContext context) {
|
||||
return resolveArrayAccessSpecialMethod(arrayAccessExpression, null, context, context.trace, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JetType resolveArrayAccessSpecialMethod(@NotNull JetArrayAccessExpression arrayAccessExpression,
|
||||
@Nullable JetExpression rightHandSide, //only for 'set' method
|
||||
@NotNull ExpressionTypingContext context,
|
||||
@NotNull BindingTrace traceForResolveResult,
|
||||
boolean isGet) {
|
||||
JetType arrayType = facade.getType(arrayAccessExpression.getArrayExpression(), context);
|
||||
if (arrayType == null) return null;
|
||||
|
||||
ExpressionReceiver receiver = new ExpressionReceiver(arrayAccessExpression.getArrayExpression(), arrayType);
|
||||
if (!isGet) assert rightHandSide != null;
|
||||
OverloadResolutionResults<FunctionDescriptor> functionResults = context.resolveCallWithGivenName(
|
||||
isGet ? CallMaker.makeArrayGetCall(receiver, arrayAccessExpression) : CallMaker.makeArraySetCall(receiver, arrayAccessExpression, rightHandSide),
|
||||
arrayAccessExpression,
|
||||
"set");
|
||||
if (!setFunctionResults.isSuccess()) {
|
||||
context.trace.report(NO_SET_METHOD.on(arrayAccessExpression.getIndicesNode()));
|
||||
if (getterNeeded) {
|
||||
return getFunctionResults.getResultingDescriptor().getReturnType();
|
||||
}
|
||||
isGet ? "get" : "set");
|
||||
if (!functionResults.isSuccess()) {
|
||||
JetContainerNode indicesNode = arrayAccessExpression.getIndicesNode();
|
||||
traceForResolveResult.report(isGet ? NO_GET_METHOD.on(indicesNode) : NO_SET_METHOD.on(indicesNode));
|
||||
return null;
|
||||
}
|
||||
FunctionDescriptor setFunctionDescriptor = setFunctionResults.getResultingDescriptor();
|
||||
context.trace.record(INDEXED_LVALUE_SET, arrayAccessExpression, setFunctionResults.getResultingCall());
|
||||
|
||||
if (getterNeeded) {
|
||||
return getFunctionResults.getResultingDescriptor().getReturnType();
|
||||
}
|
||||
|
||||
return setFunctionDescriptor.getReturnType();
|
||||
traceForResolveResult.record(isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression, functionResults.getResultingCall());
|
||||
return functionResults.getResultingDescriptor().getReturnType();
|
||||
}
|
||||
}
|
||||
+63
-46
@@ -1,23 +1,29 @@
|
||||
package org.jetbrains.jet.lang.types.expressions;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
|
||||
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResultsUtil;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_REFERENCE_TARGET;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.VARIABLE_REASSIGNMENT;
|
||||
|
||||
/**
|
||||
@@ -140,63 +146,74 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
|
||||
}
|
||||
|
||||
protected JetType visitAssignmentOperation(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
|
||||
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceExpectedReturnType(TypeUtils.NO_EXPECTED_TYPE);
|
||||
// If there's += (or similar op) defined as such, we just call it.
|
||||
//There is a temporary binding trace for an opportunity to resolve set method for array if needed (the initial trace should be used there)
|
||||
TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(contextWithExpectedType.trace);
|
||||
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceExpectedReturnType(TypeUtils.NO_EXPECTED_TYPE).replaceBindingTrace(temporaryBindingTrace);
|
||||
|
||||
JetSimpleNameExpression operationSign = expression.getOperationReference();
|
||||
IElementType operationType = operationSign.getReferencedNameElementType();
|
||||
String name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
|
||||
|
||||
TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(context.trace);
|
||||
JetType assignmentOperationType = basic.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));
|
||||
if (left == null) return null;
|
||||
|
||||
if (left instanceof JetArrayAccessExpression) {
|
||||
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
||||
basic.resolveArrayAccessToLValue(arrayAccessExpression, expression.getRight(), context.replaceScope(scope), false);
|
||||
}
|
||||
assignmentOperationType = basic.getTypeForBinaryCall(scope, counterpartName, context, expression);
|
||||
if (assignmentOperationType != null) {
|
||||
context.trace.record(VARIABLE_REASSIGNMENT, expression);
|
||||
ExpressionTypingUtils.checkWrappingInRef(expression.getLeft(), context);
|
||||
}
|
||||
}
|
||||
else {
|
||||
JetType leftType = facade.getType(left, context);
|
||||
if (leftType == null) {
|
||||
facade.getType(expression.getRight(), context);
|
||||
context.trace.report(UNRESOLVED_REFERENCE.on(operationSign));
|
||||
temporaryBindingTrace.commit();
|
||||
checkReassignment(expression, context, assignmentOperationType, left);
|
||||
return null;
|
||||
}
|
||||
ExpressionReceiver receiver = new ExpressionReceiver(left, leftType);
|
||||
|
||||
// We check that defined only one of '+=' and '+' operations, and call it (in the case '+' we then also assign)
|
||||
// Check for '+='
|
||||
String name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
|
||||
TemporaryBindingTrace assignmentOperationTrace = TemporaryBindingTrace.create(context.trace);
|
||||
OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors = basic.getResolutionResultsForBinaryCall(scope, name, context.replaceBindingTrace(assignmentOperationTrace), expression, receiver);
|
||||
JetType assignmentOperationType = OverloadResolutionResultsUtil.getResultType(assignmentOperationDescriptors);
|
||||
|
||||
// Check for '+'
|
||||
String counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
|
||||
TemporaryBindingTrace binaryOperationTrace = TemporaryBindingTrace.create(context.trace);
|
||||
OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors = basic.getResolutionResultsForBinaryCall(scope, counterpartName, context.replaceBindingTrace(binaryOperationTrace), expression, receiver);
|
||||
JetType binaryOperationType = OverloadResolutionResultsUtil.getResultType(binaryOperationDescriptors);
|
||||
|
||||
JetType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType;
|
||||
if (assignmentOperationType != null && binaryOperationType != null) {
|
||||
OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors);
|
||||
context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls()));
|
||||
Collection<DeclarationDescriptor> descriptors = Sets.newHashSet();
|
||||
for (ResolvedCall<? extends FunctionDescriptor> call : ambiguityResolutionResults.getResultingCalls()) {
|
||||
descriptors.add(call.getResultingDescriptor());
|
||||
}
|
||||
facade.getType(expression.getRight(), context);
|
||||
context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
|
||||
}
|
||||
else if (assignmentOperationType != null) {
|
||||
assignmentOperationTrace.commit();
|
||||
if (!JetStandardClasses.isUnit(assignmentOperationType)) {
|
||||
context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
|
||||
}
|
||||
} else {
|
||||
binaryOperationTrace.commit();
|
||||
context.trace.record(VARIABLE_REASSIGNMENT, expression);
|
||||
ExpressionTypingUtils.checkWrappingInRef(expression.getLeft(), context);
|
||||
if (left instanceof JetArrayAccessExpression) {
|
||||
ExpressionTypingContext contextForResolve = context.replaceScope(scope).replaceBindingTrace(TemporaryBindingTrace.create(contextWithExpectedType.trace));
|
||||
basic.resolveArrayAccessSetMethod((JetArrayAccessExpression) left, expression.getRight(), contextForResolve, context.trace);
|
||||
}
|
||||
}
|
||||
basic.checkLValue(context.trace, expression.getLeft());
|
||||
return checkAssignmentType(assignmentOperationType, expression, contextWithExpectedType);
|
||||
temporaryBindingTrace.commit();
|
||||
return checkAssignmentType(type, expression, contextWithExpectedType);
|
||||
}
|
||||
|
||||
private void checkReassignment(@NotNull JetBinaryExpression expression, @NotNull ExpressionTypingContext context,
|
||||
@NotNull JetType assignmentOperationType, @Nullable JetExpression left) {
|
||||
if (left == null) return;
|
||||
JetType leftType = facade.getType(left, context.replaceScope(scope));
|
||||
if (leftType == null) return;
|
||||
boolean isUnit = context.semanticServices.getTypeChecker().
|
||||
isSubtypeOf(assignmentOperationType, JetStandardClasses.getUnitType());
|
||||
if (isUnit) return;
|
||||
|
||||
if (context.semanticServices.getTypeChecker().isSubtypeOf(assignmentOperationType, leftType)) {
|
||||
context.trace.record(VARIABLE_REASSIGNMENT, expression);
|
||||
}
|
||||
else {
|
||||
context.trace.report(TYPE_MISMATCH.on(expression, leftType, assignmentOperationType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected JetType visitAssignment(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
|
||||
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceExpectedReturnType(TypeUtils.NO_EXPECTED_TYPE);
|
||||
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
||||
JetExpression right = expression.getRight();
|
||||
if (left instanceof JetArrayAccessExpression) {
|
||||
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
||||
JetType assignmentType = basic.resolveArrayAccessToLValue(arrayAccessExpression, right, context.replaceScope(scope), false); //todo
|
||||
JetType assignmentType = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context.replaceScope(scope), context.trace);
|
||||
basic.checkLValue(context.trace, arrayAccessExpression);
|
||||
return checkAssignmentType(assignmentType, expression, contextWithExpectedType);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ class ArrayWrapper<T>() {
|
||||
contents.add(item)
|
||||
}
|
||||
|
||||
fun plusAssign(rhs: ArrayWrapper<T>): ArrayWrapper<T> {
|
||||
fun plus(rhs: ArrayWrapper<T>): ArrayWrapper<T> {
|
||||
val result = ArrayWrapper<T>()
|
||||
result.contents.addAll(contents)
|
||||
result.contents.addAll(rhs.contents)
|
||||
|
||||
@@ -37,7 +37,7 @@ fun test4() : Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
/*fun test5() : Boolean {
|
||||
fun test5() : Boolean {
|
||||
var mnr = Array<MyNumber>(2,{MyNumber(42)})
|
||||
mnr[0]++
|
||||
if (mnr[0].i != 43) return false
|
||||
@@ -69,7 +69,7 @@ fun test8() : Boolean {
|
||||
if (mnr[1].i != 42) return false
|
||||
return true
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
fun box() : String {
|
||||
var m = MyNumber(42)
|
||||
@@ -78,7 +78,7 @@ fun box() : String {
|
||||
if (!test2()) return "fail test 2"
|
||||
if (!test3()) return "fail test 3"
|
||||
if (!test4()) return "fail test 4"
|
||||
/*
|
||||
|
||||
if (!test5()) return "fail test 5"
|
||||
if (!test6()) return "fail test 6"
|
||||
if (!test7()) return "fail test 7"
|
||||
@@ -86,11 +86,11 @@ fun box() : String {
|
||||
|
||||
|
||||
++m
|
||||
if (m.i != 44) return "fail 0"
|
||||
if (m.i != 43) return "fail 0"
|
||||
|
||||
var m1 = ++m
|
||||
if (m1.i != 46) return "fail 3"
|
||||
if (m.i != 46) return "fail 4"
|
||||
*/
|
||||
if (m1.i != 44) return "fail 3"
|
||||
if (m.i != 44) return "fail 4"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -35,12 +35,12 @@ class UnitIncDec() {
|
||||
|
||||
fun testUnitIncDec() {
|
||||
var x = UnitIncDec()
|
||||
x++
|
||||
++x
|
||||
x--
|
||||
--x
|
||||
x = <!TYPE_MISMATCH, UNUSED_CHANGED_VALUE!>x++<!>
|
||||
x = <!TYPE_MISMATCH, UNUSED_CHANGED_VALUE!>x--<!>
|
||||
x = <!TYPE_MISMATCH!>++x<!>
|
||||
x = <!TYPE_MISMATCH, UNUSED_VALUE!>--x<!>
|
||||
x<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>++<!>
|
||||
<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>++<!>x
|
||||
x<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>--<!>
|
||||
<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>--<!>x
|
||||
x = <!UNUSED_CHANGED_VALUE!>x<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>++<!><!>
|
||||
x = <!UNUSED_CHANGED_VALUE!>x<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>--<!><!>
|
||||
x = <!INC_DEC_SHOULD_NOT_RETURN_UNIT!>++<!>x
|
||||
x = <!UNUSED_VALUE!><!INC_DEC_SHOULD_NOT_RETURN_UNIT!>--<!>x<!>
|
||||
}
|
||||
@@ -20,9 +20,9 @@ class B() {
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
var c = B()
|
||||
<!TYPE_MISMATCH!>c += B()<!>
|
||||
<!TYPE_MISMATCH!>c *= B()<!>
|
||||
<!TYPE_MISMATCH!>c /= B()<!>
|
||||
<!TYPE_MISMATCH!>c -= B()<!>
|
||||
<!TYPE_MISMATCH!>c %= B()<!>
|
||||
c <!ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT!>+=<!> B()
|
||||
c <!ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT!>*=<!> B()
|
||||
c <!ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT!>/=<!> B()
|
||||
c <!ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT!>-=<!> B()
|
||||
c <!ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT!>%=<!> B()
|
||||
}
|
||||
@@ -35,12 +35,12 @@ class UnitIncDec() {
|
||||
|
||||
fun testUnitIncDec() {
|
||||
var x = UnitIncDec()
|
||||
x++
|
||||
++x
|
||||
x--
|
||||
--x
|
||||
x = <error>x++</error>
|
||||
x = <error>x--</error>
|
||||
x = <error>++x</error>
|
||||
x = <error>--x</error>
|
||||
x<error>++</error>
|
||||
<error>++</error>x
|
||||
x<error>--</error>
|
||||
<error>--</error>x
|
||||
x = <warning>x<error>++</error></warning>
|
||||
x = <warning>x<error>--</error></warning>
|
||||
x = <error>++</error>x
|
||||
x = <warning><error>--</error>x</warning>
|
||||
}
|
||||
@@ -2,8 +2,6 @@ package std
|
||||
|
||||
import java.io.StringReader
|
||||
|
||||
inline fun <T> T?.plus(str: String?) : String { return toString() + str }
|
||||
|
||||
inline fun String.lastIndexOf(s: String) = (this as java.lang.String).lastIndexOf(s)
|
||||
|
||||
inline fun String.lastIndexOf(s: Char) = (this as java.lang.String).lastIndexOf(s.toString())
|
||||
|
||||
Reference in New Issue
Block a user