By Pavel Talanov: KT-618 overloaded assignment operators should not allow for returning types other than Unit of Subtypes or the type where they are defined

This commit is contained in:
Andrey Breslav
2011-11-25 18:32:03 +03:00
parent ae6e87ef5a
commit a7eada71ce
2 changed files with 50 additions and 3 deletions
@@ -20,11 +20,12 @@ import org.jetbrains.jet.lexer.JetTokens;
import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_SET; import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_SET;
import static org.jetbrains.jet.lang.resolve.BindingContext.VARIABLE_REASSIGNMENT;
import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.getExpressionReceiver; import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.getExpressionReceiver;
/** /**
* @author abreslav * @author abreslav
*/ */
public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingVisitor { public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingVisitor {
private final WritableScope scope; private final WritableScope scope;
@@ -138,17 +139,35 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
} }
assignmentOperationType = getTypeForBinaryCall(scope, counterpartName, context, expression); assignmentOperationType = getTypeForBinaryCall(scope, counterpartName, context, expression);
if (assignmentOperationType != null) { if (assignmentOperationType != null) {
context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression); context.trace.record(VARIABLE_REASSIGNMENT, expression);
ExpressionTypingUtils.checkWrappingInRef(expression.getLeft(), context); ExpressionTypingUtils.checkWrappingInRef(expression.getLeft(), context);
} }
} }
else { else {
temporaryBindingTrace.commit(); temporaryBindingTrace.commit();
checkReassignment(expression, context, assignmentOperationType, left);
} }
checkLValue(context.trace, expression.getLeft()); checkLValue(context.trace, expression.getLeft());
return checkAssignmentType(assignmentOperationType, expression, contextWithExpectedType); return checkAssignmentType(assignmentOperationType, 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));
}
}
@Override @Override
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);
@@ -0,0 +1,28 @@
namespace lol
class B() {
fun plusAssign(other : B) : String {
return "s"
}
fun minusAssign(other : B) : String {
return "s"
}
fun modAssign(other : B) : String {
return "s"
}
fun divAssign(other : B) : String {
return "s"
}
fun timesAssign(other : B) : String {
return "s"
}
}
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()<!>
}