KT-235 Illegal assignment return type
This commit is contained in:
@@ -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");
|
||||
|
||||
+24
-13
@@ -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()
|
||||
}
|
||||
Reference in New Issue
Block a user