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 ('{...}')");
|
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> 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> 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> 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");
|
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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
|
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
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.TemporaryBindingTrace;
|
||||||
import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
|
import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
|
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
|
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
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.JetStandardClasses;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||||
@@ -35,7 +34,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@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 (context.expectedType != TypeUtils.NO_EXPECTED_TYPE) {
|
||||||
if (JetStandardClasses.isUnit(context.expectedType)) {
|
if (JetStandardClasses.isUnit(context.expectedType)) {
|
||||||
return JetStandardClasses.getUnitType();
|
return JetStandardClasses.getUnitType();
|
||||||
@@ -45,6 +44,16 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
|||||||
return null;
|
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
|
@Override
|
||||||
public JetType visitObjectDeclaration(JetObjectDeclaration declaration, ExpressionTypingContext context) {
|
public JetType visitObjectDeclaration(JetObjectDeclaration declaration, ExpressionTypingContext context) {
|
||||||
TopDownAnalyzer.processObject(context.semanticServices, context.trace, scope, scope.getContainingDeclaration(), declaration);
|
TopDownAnalyzer.processObject(context.semanticServices, context.trace, scope, scope.getContainingDeclaration(), declaration);
|
||||||
@@ -108,7 +117,8 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.
|
// If there's += (or similar op) defined as such, we just call it.
|
||||||
JetSimpleNameExpression operationSign = expression.getOperationReference();
|
JetSimpleNameExpression operationSign = expression.getOperationReference();
|
||||||
IElementType operationType = operationSign.getReferencedNameElementType();
|
IElementType operationType = operationSign.getReferencedNameElementType();
|
||||||
@@ -126,8 +136,8 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
|||||||
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
||||||
resolveArrayAccessToLValue(arrayAccessExpression, expression.getRight(), operationSign, context);
|
resolveArrayAccessToLValue(arrayAccessExpression, expression.getRight(), operationSign, context);
|
||||||
}
|
}
|
||||||
JetType typeForBinaryCall = getTypeForBinaryCall(scope, counterpartName, context, expression);
|
assignmentOperationType = getTypeForBinaryCall(scope, counterpartName, context, expression);
|
||||||
if (typeForBinaryCall != null) {
|
if (assignmentOperationType != null) {
|
||||||
context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression);
|
context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression);
|
||||||
ExpressionTypingUtils.checkWrappingInRef(expression.getLeft(), context);
|
ExpressionTypingUtils.checkWrappingInRef(expression.getLeft(), context);
|
||||||
}
|
}
|
||||||
@@ -136,20 +146,21 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
|||||||
temporaryBindingTrace.commit();
|
temporaryBindingTrace.commit();
|
||||||
}
|
}
|
||||||
checkLValue(context.trace, expression.getLeft());
|
checkLValue(context.trace, expression.getLeft());
|
||||||
return checkExpectedType(expression, context);
|
return checkAssignmentType(assignmentOperationType, expression, contextWithExpectedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 left = JetPsiUtil.deparenthesize(expression.getLeft());
|
||||||
JetExpression right = expression.getRight();
|
JetExpression right = expression.getRight();
|
||||||
if (left instanceof JetArrayAccessExpression) {
|
if (left instanceof JetArrayAccessExpression) {
|
||||||
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
||||||
JetType resultType = resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference(), context);
|
JetType assignmentType = resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference(), context);
|
||||||
checkLValue(context.trace, arrayAccessExpression);
|
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) {
|
if (right != null) {
|
||||||
JetType rightType = facade.getType(right, context.replaceExpectedType(leftType).replaceScope(scope));
|
JetType rightType = facade.getType(right, context.replaceExpectedType(leftType).replaceScope(scope));
|
||||||
}
|
}
|
||||||
@@ -168,7 +179,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
|||||||
}
|
}
|
||||||
ExpressionTypingUtils.checkWrappingInRef(simpleName, context);
|
ExpressionTypingUtils.checkWrappingInRef(simpleName, context);
|
||||||
}
|
}
|
||||||
return checkExpectedType(expression, context);
|
return checkExpectedType(expression, contextWithExpectedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, ExpressionTypingContext context) {
|
private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, ExpressionTypingContext context) {
|
||||||
@@ -196,7 +207,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
|||||||
// else {
|
// else {
|
||||||
// context.trace.record(REFERENCE_TARGET, operationSign, setFunctionDescriptor);
|
// context.trace.record(REFERENCE_TARGET, operationSign, setFunctionDescriptor);
|
||||||
// }
|
// }
|
||||||
return DataFlowUtils.checkType(setFunctionDescriptor.getReturnType(), arrayAccessExpression, context);
|
return setFunctionDescriptor.getReturnType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ fun testFunctionLiterals() {
|
|||||||
|
|
||||||
val endsWithReAssignment = { () : Int =>
|
val endsWithReAssignment = { () : Int =>
|
||||||
var x = 1
|
var x = 1
|
||||||
<!EXPECTED_TYPE_MISMATCH!>x += 333<!>
|
<!ASSIGNMENT_TYPE_MISMATCH!>x += 333<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
val endsWithFunDeclaration : fun() : String = {
|
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