diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java index c481c2ba635..7bd3fd8f888 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java @@ -31,6 +31,11 @@ public class BindingTraceContext extends BindingTrace implements BindingContext resolutionResults.put(expression, descriptor); } + @Override + public void removeReferenceResolution(@NotNull JetReferenceExpression referenceExpression) { + resolutionResults.remove(referenceExpression); + } + @Override public void recordTypeResolution(@NotNull JetTypeReference typeReference, @NotNull JetType type) { types.put(typeReference, type); diff --git a/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java index a9f2a73c4c7..30394e46f96 100644 --- a/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java +++ b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java @@ -29,4 +29,8 @@ public class BindingTrace { public void setToplevelScope(JetScope toplevelScope) { } + + public void removeReferenceResolution(@NotNull JetReferenceExpression referenceExpression) { + + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 17be3a54bc2..fa59443e0c1 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -57,9 +57,9 @@ public class JetTypeInferrer { } @Nullable - private FunctionDescriptor lookupFunction(JetScope scope, JetReferenceExpression reference, String name, JetType receiverType, List argumentTypes) { + private FunctionDescriptor lookupFunction(JetScope scope, JetReferenceExpression reference, String name, JetType receiverType, List argumentTypes, boolean reportUnresolved) { OverloadDomain overloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, name); - overloadDomain = wrapForTracing(overloadDomain, reference); + overloadDomain = wrapForTracing(overloadDomain, reference, reportUnresolved); return overloadDomain.getFunctionDescriptorForPositionedArguments(Collections.emptyList(), argumentTypes); } @@ -129,10 +129,10 @@ public class JetTypeInferrer { throw new IllegalArgumentException("Unsupported element: " + elem); } }); - return wrapForTracing(result[0], reference[0]); + return wrapForTracing(result[0], reference[0], true); } - private OverloadDomain wrapForTracing(final OverloadDomain overloadDomain, @NotNull final JetReferenceExpression referenceExpression) { + private OverloadDomain wrapForTracing(final OverloadDomain overloadDomain, @NotNull final JetReferenceExpression referenceExpression, final boolean reportUnresolved) { if (overloadDomain == null) return OverloadDomain.EMPTY; return new OverloadDomain() { @Override @@ -141,7 +141,9 @@ public class JetTypeInferrer { if (descriptor != null) { trace.recordReferenceResolution(referenceExpression, descriptor); } else { - semanticServices.getErrorHandler().unresolvedReference(referenceExpression); + if (reportUnresolved) { + semanticServices.getErrorHandler().unresolvedReference(referenceExpression); + } } return descriptor; } @@ -152,7 +154,9 @@ public class JetTypeInferrer { if (descriptor != null) { trace.recordReferenceResolution(referenceExpression, descriptor); } else { - semanticServices.getErrorHandler().unresolvedReference(referenceExpression); + if (reportUnresolved) { + semanticServices.getErrorHandler().unresolvedReference(referenceExpression); + } } return descriptor; } @@ -534,7 +538,7 @@ public class JetTypeInferrer { else { JetType type = getType(scope, expression.getBaseExpression(), false); if (type != null) { - FunctionDescriptor functionDescriptor = lookupFunction(scope, expression.getOperationSign(), name, type, Collections.emptyList()); + FunctionDescriptor functionDescriptor = lookupFunction(scope, expression.getOperationSign(), name, type, Collections.emptyList(), true); if (functionDescriptor != null) { result = functionDescriptor.getUnsubstitutedReturnType(); } @@ -548,10 +552,10 @@ public class JetTypeInferrer { IElementType operationType = operationSign.getReferencedNameElementType(); if (operationType == JetTokens.IDENTIFIER) { - result = getTypeForBinaryCall(expression, operationSign.getReferencedName(), scope); + result = getTypeForBinaryCall(expression, operationSign.getReferencedName(), scope, true); } else if (binaryOperationNames.containsKey(operationType)) { - result = getTypeForBinaryCall(expression, binaryOperationNames.get(operationType), scope); + result = getTypeForBinaryCall(expression, binaryOperationNames.get(operationType), scope, true); } else if (operationType == JetTokens.EQ) { JetExpression left = expression.getLeft(); @@ -567,7 +571,7 @@ public class JetTypeInferrer { result = null; // TODO : This is not an expression, in fact! } else if (comparisonOperations.contains(operationType)) { - JetType compareToReturnType = getTypeForBinaryCall(expression, "compareTo", scope); + JetType compareToReturnType = getTypeForBinaryCall(expression, "compareTo", scope, true); if (compareToReturnType != null) { TypeConstructor constructor = compareToReturnType.getConstructor(); JetStandardLibrary standardLibrary = semanticServices.getStandardLibrary(); @@ -578,6 +582,30 @@ public class JetTypeInferrer { semanticServices.getErrorHandler().structuralError(operationSign.getNode(), "compareTo must return Int, but returns " + compareToReturnType); } } + } + else if (assignmentOperationNames.containsKey(operationType)) { + String name = assignmentOperationNames.get(operationType); + JetType assignmentOperationType = getTypeForBinaryCall(expression, name, scope, false); + + String counterpartName = binaryOperationNames.get(assignmentOperationCounterparts.get(operationType)); + JetType counterpartType = getTypeForBinaryCall(expression, counterpartName, scope, false); + + if (assignmentOperationType != null) { + if (counterpartType != null) { + semanticServices.getErrorHandler().structuralError(operationSign.getNode(), "Ambiguity: both '" + name + "' and '" + counterpartName + "' are defined"); + // TODO : make reference unresolved? + trace.removeReferenceResolution(operationSign); + } else { + result = assignmentOperationType; + } + } + else { + if (counterpartType == null) { + semanticServices.getErrorHandler().unresolvedReference(operationSign); + } else { + result = counterpartType; + } + } } else { semanticServices.getErrorHandler().structuralError(operationSign.getNode(), "Unknown operation"); } @@ -591,7 +619,7 @@ public class JetTypeInferrer { List argumentTypes = getTypes(scope, indexExpressions); if (argumentTypes == null) return; - FunctionDescriptor functionDescriptor = lookupFunction(scope, expression, "get", receiverType, argumentTypes); + FunctionDescriptor functionDescriptor = lookupFunction(scope, expression, "get", receiverType, argumentTypes, true); if (functionDescriptor != null) { result = functionDescriptor.getUnsubstitutedReturnType(); } @@ -608,8 +636,8 @@ public class JetTypeInferrer { if (receiverType == null) return; // TODO : nasty hack: effort is duplicated - lookupFunction(scope, arrayAccessExpression, "set", receiverType, argumentTypes); - FunctionDescriptor functionDescriptor = lookupFunction(scope, operationSign, "set", receiverType, argumentTypes); + lookupFunction(scope, arrayAccessExpression, "set", receiverType, argumentTypes, true); + FunctionDescriptor functionDescriptor = lookupFunction(scope, operationSign, "set", receiverType, argumentTypes, true); if (functionDescriptor != null) { result = functionDescriptor.getUnsubstitutedReturnType(); } @@ -620,7 +648,7 @@ public class JetTypeInferrer { throw new IllegalArgumentException("Unsupported element: " + elem); } - private JetType getTypeForBinaryCall(JetBinaryExpression expression, String name, JetScope scope) { + private JetType getTypeForBinaryCall(JetBinaryExpression expression, @NotNull String name, JetScope scope, boolean reportUnresolved) { JetSimpleNameExpression operationSign = expression.getOperationReference(); JetExpression left = expression.getLeft(); JetType leftType = getType(scope, left, false); @@ -629,7 +657,7 @@ public class JetTypeInferrer { return ErrorType.createErrorType("No right argument"); // TODO } JetType rightType = getType(scope, right, false); - FunctionDescriptor functionDescriptor = lookupFunction(scope, operationSign, name, leftType, Collections.singletonList(rightType)); + FunctionDescriptor functionDescriptor = lookupFunction(scope, operationSign, name, leftType, Collections.singletonList(rightType), reportUnresolved); if (functionDescriptor != null) { return functionDescriptor.getUnsubstitutedReturnType(); } @@ -668,5 +696,14 @@ public class JetTypeInferrer { assignmentOperationNames.put(JetTokens.MINUSEQ, "minusAssign"); } + private static final Map assignmentOperationCounterparts = new HashMap(); + static { + assignmentOperationCounterparts.put(JetTokens.MULTEQ, JetTokens.MUL); + assignmentOperationCounterparts.put(JetTokens.DIVEQ, JetTokens.DIV); + assignmentOperationCounterparts.put(JetTokens.PERCEQ, JetTokens.PERC); + assignmentOperationCounterparts.put(JetTokens.PLUSEQ, JetTokens.PLUS); + assignmentOperationCounterparts.put(JetTokens.MINUSEQ, JetTokens.MINUS); + } + } diff --git a/idea/testData/resolve/ResolveOfInfixExpressions.jet b/idea/testData/resolve/ResolveOfInfixExpressions.jet index 4165b2ff506..7b525f95ee2 100644 --- a/idea/testData/resolve/ResolveOfInfixExpressions.jet +++ b/idea/testData/resolve/ResolveOfInfixExpressions.jet @@ -16,6 +16,7 @@ import util.* `t`t<`t.T`T>(`t.t`t)`:t.T` new `X`X<`t.T`T>() 1 `std::Int.plus(Int)`+ 1 + 1 `std::Int.plus(Int)`+= 1 new X() `plus`+ "1" new X() `plus`plus "sadfas" new X().`plus`plus("") @@ -32,6 +33,7 @@ import util.* ~get1~fun get(i : Int) : Int {} ~get2~fun get(i : Int, j : Int) : String {} ~get3~fun get(i : Object) : Any {return i } + ~+=~fun plusAssign(a : Any?) : Unit {} } ~Bar~class Bar : Foo { @@ -59,6 +61,7 @@ fun tt(t : T) : T { `inc`++y `dec`--y y`dec`-- + y `+=`+= 1 1 `std::Int.compareTo(Double)`> 2.0 1 `std::Int.compareTo(Double)`< 2.0 1 `std::Int.compareTo(Double)`>= 2.0