KT-235 Illegal assignment return type

This commit is contained in:
svtk
2011-11-10 22:13:52 +04:00
parent 89b4faa6fe
commit 25d26fe6fd
4 changed files with 75 additions and 14 deletions
@@ -215,6 +215,7 @@ public interface Errors {
SimpleDiagnosticFactory NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY = SimpleDiagnosticFactory.create(ERROR, "A 'return' expression required in a function with a block body ('{...}')");
ParameterizedDiagnosticFactory1<JetType> RETURN_TYPE_MISMATCH = ParameterizedDiagnosticFactory1.create(ERROR, "This function must return a value of type {0}");
ParameterizedDiagnosticFactory1<JetType> EXPECTED_TYPE_MISMATCH = ParameterizedDiagnosticFactory1.create(ERROR, "Expected a value of type {0}");
ParameterizedDiagnosticFactory1<JetType> ASSIGNMENT_TYPE_MISMATCH = ParameterizedDiagnosticFactory1.create(ERROR, "Expected a value of type {0}. Assignment operation is not an expression, so it does not return any value");
ParameterizedDiagnosticFactory1<JetType> UPPER_BOUND_VIOLATED = ParameterizedDiagnosticFactory1.create(ERROR, "An upper bound {0} is violated"); // TODO : Message
ParameterizedDiagnosticFactory1<JetType> FINAL_CLASS_OBJECT_UPPER_BOUND = ParameterizedDiagnosticFactory1.create(ERROR, "{0} is a final type, and thus a class object cannot extend it");
@@ -4,16 +4,15 @@ 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.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
@@ -35,7 +34,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
}
@Nullable
private JetType checkExpectedType(JetExpression expression, ExpressionTypingContext context) {
private JetType checkExpectedType(@NotNull JetExpression expression, @NotNull ExpressionTypingContext context) {
if (context.expectedType != TypeUtils.NO_EXPECTED_TYPE) {
if (JetStandardClasses.isUnit(context.expectedType)) {
return JetStandardClasses.getUnitType();
@@ -45,6 +44,16 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
return null;
}
@Nullable
private JetType checkAssignmentType(@Nullable JetType assignmentType, @NotNull JetBinaryExpression expression, @NotNull ExpressionTypingContext context) {
if (assignmentType != null && !JetStandardClasses.isUnit(assignmentType) && context.expectedType != TypeUtils.NO_EXPECTED_TYPE &&
TypeUtils.equalTypes(context.expectedType, assignmentType)) {
context.trace.report(Errors.ASSIGNMENT_TYPE_MISMATCH.on(expression, context.expectedType));
return null;
}
return checkExpectedType(expression, context);
}
@Override
public JetType visitObjectDeclaration(JetObjectDeclaration declaration, ExpressionTypingContext context) {
TopDownAnalyzer.processObject(context.semanticServices, context.trace, scope, scope.getContainingDeclaration(), declaration);
@@ -108,7 +117,8 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
}
@Override
protected JetType visitAssignmentOperation(JetBinaryExpression expression, ExpressionTypingContext context) {
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.
JetSimpleNameExpression operationSign = expression.getOperationReference();
IElementType operationType = operationSign.getReferencedNameElementType();
@@ -126,8 +136,8 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
resolveArrayAccessToLValue(arrayAccessExpression, expression.getRight(), operationSign, context);
}
JetType typeForBinaryCall = getTypeForBinaryCall(scope, counterpartName, context, expression);
if (typeForBinaryCall != null) {
assignmentOperationType = getTypeForBinaryCall(scope, counterpartName, context, expression);
if (assignmentOperationType != null) {
context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression);
ExpressionTypingUtils.checkWrappingInRef(expression.getLeft(), context);
}
@@ -136,20 +146,21 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
temporaryBindingTrace.commit();
}
checkLValue(context.trace, expression.getLeft());
return checkExpectedType(expression, context);
return checkAssignmentType(assignmentOperationType, expression, contextWithExpectedType);
}
@Override
protected JetType visitAssignment(JetBinaryExpression expression, ExpressionTypingContext context) {
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 resultType = resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference(), context);
JetType assignmentType = resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference(), context);
checkLValue(context.trace, arrayAccessExpression);
return resultType;
return checkAssignmentType(assignmentType, expression, contextWithExpectedType);
}
JetType leftType = facade.getType(expression.getLeft(), context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(scope));
JetType leftType = facade.getType(expression.getLeft(), context.replaceScope(scope));
if (right != null) {
JetType rightType = facade.getType(right, context.replaceExpectedType(leftType).replaceScope(scope));
}
@@ -168,7 +179,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
}
ExpressionTypingUtils.checkWrappingInRef(simpleName, context);
}
return checkExpectedType(expression, context);
return checkExpectedType(expression, contextWithExpectedType);
}
private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, ExpressionTypingContext context) {
@@ -196,7 +207,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
// else {
// context.trace.record(REFERENCE_TARGET, operationSign, setFunctionDescriptor);
// }
return DataFlowUtils.checkType(setFunctionDescriptor.getReturnType(), arrayAccessExpression, context);
return setFunctionDescriptor.getReturnType();
}
@Override
@@ -185,7 +185,7 @@ fun testFunctionLiterals() {
val endsWithReAssignment = { () : Int =>
var x = 1
<!EXPECTED_TYPE_MISMATCH!>x += 333<!>
<!ASSIGNMENT_TYPE_MISMATCH!>x += 333<!>
}
val endsWithFunDeclaration : fun() : String = {
@@ -0,0 +1,49 @@
//KT-235 Illegal assignment return type
namespace kt235
fun main(args: Array<String>) {
val array = MyArray()
val f = { (): String =>
<!EXPECTED_TYPE_MISMATCH!>array[2] = 23<!> //error: Type mismatch: inferred type is Int (!!!) but String was expected
}
val g = {(): String =>
var x = 1
<!EXPECTED_TYPE_MISMATCH!>x += 2<!> //no error, but it should be here
}
val h = {(): String =>
var x = 1
<!EXPECTED_TYPE_MISMATCH!>x = 2<!> //the same
}
val array1 = MyArray1()
val x = { (): String =>
<!EXPECTED_TYPE_MISMATCH!>array1[2] = 23<!>
}
val fi = { (): Int =>
<!ASSIGNMENT_TYPE_MISMATCH!>array[2] = 23<!>
}
val gi = {(): Int =>
var x = 1
<!ASSIGNMENT_TYPE_MISMATCH!>x += 21<!>
}
var m: MyNumber = MyNumber()
val a = { (): MyNumber =>
m++
}
}
class MyArray() {
fun get(i: Int): Int = 1
fun set(i: Int, value: Int): Int = 1
}
class MyArray1() {
fun get(i: Int): Int = 1
fun set(i: Int, value: Int) {}
}
class MyNumber() {
fun inc(): MyNumber = MyNumber()
}