diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index cafee41d2cc..547a90a7731 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -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 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()) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index dd16bbc7f18..4796325484e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -310,6 +310,16 @@ public class JetFlowInformationProvider { hasReassignMethodReturningUnit = true; } } + if (descriptor == null) { + Collection 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)); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 99cdb406f14..eee0c5de5e1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -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 ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT = new ParameterizedDiagnosticFactory2(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 ('.')"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResultsUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResultsUtil.java new file mode 100644 index 00000000000..a480b2c6ac5 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadResolutionResultsUtil.java @@ -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 OverloadResolutionResults ambiguity(OverloadResolutionResults results1, OverloadResolutionResults results2) { + Collection> resultingCalls = Lists.newArrayList(); + resultingCalls.addAll((Collection>) results1.getResultingCalls()); + resultingCalls.addAll((Collection>) results2.getResultingCalls()); + return OverloadResolutionResultsImpl.ambiguity(resultingCalls); + } + + @Nullable + public static JetType getResultType(OverloadResolutionResults results) { + if (results.isSuccess()) { + return results.getResultingDescriptor().getReturnType(); + } + return null; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index acf7b2db7fa..b18bc19571c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -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 = context.resolveCallWithGivenNameToDescriptor( + OverloadResolutionResults 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 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 results = context.replaceScope(scope).resolveCallWithGivenNameToDescriptor( + return OverloadResolutionResultsUtil.getResultType(getResolutionResultsForBinaryCall(scope, name, context, binaryExpression, receiver)); + } + + @NotNull + /*package*/ OverloadResolutionResults 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 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 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 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(); } } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java index d3551d4041a..715b697741d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java @@ -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 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 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 ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors); + context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls())); + Collection descriptors = Sets.newHashSet(); + for (ResolvedCall 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); } diff --git a/compiler/testData/codegen/classes/overloadPlusAssignReturn.jet b/compiler/testData/codegen/classes/overloadPlusAssignReturn.jet index 42671b9f138..c5236b0ace4 100644 --- a/compiler/testData/codegen/classes/overloadPlusAssignReturn.jet +++ b/compiler/testData/codegen/classes/overloadPlusAssignReturn.jet @@ -7,7 +7,7 @@ class ArrayWrapper() { contents.add(item) } - fun plusAssign(rhs: ArrayWrapper): ArrayWrapper { + fun plus(rhs: ArrayWrapper): ArrayWrapper { val result = ArrayWrapper() result.contents.addAll(contents) result.contents.addAll(rhs.contents) diff --git a/compiler/testData/codegen/regressions/kt471.kt b/compiler/testData/codegen/regressions/kt471.kt index 0c33b4fe0e5..bc452506e78 100644 --- a/compiler/testData/codegen/regressions/kt471.kt +++ b/compiler/testData/codegen/regressions/kt471.kt @@ -37,7 +37,7 @@ fun test4() : Boolean { return true } -/*fun test5() : Boolean { +fun test5() : Boolean { var mnr = Array(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" } diff --git a/compiler/testData/diagnostics/tests/IncDec.jet b/compiler/testData/diagnostics/tests/IncDec.jet index f0cab587ec0..36f235c0734 100644 --- a/compiler/testData/diagnostics/tests/IncDec.jet +++ b/compiler/testData/diagnostics/tests/IncDec.jet @@ -35,12 +35,12 @@ class UnitIncDec() { fun testUnitIncDec() { var x = UnitIncDec() - x++ - ++x - x-- - --x - x = x++ - x = x-- - x = ++x - x = --x + x++ + ++x + x-- + --x + x = x++ + x = x-- + x = ++x + x = --x } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/kt618.jet b/compiler/testData/diagnostics/tests/regressions/kt618.jet index 2ef9ef9d760..616f0283f8f 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt618.jet +++ b/compiler/testData/diagnostics/tests/regressions/kt618.jet @@ -20,9 +20,9 @@ class B() { fun main(args : Array) { var c = B() - c += B() - c *= B() - c /= B() - c -= B() - c %= B() + c += B() + c *= B() + c /= B() + c -= B() + c %= B() } \ No newline at end of file diff --git a/idea/testData/checker/IncDec.jet b/idea/testData/checker/IncDec.jet index aa46004ffc2..b43ade29028 100644 --- a/idea/testData/checker/IncDec.jet +++ b/idea/testData/checker/IncDec.jet @@ -35,12 +35,12 @@ class UnitIncDec() { fun testUnitIncDec() { var x = UnitIncDec() - x++ - ++x - x-- - --x - x = x++ - x = x-- - x = ++x - x = --x + x++ + ++x + x-- + --x + x = x++ + x = x-- + x = ++x + x = --x } \ No newline at end of file diff --git a/stdlib/ktSrc/String.kt b/stdlib/ktSrc/String.kt index df38013e610..e756e338ff4 100644 --- a/stdlib/ktSrc/String.kt +++ b/stdlib/ktSrc/String.kt @@ -2,8 +2,6 @@ package std import java.io.StringReader -inline fun 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())