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() {
|
public int receiverSize() {
|
||||||
if(isStandardStack(resolvedGetCall) && isStandardStack(resolvedSetCall)) {
|
if(isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -566,7 +566,7 @@ public abstract class StackValue {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dupReceiver(InstructionAdapter v) {
|
public void dupReceiver(InstructionAdapter v) {
|
||||||
if(isStandardStack(resolvedGetCall) && isStandardStack(resolvedSetCall)) {
|
if(isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) {
|
||||||
v.dup2(); // collection and index
|
v.dup2(); // collection and index
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -702,7 +702,7 @@ public abstract class StackValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isStandardStack(ResolvedCall call) {
|
private boolean isStandardStack(ResolvedCall call, int valueParamsSize) {
|
||||||
if(call == null)
|
if(call == null)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -711,11 +711,14 @@ public abstract class StackValue {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(call.getResultingDescriptor().getValueParameters().size() != 1)
|
List<ValueParameterDescriptor> valueParameters = call.getResultingDescriptor().getValueParameters();
|
||||||
|
if(valueParameters.size() != valueParamsSize)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(codegen.typeMapper.mapType(call.getResultingDescriptor().getValueParameters().get(0).getOutType()).getSize() != 1)
|
for (ValueParameterDescriptor valueParameter : valueParameters) {
|
||||||
return false;
|
if (codegen.typeMapper.mapType(valueParameter.getOutType()).getSize() != 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(call.getThisObject().exists()) {
|
if(call.getThisObject().exists()) {
|
||||||
if(call.getReceiverArgument().exists())
|
if(call.getReceiverArgument().exists())
|
||||||
|
|||||||
@@ -310,6 +310,16 @@ public class JetFlowInformationProvider {
|
|||||||
hasReassignMethodReturningUnit = true;
|
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) {
|
if (!hasReassignMethodReturningUnit) {
|
||||||
trace.report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor));
|
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_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 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 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 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 ('.')");
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+57
-77
@@ -14,6 +14,7 @@ import org.jetbrains.jet.lang.psi.*;
|
|||||||
import org.jetbrains.jet.lang.resolve.*;
|
import org.jetbrains.jet.lang.resolve.*;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
|
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
|
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.calls.autocasts.DataFlowInfo;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.*;
|
import org.jetbrains.jet.lang.resolve.constants.*;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.StringValue;
|
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.lang.types.checker.JetTypeChecker;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
|
import javax.naming.ldap.ExtendedResponse;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||||
@@ -661,24 +663,19 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
context.trace.report(UNSUPPORTED.on(operationSign, "visitUnaryExpression"));
|
context.trace.report(UNSUPPORTED.on(operationSign, "visitUnaryExpression"));
|
||||||
return null;
|
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) {
|
if ((operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS) && baseExpression instanceof JetArrayAccessExpression) {
|
||||||
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace);
|
JetExpression stubExpression = ExpressionTypingUtils.createStubExpressionOfNecessaryType(baseExpression.getProject(), type, context.trace);
|
||||||
JetType expressionType = facade.getType(baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceBindingTrace(temporaryTrace));
|
resolveArrayAccessSetMethod((JetArrayAccessExpression) baseExpression, stubExpression, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceBindingTrace(TemporaryBindingTrace.create(initialTrace)), context.trace);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
type = facade.getType(baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE));
|
|
||||||
}
|
|
||||||
if (type == null) return null;
|
|
||||||
|
|
||||||
ExpressionReceiver receiver = new ExpressionReceiver(baseExpression, type);
|
ExpressionReceiver receiver = new ExpressionReceiver(baseExpression, type);
|
||||||
|
|
||||||
@@ -687,12 +684,16 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
expression.getOperationReference(),
|
expression.getOperationReference(),
|
||||||
name);
|
name);
|
||||||
|
|
||||||
if (!functionDescriptor.isSuccess()) return null;
|
if (!functionDescriptor.isSuccess()) {
|
||||||
|
temporaryTrace.commit();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
JetType returnType = functionDescriptor.getResultingDescriptor().getReturnType();
|
JetType returnType = functionDescriptor.getResultingDescriptor().getReturnType();
|
||||||
JetType result;
|
JetType result;
|
||||||
if (operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS) {
|
if (operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS) {
|
||||||
if (context.semanticServices.getTypeChecker().isSubtypeOf(returnType, JetStandardClasses.getUnitType())) {
|
if (context.semanticServices.getTypeChecker().isSubtypeOf(returnType, JetStandardClasses.getUnitType())) {
|
||||||
result = JetStandardClasses.getUnitType();
|
result = JetStandardClasses.getUnitType();
|
||||||
|
context.trace.report(INC_DEC_SHOULD_NOT_RETURN_UNIT.on(operationSign));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
JetType receiverType = receiver.getType();
|
JetType receiverType = receiver.getType();
|
||||||
@@ -712,7 +713,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
else {
|
else {
|
||||||
result = returnType;
|
result = returnType;
|
||||||
}
|
}
|
||||||
|
temporaryTrace.commit();
|
||||||
return DataFlowUtils.checkType(result, expression, context);
|
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) {
|
public boolean checkInExpression(JetElement callElement, @NotNull JetSimpleNameExpression operationSign, @Nullable JetExpression left, @NotNull JetExpression right, ExpressionTypingContext context) {
|
||||||
String name = "contains";
|
String name = "contains";
|
||||||
ExpressionReceiver receiver = safeGetExpressionReceiver(facade, right, context.replaceExpectedType(NO_EXPECTED_TYPE));
|
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)),
|
CallMaker.makeCallWithExpressions(callElement, receiver, null, operationSign, Collections.singletonList(left)),
|
||||||
operationSign,
|
operationSign,
|
||||||
name);
|
name);
|
||||||
JetType containsType = functionDescriptor.isSuccess() ? functionDescriptor.getResultingDescriptor().getReturnType() : null;
|
JetType containsType = OverloadResolutionResultsUtil.getResultType(resolutionResult);
|
||||||
ensureBooleanResult(operationSign, name, containsType, context);
|
ensureBooleanResult(operationSign, name, containsType, context);
|
||||||
return functionDescriptor.isSuccess();
|
return resolutionResult.isSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureNonemptyIntersectionOfOperandTypes(JetBinaryExpression expression, ExpressionTypingContext context) {
|
private void ensureNonemptyIntersectionOfOperandTypes(JetBinaryExpression expression, ExpressionTypingContext context) {
|
||||||
@@ -892,38 +893,24 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JetType visitArrayAccessExpression(JetArrayAccessExpression expression, ExpressionTypingContext contextWithExpectedType) {
|
public JetType visitArrayAccessExpression(JetArrayAccessExpression expression, ExpressionTypingContext context) {
|
||||||
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE);
|
return resolveArrayAccessGetMethod(expression, context.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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public JetType getTypeForBinaryCall(JetScope scope, String name, ExpressionTypingContext context, JetBinaryExpression binaryExpression) {
|
public JetType getTypeForBinaryCall(JetScope scope, String name, ExpressionTypingContext context, JetBinaryExpression binaryExpression) {
|
||||||
ExpressionReceiver receiver = safeGetExpressionReceiver(facade, binaryExpression.getLeft(), context.replaceScope(scope));
|
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),
|
CallMaker.makeCall(receiver, binaryExpression),
|
||||||
binaryExpression.getOperationReference(),
|
binaryExpression.getOperationReference(),
|
||||||
name
|
name
|
||||||
);
|
);
|
||||||
if (results.isSuccess()) {
|
|
||||||
return results.getResultingDescriptor().getReturnType();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1000,44 +987,37 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*package*/ JetType resolveArrayAccessToLValue(@NotNull JetArrayAccessExpression arrayAccessExpression, @NotNull JetExpression right, @NotNull ExpressionTypingContext context, final boolean getterNeeded) {
|
@Nullable
|
||||||
ExpressionReceiver receiver = getExpressionReceiver(facade, arrayAccessExpression.getArrayExpression(), context.replaceExpectedType(NO_EXPECTED_TYPE));
|
/*package*/ JetType resolveArrayAccessSetMethod(@NotNull JetArrayAccessExpression arrayAccessExpression, @NotNull JetExpression rightHandSide, @NotNull ExpressionTypingContext context, @NotNull BindingTrace traceForResolveResult) {
|
||||||
if (receiver == null) return null;
|
return resolveArrayAccessSpecialMethod(arrayAccessExpression, rightHandSide, context, traceForResolveResult, false);
|
||||||
|
}
|
||||||
|
|
||||||
OverloadResolutionResults<FunctionDescriptor> getFunctionResults = null;
|
@Nullable
|
||||||
if (getterNeeded) {
|
/*package*/ JetType resolveArrayAccessGetMethod(@NotNull JetArrayAccessExpression arrayAccessExpression, @NotNull ExpressionTypingContext context) {
|
||||||
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace);
|
return resolveArrayAccessSpecialMethod(arrayAccessExpression, null, context, context.trace, true);
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
Call call = CallMaker.makeArraySetCall(receiver, arrayAccessExpression, right);
|
@Nullable
|
||||||
OverloadResolutionResults<FunctionDescriptor> setFunctionResults = context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).resolveCallWithGivenName(
|
private JetType resolveArrayAccessSpecialMethod(@NotNull JetArrayAccessExpression arrayAccessExpression,
|
||||||
call,
|
@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,
|
arrayAccessExpression,
|
||||||
"set");
|
isGet ? "get" : "set");
|
||||||
if (!setFunctionResults.isSuccess()) {
|
if (!functionResults.isSuccess()) {
|
||||||
context.trace.report(NO_SET_METHOD.on(arrayAccessExpression.getIndicesNode()));
|
JetContainerNode indicesNode = arrayAccessExpression.getIndicesNode();
|
||||||
if (getterNeeded) {
|
traceForResolveResult.report(isGet ? NO_GET_METHOD.on(indicesNode) : NO_SET_METHOD.on(indicesNode));
|
||||||
return getFunctionResults.getResultingDescriptor().getReturnType();
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
FunctionDescriptor setFunctionDescriptor = setFunctionResults.getResultingDescriptor();
|
traceForResolveResult.record(isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression, functionResults.getResultingCall());
|
||||||
context.trace.record(INDEXED_LVALUE_SET, arrayAccessExpression, setFunctionResults.getResultingCall());
|
return functionResults.getResultingDescriptor().getReturnType();
|
||||||
|
|
||||||
if (getterNeeded) {
|
|
||||||
return getFunctionResults.getResultingDescriptor().getReturnType();
|
|
||||||
}
|
|
||||||
|
|
||||||
return setFunctionDescriptor.getReturnType();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+63
-46
@@ -1,23 +1,29 @@
|
|||||||
package org.jetbrains.jet.lang.types.expressions;
|
package org.jetbrains.jet.lang.types.expressions;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.*;
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
|
||||||
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
|
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResultsUtil;
|
||||||
import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
|
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
|
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.JetStandardClasses;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
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;
|
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) {
|
protected JetType visitAssignmentOperation(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
|
||||||
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceExpectedReturnType(TypeUtils.NO_EXPECTED_TYPE);
|
//There is a temporary binding trace for an opportunity to resolve set method for array if needed (the initial trace should be used there)
|
||||||
// If there's += (or similar op) defined as such, we just call it.
|
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();
|
JetSimpleNameExpression operationSign = expression.getOperationReference();
|
||||||
IElementType operationType = operationSign.getReferencedNameElementType();
|
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());
|
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
||||||
// If there isn't, we call plus (or like) and then assign
|
if (left == null) return null;
|
||||||
if (assignmentOperationType == null) {
|
|
||||||
String counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
|
|
||||||
|
|
||||||
if (left instanceof JetArrayAccessExpression) {
|
JetType leftType = facade.getType(left, context);
|
||||||
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
if (leftType == null) {
|
||||||
basic.resolveArrayAccessToLValue(arrayAccessExpression, expression.getRight(), context.replaceScope(scope), false);
|
facade.getType(expression.getRight(), context);
|
||||||
}
|
context.trace.report(UNRESOLVED_REFERENCE.on(operationSign));
|
||||||
assignmentOperationType = basic.getTypeForBinaryCall(scope, counterpartName, context, expression);
|
|
||||||
if (assignmentOperationType != null) {
|
|
||||||
context.trace.record(VARIABLE_REASSIGNMENT, expression);
|
|
||||||
ExpressionTypingUtils.checkWrappingInRef(expression.getLeft(), context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
temporaryBindingTrace.commit();
|
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());
|
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) {
|
protected JetType visitAssignment(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
|
||||||
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceExpectedReturnType(TypeUtils.NO_EXPECTED_TYPE);
|
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceExpectedReturnType(TypeUtils.NO_EXPECTED_TYPE);
|
||||||
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
||||||
JetExpression right = expression.getRight();
|
JetExpression right = expression.getRight();
|
||||||
if (left instanceof JetArrayAccessExpression) {
|
if (left instanceof JetArrayAccessExpression) {
|
||||||
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
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);
|
basic.checkLValue(context.trace, arrayAccessExpression);
|
||||||
return checkAssignmentType(assignmentType, expression, contextWithExpectedType);
|
return checkAssignmentType(assignmentType, expression, contextWithExpectedType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ class ArrayWrapper<T>() {
|
|||||||
contents.add(item)
|
contents.add(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun plusAssign(rhs: ArrayWrapper<T>): ArrayWrapper<T> {
|
fun plus(rhs: ArrayWrapper<T>): ArrayWrapper<T> {
|
||||||
val result = ArrayWrapper<T>()
|
val result = ArrayWrapper<T>()
|
||||||
result.contents.addAll(contents)
|
result.contents.addAll(contents)
|
||||||
result.contents.addAll(rhs.contents)
|
result.contents.addAll(rhs.contents)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ fun test4() : Boolean {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/*fun test5() : Boolean {
|
fun test5() : Boolean {
|
||||||
var mnr = Array<MyNumber>(2,{MyNumber(42)})
|
var mnr = Array<MyNumber>(2,{MyNumber(42)})
|
||||||
mnr[0]++
|
mnr[0]++
|
||||||
if (mnr[0].i != 43) return false
|
if (mnr[0].i != 43) return false
|
||||||
@@ -69,7 +69,7 @@ fun test8() : Boolean {
|
|||||||
if (mnr[1].i != 42) return false
|
if (mnr[1].i != 42) return false
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
fun box() : String {
|
fun box() : String {
|
||||||
var m = MyNumber(42)
|
var m = MyNumber(42)
|
||||||
@@ -78,7 +78,7 @@ fun box() : String {
|
|||||||
if (!test2()) return "fail test 2"
|
if (!test2()) return "fail test 2"
|
||||||
if (!test3()) return "fail test 3"
|
if (!test3()) return "fail test 3"
|
||||||
if (!test4()) return "fail test 4"
|
if (!test4()) return "fail test 4"
|
||||||
/*
|
|
||||||
if (!test5()) return "fail test 5"
|
if (!test5()) return "fail test 5"
|
||||||
if (!test6()) return "fail test 6"
|
if (!test6()) return "fail test 6"
|
||||||
if (!test7()) return "fail test 7"
|
if (!test7()) return "fail test 7"
|
||||||
@@ -86,11 +86,11 @@ fun box() : String {
|
|||||||
|
|
||||||
|
|
||||||
++m
|
++m
|
||||||
if (m.i != 44) return "fail 0"
|
if (m.i != 43) return "fail 0"
|
||||||
|
|
||||||
var m1 = ++m
|
var m1 = ++m
|
||||||
if (m1.i != 46) return "fail 3"
|
if (m1.i != 44) return "fail 3"
|
||||||
if (m.i != 46) return "fail 4"
|
if (m.i != 44) return "fail 4"
|
||||||
*/
|
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ class UnitIncDec() {
|
|||||||
|
|
||||||
fun testUnitIncDec() {
|
fun testUnitIncDec() {
|
||||||
var x = UnitIncDec()
|
var x = UnitIncDec()
|
||||||
x++
|
x<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>++<!>
|
||||||
++x
|
<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>++<!>x
|
||||||
x--
|
x<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>--<!>
|
||||||
--x
|
<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>--<!>x
|
||||||
x = <!TYPE_MISMATCH, UNUSED_CHANGED_VALUE!>x++<!>
|
x = <!UNUSED_CHANGED_VALUE!>x<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>++<!><!>
|
||||||
x = <!TYPE_MISMATCH, UNUSED_CHANGED_VALUE!>x--<!>
|
x = <!UNUSED_CHANGED_VALUE!>x<!INC_DEC_SHOULD_NOT_RETURN_UNIT!>--<!><!>
|
||||||
x = <!TYPE_MISMATCH!>++x<!>
|
x = <!INC_DEC_SHOULD_NOT_RETURN_UNIT!>++<!>x
|
||||||
x = <!TYPE_MISMATCH, UNUSED_VALUE!>--x<!>
|
x = <!UNUSED_VALUE!><!INC_DEC_SHOULD_NOT_RETURN_UNIT!>--<!>x<!>
|
||||||
}
|
}
|
||||||
@@ -20,9 +20,9 @@ class B() {
|
|||||||
|
|
||||||
fun main(args : Array<String>) {
|
fun main(args : Array<String>) {
|
||||||
var c = B()
|
var c = B()
|
||||||
<!TYPE_MISMATCH!>c += B()<!>
|
c <!ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT!>+=<!> B()
|
||||||
<!TYPE_MISMATCH!>c *= B()<!>
|
c <!ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT!>*=<!> B()
|
||||||
<!TYPE_MISMATCH!>c /= B()<!>
|
c <!ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT!>/=<!> B()
|
||||||
<!TYPE_MISMATCH!>c -= B()<!>
|
c <!ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT!>-=<!> B()
|
||||||
<!TYPE_MISMATCH!>c %= B()<!>
|
c <!ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT!>%=<!> B()
|
||||||
}
|
}
|
||||||
@@ -35,12 +35,12 @@ class UnitIncDec() {
|
|||||||
|
|
||||||
fun testUnitIncDec() {
|
fun testUnitIncDec() {
|
||||||
var x = UnitIncDec()
|
var x = UnitIncDec()
|
||||||
x++
|
x<error>++</error>
|
||||||
++x
|
<error>++</error>x
|
||||||
x--
|
x<error>--</error>
|
||||||
--x
|
<error>--</error>x
|
||||||
x = <error>x++</error>
|
x = <warning>x<error>++</error></warning>
|
||||||
x = <error>x--</error>
|
x = <warning>x<error>--</error></warning>
|
||||||
x = <error>++x</error>
|
x = <error>++</error>x
|
||||||
x = <error>--x</error>
|
x = <warning><error>--</error>x</warning>
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,6 @@ package std
|
|||||||
|
|
||||||
import java.io.StringReader
|
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: String) = (this as java.lang.String).lastIndexOf(s)
|
||||||
|
|
||||||
inline fun String.lastIndexOf(s: Char) = (this as java.lang.String).lastIndexOf(s.toString())
|
inline fun String.lastIndexOf(s: Char) = (this as java.lang.String).lastIndexOf(s.toString())
|
||||||
|
|||||||
Reference in New Issue
Block a user