KT-351 Distinguish statement and expression positions

This commit is contained in:
svtk
2011-12-13 19:43:20 +04:00
parent 182009ab61
commit a41d33a56c
19 changed files with 318 additions and 65 deletions
@@ -232,6 +232,14 @@ public interface Errors {
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> IMPLICIT_CAST_TO_UNIT_OR_ANY = ParameterizedDiagnosticFactory1.create(WARNING, "Type was casted to ''{0}''. Please specify ''{0}'' as expected type, if you mean such cast");
ParameterizedDiagnosticFactory1<JetExpression> EXPRESSION_EXPECTED = new ParameterizedDiagnosticFactory1<JetExpression>(ERROR, "{0} is not an expression, and only expression are allowed here") {
@Override
protected String makeMessageFor(JetExpression expression) {
String expressionType = expression.toString();
return expressionType.substring(0, 1) + expressionType.substring(1).toLowerCase();
}
};
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");
@@ -242,6 +242,11 @@ public class JetStandardClasses {
public static JetType getAnyType() {
return ANY_TYPE;
}
public static boolean isAny(JetType type) {
return !(type instanceof NamespaceType) &&
type.getConstructor() == ANY_TYPE.getConstructor();
}
public static JetType getNullableAnyType() {
return NULLABLE_ANY_TYPE;
@@ -110,11 +110,15 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetType visitParenthesizedExpression(JetParenthesizedExpression expression, ExpressionTypingContext context) {
return visitParenthesizedExpression(expression, context, false);
}
public JetType visitParenthesizedExpression(JetParenthesizedExpression expression, ExpressionTypingContext context, boolean isStatement) {
JetExpression innerExpression = expression.getExpression();
if (innerExpression == null) {
return null;
}
return DataFlowUtils.checkType(facade.getType(innerExpression, context.replaceScope(context.scope)), expression, context);
return DataFlowUtils.checkType(facade.getType(innerExpression, context.replaceScope(context.scope), isStatement), expression, context);
}
@Override
@@ -479,7 +483,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetType visitBlockExpression(JetBlockExpression expression, ExpressionTypingContext context) {
return context.getServices().getBlockReturnedType(context.scope, expression, CoercionStrategy.NO_COERCION, context);
return visitBlockExpression(expression, context, false);
}
public JetType visitBlockExpression(JetBlockExpression expression, ExpressionTypingContext context, boolean isStatement) {
return context.getServices().getBlockReturnedType(context.scope, expression, isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION, context);
}
@Override
@@ -611,6 +619,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetType visitUnaryExpression(JetUnaryExpression expression, ExpressionTypingContext context) {
return visitUnaryExpression(expression, context, false);
}
public JetType visitUnaryExpression(JetUnaryExpression expression, ExpressionTypingContext context, boolean isStatement) {
JetExpression baseExpression = expression.getBaseExpression();
if (baseExpression == null) return null;
JetSimpleNameExpression operationSign = expression.getOperationReference();
@@ -619,9 +631,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
referencedName = referencedName == null ? " <?>" : referencedName;
context.labelResolver.enterLabeledElement(referencedName.substring(1), baseExpression);
// TODO : Some processing for the label?
JetType type = DataFlowUtils.checkType(facade.getType(baseExpression, context.replaceExpectedReturnType(context.expectedType)), expression, context);
ExpressionTypingContext newContext = context.replaceExpectedReturnType(context.expectedType);
JetType type = facade.getType(baseExpression, newContext, isStatement);
context.labelResolver.exitLabeledElement(baseExpression);
return type;
return DataFlowUtils.checkType(type, expression, context);
}
IElementType operationType = operationSign.getReferencedNameElementType();
String name = OperatorConventions.UNARY_OPERATION_NAMES.get(operationType);
@@ -835,6 +848,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
private JetType assignmentIsNotAnExpressionError(JetBinaryExpression expression, ExpressionTypingContext context) {
facade.checkStatementType(expression, context.replaceExpectedType(NO_EXPECTED_TYPE));
context.trace.report(ASSIGNMENT_IN_EXPRESSION_CONTEXT.on(expression));
return null;
}
@@ -12,8 +12,6 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.calls.TaskPrioritizers;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
@@ -54,7 +52,11 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetType visitIfExpression(JetIfExpression expression, ExpressionTypingContext contextWithExpectedType) {
public JetType visitIfExpression(JetIfExpression expression, ExpressionTypingContext context) {
return visitIfExpression(expression, context, false);
}
public JetType visitIfExpression(JetIfExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
JetExpression condition = expression.getCondition();
checkCondition(context.scope, condition, context);
@@ -73,7 +75,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
if (type != null && JetStandardClasses.isNothing(type)) {
facade.setResultingDataFlowInfo(elseInfo);
}
return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
return DataFlowUtils.checkImplicitCast(DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType), expression, contextWithExpectedType, isStatement);
}
return null;
}
@@ -82,10 +84,11 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
if (type != null && JetStandardClasses.isNothing(type)) {
facade.setResultingDataFlowInfo(thenInfo);
}
return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
return DataFlowUtils.checkImplicitCast(DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType), expression, contextWithExpectedType, isStatement);
}
JetType thenType = context.getServices().getBlockReturnedTypeWithWritableScope(thenScope, Collections.singletonList(thenBranch), CoercionStrategy.NO_COERCION, contextWithExpectedType.replaceDataFlowInfo(thenInfo));
JetType elseType = context.getServices().getBlockReturnedTypeWithWritableScope(elseScope, Collections.singletonList(elseBranch), CoercionStrategy.NO_COERCION, contextWithExpectedType.replaceDataFlowInfo(elseInfo));
CoercionStrategy coercionStrategy = isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION;
JetType thenType = context.getServices().getBlockReturnedTypeWithWritableScope(thenScope, Collections.singletonList(thenBranch), coercionStrategy, contextWithExpectedType.replaceDataFlowInfo(thenInfo));
JetType elseType = context.getServices().getBlockReturnedTypeWithWritableScope(elseScope, Collections.singletonList(elseBranch), coercionStrategy, contextWithExpectedType.replaceDataFlowInfo(elseInfo));
JetType result;
if (thenType == null) {
@@ -107,11 +110,18 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
else if (jumpInElse && !jumpInThen) {
facade.setResultingDataFlowInfo(thenInfo);
}
return result;
if (result == null) return null;
return DataFlowUtils.checkImplicitCast(result, expression, contextWithExpectedType, isStatement);
}
@Override
public JetType visitWhileExpression(JetWhileExpression expression, ExpressionTypingContext contextWithExpectedType) {
public JetType visitWhileExpression(JetWhileExpression expression, ExpressionTypingContext context) {
return visitWhileExpression(expression, context, false);
}
public JetType visitWhileExpression(JetWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
if (!isStatement) return DataFlowUtils.illegalStatementType(expression, contextWithExpectedType, facade);
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
JetExpression condition = expression.getCondition();
checkCondition(context.scope, condition, context);
@@ -152,7 +162,12 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
}
@Override
public JetType visitDoWhileExpression(JetDoWhileExpression expression, ExpressionTypingContext contextWithExpectedType) {
public JetType visitDoWhileExpression(JetDoWhileExpression expression, ExpressionTypingContext context) {
return visitDoWhileExpression(expression, context, false);
}
public JetType visitDoWhileExpression(JetDoWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
if (!isStatement) return DataFlowUtils.illegalStatementType(expression, contextWithExpectedType, facade);
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
JetExpression body = expression.getBody();
JetScope conditionScope = context.scope;
@@ -181,7 +196,13 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
}
@Override
public JetType visitForExpression(JetForExpression expression, ExpressionTypingContext contextWithExpectedType) {
public JetType visitForExpression(JetForExpression expression, ExpressionTypingContext context) {
return visitForExpression(expression, context, false);
}
public JetType visitForExpression(JetForExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
if (!isStatement) return DataFlowUtils.illegalStatementType(expression, contextWithExpectedType, facade);
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
JetParameter loopParameter = expression.getLoopParameter();
JetExpression loopRange = expression.getLoopRange();
@@ -419,6 +440,4 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
context.labelResolver.recordLabel(expression, context);
return DataFlowUtils.checkType(JetStandardClasses.getNothingType(), expression, context);
}
}
@@ -11,6 +11,7 @@ import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.TypeUtils;
@@ -18,8 +19,7 @@ import org.jetbrains.jet.lexer.JetTokens;
import java.util.List;
import static org.jetbrains.jet.lang.diagnostics.Errors.AUTOCAST_IMPOSSIBLE;
import static org.jetbrains.jet.lang.diagnostics.Errors.TYPE_MISMATCH;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
/**
@@ -154,4 +154,30 @@ public class DataFlowUtils {
context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType));
return expressionType;
}
@Nullable
public static JetType checkStatementType(@NotNull JetExpression expression, @NotNull ExpressionTypingContext context) {
if (context.expectedType != TypeUtils.NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(context.expectedType)) {
context.trace.report(EXPECTED_TYPE_MISMATCH.on(expression, context.expectedType));
return null;
}
return JetStandardClasses.getUnitType();
}
@Nullable
public static JetType checkImplicitCast(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ExpressionTypingContext context, boolean isStatement) {
if (expressionType != null && context.expectedType == TypeUtils.NO_EXPECTED_TYPE && !isStatement &&
(JetStandardClasses.isUnit(expressionType) || JetStandardClasses.isAny(expressionType))) {
context.trace.report(IMPLICIT_CAST_TO_UNIT_OR_ANY.on(expression, expressionType));
}
return expressionType;
}
@Nullable
public static JetType illegalStatementType(@NotNull JetExpression expression, @NotNull ExpressionTypingContext context, @NotNull ExpressionTypingInternals facade) {
facade.checkStatementType(expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE));
context.trace.report(EXPRESSION_EXPECTED.on(expression, expression));
return null;
}
}
@@ -14,7 +14,7 @@ public interface ExpressionTypingFacade {
@Nullable
JetType getType(@NotNull JetExpression expression, ExpressionTypingContext context);
@Nullable
JetType getTypeForStatement(@NotNull JetExpression expression, ExpressionTypingContext context);
JetType getType(@NotNull JetExpression expression, ExpressionTypingContext context, boolean isStatement);
}
@@ -24,4 +24,6 @@ import org.jetbrains.jet.lang.types.JetType;
JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context);
void checkInExpression(JetElement callElement, @NotNull JetSimpleNameExpression operationSign, @NotNull JetExpression left, @NotNull JetExpression right, ExpressionTypingContext context);
void checkStatementType(@NotNull JetExpression expression, ExpressionTypingContext context);
}
@@ -133,7 +133,7 @@ public class ExpressionTypingServices {
getBlockReturnedType(newContext.scope, blockExpression, CoercionStrategy.COERCION_TO_UNIT, context);
}
else {
expressionTypingFacade.getType(bodyExpression, newContext);
expressionTypingFacade.getType(bodyExpression, newContext, !blockBody);
}
}
@@ -159,7 +159,7 @@ public class ExpressionTypingServices {
assert bodyExpression != null;
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
expressionTypingFacade.getType(bodyExpression, ExpressionTypingContext.newContext(semanticServices, new HashMap<JetPattern, DataFlowInfo>(), new HashMap<JetPattern, List<VariableDescriptor>>(), new LabelResolver(),
trace, functionInnerScope, DataFlowInfo.EMPTY, NO_EXPECTED_TYPE, FORBIDDEN, false));
trace, functionInnerScope, DataFlowInfo.EMPTY, NO_EXPECTED_TYPE, FORBIDDEN, false), !function.hasBlockBody());
//todo function literals
final Collection<JetExpression> returnedExpressions = Lists.newArrayList();
if (function.hasBlockBody()) {
@@ -225,13 +225,13 @@ public class ExpressionTypingServices {
final boolean[] mismatch = new boolean[1];
ObservableBindingTrace errorInterceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceExpectingUnit, statementExpression, mismatch);
newContext = createContext(newContext, errorInterceptingTrace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType);
result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext);
result = blockLevelVisitor.getType(statementExpression, newContext, true);
if (mismatch[0]) {
TemporaryBindingTrace temporaryTraceNoExpectedType = TemporaryBindingTrace.create(trace);
mismatch[0] = false;
ObservableBindingTrace interceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceNoExpectedType, statementExpression, mismatch);
newContext = createContext(newContext, interceptingTrace, scope, newContext.dataFlowInfo, NO_EXPECTED_TYPE, context.expectedReturnType);
result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext);
result = blockLevelVisitor.getType(statementExpression, newContext, true);
if (mismatch[0]) {
temporaryTraceExpectingUnit.commit();
}
@@ -245,11 +245,11 @@ public class ExpressionTypingServices {
}
else {
newContext = createContext(newContext, trace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType);
result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext);
result = blockLevelVisitor.getType(statementExpression, newContext, true);
}
}
else {
result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext);
result = blockLevelVisitor.getType(statementExpression, newContext, true);
if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT) {
boolean mightBeUnit = false;
if (statementExpression instanceof JetDeclaration) {
@@ -271,7 +271,7 @@ public class ExpressionTypingServices {
}
}
else {
result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext);
result = blockLevelVisitor.getType(statementExpression, newContext, true);
}
DataFlowInfo newDataFlowInfo = blockLevelVisitor.getResultingDataFlowInfo();
@@ -40,7 +40,7 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetType, Expre
private ExpressionTypingVisitorDispatcher(WritableScope writableScope) {
this.basic = new BasicExpressionTypingVisitor(this);
if (writableScope != null) {
this.statements = new ExpressionTypingVisitorForStatements(this, writableScope, basic);
this.statements = new ExpressionTypingVisitorForStatements(this, writableScope, basic, controlStructures, patterns);
}
else {
this.statements = null;
@@ -84,10 +84,22 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetType, Expre
return getType(expression, context, this);
}
@Override
@Nullable
public final JetType getTypeForStatement(@NotNull JetExpression expression, ExpressionTypingContext context) {
return getType(expression, context, statements);
public final JetType getType(@NotNull JetExpression expression, ExpressionTypingContext context, boolean isStatement) {
if (!isStatement) return getType(expression, context);
if (statements != null) {
return getType(expression, context, statements);
}
return getType(expression, context, createStatementVisitor(context));
}
private ExpressionTypingVisitorForStatements createStatementVisitor(ExpressionTypingContext context) {
return new ExpressionTypingVisitorForStatements(this, ExpressionTypingUtils.newWritableScopeImpl(context).setDebugName("statement scope"), basic, controlStructures, patterns);
}
@Override
public void checkStatementType(@NotNull JetExpression expression, ExpressionTypingContext context) {
expression.accept(createStatementVisitor(context), context);
}
@Nullable
@@ -1,6 +1,5 @@
package org.jetbrains.jet.lang.types.expressions;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,22 +31,20 @@ import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.get
public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisitor {
private final WritableScope scope;
private final BasicExpressionTypingVisitor basic;
private final ControlStructureTypingVisitor controlStructures;
private final PatternMatchingTypingVisitor patterns;
public ExpressionTypingVisitorForStatements(@NotNull ExpressionTypingInternals facade, @NotNull WritableScope scope, BasicExpressionTypingVisitor basic) {
public ExpressionTypingVisitorForStatements(
@NotNull ExpressionTypingInternals facade,
@NotNull WritableScope scope,
BasicExpressionTypingVisitor basic,
@NotNull ControlStructureTypingVisitor controlStructures,
@NotNull PatternMatchingTypingVisitor patterns) {
super(facade);
this.scope = scope;
this.basic = basic;
}
@Nullable
private JetType checkExpectedType(@NotNull JetExpression expression, @NotNull ExpressionTypingContext context) {
if (context.expectedType != TypeUtils.NO_EXPECTED_TYPE) {
if (JetStandardClasses.isUnit(context.expectedType)) {
return JetStandardClasses.getUnitType();
}
context.trace.report(EXPECTED_TYPE_MISMATCH.on(expression, context.expectedType));
}
return null;
this.controlStructures = controlStructures;
this.patterns = patterns;
}
@Nullable
@@ -57,7 +54,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
context.trace.report(Errors.ASSIGNMENT_TYPE_MISMATCH.on(expression, context.expectedType));
return null;
}
return checkExpectedType(expression, context);
return DataFlowUtils.checkStatementType(expression, context);
}
@Override
@@ -68,7 +65,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
PropertyDescriptor propertyDescriptor = context.getDescriptorResolver().resolveObjectDeclarationAsPropertyDescriptor(scope.getContainingDeclaration(), declaration, classDescriptor);
scope.addVariableDescriptor(propertyDescriptor);
}
return checkExpectedType(declaration, context);
return DataFlowUtils.checkStatementType(declaration, context);
}
@Override
@@ -103,7 +100,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
}
scope.addVariableDescriptor(propertyDescriptor);
return checkExpectedType(property, context);
return DataFlowUtils.checkStatementType(property, context);
}
@Override
@@ -112,7 +109,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
scope.addFunctionDescriptor(functionDescriptor);
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace);
context.getServices().checkFunctionReturnType(functionInnerScope, function, functionDescriptor, context.dataFlowInfo);
return checkExpectedType(function, context);
return DataFlowUtils.checkStatementType(function, context);
}
@Override
@@ -127,24 +124,24 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
@Override
public JetType visitDeclaration(JetDeclaration dcl, ExpressionTypingContext context) {
return checkExpectedType(dcl, context);
return DataFlowUtils.checkStatementType(dcl, context);
}
@Override
public JetType visitBinaryExpression(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
public JetType visitBinaryExpression(JetBinaryExpression expression, ExpressionTypingContext context) {
JetSimpleNameExpression operationSign = expression.getOperationReference();
IElementType operationType = operationSign.getReferencedNameElementType();
JetType result;
if (operationType == JetTokens.EQ) {
result = visitAssignment(expression, contextWithExpectedType);
result = visitAssignment(expression, context);
}
else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
result = visitAssignmentOperation(expression, contextWithExpectedType);
result = visitAssignmentOperation(expression, context);
}
else {
return facade.getType(expression, contextWithExpectedType);
return facade.getType(expression, context);
}
return DataFlowUtils.checkType(result, expression, contextWithExpectedType);
return DataFlowUtils.checkType(result, expression, context);
}
protected JetType visitAssignmentOperation(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
@@ -218,7 +215,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
if (left instanceof JetSimpleNameExpression) {
ExpressionTypingUtils.checkWrappingInRef(left, context);
}
return checkExpectedType(expression, contextWithExpectedType);
return DataFlowUtils.checkStatementType(expression, contextWithExpectedType);
}
private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, ExpressionTypingContext context) {
@@ -259,4 +256,44 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
context.trace.report(UNSUPPORTED.on(element, "in a block"));
return null;
}
@Override
public JetType visitWhileExpression(JetWhileExpression expression, ExpressionTypingContext context) {
return controlStructures.visitWhileExpression(expression, context, true);
}
@Override
public JetType visitDoWhileExpression(JetDoWhileExpression expression, ExpressionTypingContext context) {
return controlStructures.visitDoWhileExpression(expression, context, true);
}
@Override
public JetType visitForExpression(JetForExpression expression, ExpressionTypingContext context) {
return controlStructures.visitForExpression(expression, context, true);
}
@Override
public JetType visitIfExpression(JetIfExpression expression, ExpressionTypingContext context) {
return controlStructures.visitIfExpression(expression, context, true);
}
@Override
public JetType visitWhenExpression(final JetWhenExpression expression, ExpressionTypingContext context) {
return patterns.visitWhenExpression(expression, context, true);
}
@Override
public JetType visitBlockExpression(JetBlockExpression expression, ExpressionTypingContext context) {
return basic.visitBlockExpression(expression, context, true);
}
@Override
public JetType visitParenthesizedExpression(JetParenthesizedExpression expression, ExpressionTypingContext context) {
return basic.visitParenthesizedExpression(expression, context, true);
}
@Override
public JetType visitUnaryExpression(JetUnaryExpression expression, ExpressionTypingContext context) {
return basic.visitUnaryExpression(expression, context, true);
}
}
@@ -13,7 +13,6 @@ import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver;
import org.jetbrains.jet.lang.types.*;
@@ -21,7 +20,6 @@ import org.jetbrains.jet.lang.types.*;
import java.util.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.ensureBooleanResultWithCustomSubject;
import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.newWritableScopeImpl;
/**
@@ -48,7 +46,11 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
}
@Override
public JetType visitWhenExpression(final JetWhenExpression expression, ExpressionTypingContext contextWithExpectedType) {
public JetType visitWhenExpression(final JetWhenExpression expression, ExpressionTypingContext context) {
return visitWhenExpression(expression, context, false);
}
public JetType visitWhenExpression(final JetWhenExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
// TODO :change scope according to the bound value in the when header
final JetExpression subjectExpression = expression.getSubjectExpression();
@@ -92,7 +94,9 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
}
JetExpression bodyExpression = whenEntry.getExpression();
if (bodyExpression != null) {
JetType type = facade.getType(bodyExpression, contextWithExpectedType.replaceScope(scopeToExtend).replaceDataFlowInfo(newDataFlowInfo));
ExpressionTypingContext newContext = contextWithExpectedType.replaceScope(scopeToExtend).replaceDataFlowInfo(newDataFlowInfo);
CoercionStrategy coercionStrategy = isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION;
JetType type = context.getServices().getBlockReturnedTypeWithWritableScope(scopeToExtend, Collections.singletonList(bodyExpression), coercionStrategy, newContext);
if (type != null) {
expressionTypes.add(type);
}
@@ -100,7 +104,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
}
if (!expressionTypes.isEmpty()) {
return CommonSupertypes.commonSupertype(expressionTypes);
return DataFlowUtils.checkImplicitCast(CommonSupertypes.commonSupertype(expressionTypes), expression, contextWithExpectedType, isStatement);
}
else if (expression.getEntries().isEmpty()) {
// context.trace.getErrorHandler().genericError(expression.getNode(), "Entries required for when-expression");
@@ -0,0 +1,126 @@
namespace kt770_351_735
//+JDK
//KT-770 Reference is not resolved to anything, but is not marked unresolved
fun main(args : Array<String>) {
var i = 0
when (i) {
1 => i--
2 => i = 2 // i is surrounded by a black border
else => <!UNRESOLVED_REFERENCE!>j<!> = 2
}
System.out?.println(i)
}
//KT-351 Distinguish statement and expression positions
val w = <!EXPRESSION_EXPECTED!>while (true) {}<!>
fun foo() {
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>z<!> = 2
val r = { // type fun(): Int is inferred
if (true) {
2
}
else {
z = <!UNUSED_VALUE!>34<!>
}
}
val <!UNUSED_VARIABLE!>f<!>: fun(): Int = <!TYPE_MISMATCH!>r<!>
val <!UNUSED_VARIABLE!>g<!>: fun(): Any = r
}
//KT-735 Statements without braces are prohibited on the right side of when entries.
fun box() : Int {
val d = 2
var z = 0
when(d) {
is 5, is 3 => z++
else => z = -1000
}
return z
}
//More tests
fun test1() = while(true) {}
fun test2(): Unit = while(true) {}
fun testCoercionToUnit() {
val <!UNUSED_VARIABLE!>simple<!>: fun(): Unit = {
41
}
val <!UNUSED_VARIABLE!>withIf<!>: fun(): Unit = {
if (true) {
3
} else {
45
}
}
val i = 34
val <!UNUSED_VARIABLE!>withWhen<!> : fun() : Unit = {
when(i) {
is 1 => {
val d = 34
"1"
doSmth(d)
}
is 2 => '4'
else => true
}
}
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>x<!> = 43
val checkType = {
if (true) {
x = <!UNUSED_VALUE!>4<!>
} else {
45
}
}
val <!UNUSED_VARIABLE!>f<!> : fun() : String = <!TYPE_MISMATCH!>checkType<!>
}
fun doSmth(<!UNUSED_PARAMETER!>i<!>: Int) {}
fun testImplicitCoercion() {
val d = 21
var z = 0
var <!UNUSED_VARIABLE!>i<!> = <!IMPLICIT_CAST_TO_UNIT_OR_ANY!>when(d) {
is 3 => null
is 4 => { val <!NAME_SHADOWING, UNUSED_VARIABLE!>z<!> = 23 }
else => z = 20
}<!>
var <!UNUSED_VARIABLE!>u<!> = <!IMPLICIT_CAST_TO_UNIT_OR_ANY!>when(d) {
is 3 => {
z = <!UNUSED_VALUE!>34<!>
}
else => <!UNUSED_CHANGED_VALUE!>z--<!>
}<!>
var <!UNUSED_VARIABLE!>iff<!> = <!IMPLICIT_CAST_TO_UNIT_OR_ANY!>if (true) {
z = <!UNUSED_VALUE!>34<!>
}<!>
val <!UNUSED_VARIABLE!>g<!> = <!IMPLICIT_CAST_TO_UNIT_OR_ANY!>if (true) 4<!>
val <!UNUSED_VARIABLE!>h<!> = <!IMPLICIT_CAST_TO_UNIT_OR_ANY!>if (false) 4 else {}<!>
bar(if (true) {
4
}
else {
z = <!UNUSED_VALUE!>342<!>
})
}
fun bar(<!UNUSED_PARAMETER!>a<!>: Unit) {}
fun testStatementInExpressionContext() {
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>z<!> = 34
val <!UNUSED_VARIABLE!>a1<!>: Unit = <!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>z = <!UNUSED_VALUE!>334<!><!>
val <!UNUSED_VARIABLE!>a2<!>: Unit = <!EXPRESSION_EXPECTED!>while(true) {}<!>
val <!UNUSED_VARIABLE!>f<!> = <!EXPRESSION_EXPECTED!>for (i in 1..10) {}<!>
if (true) return <!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>z = <!UNUSED_VALUE!>34<!><!>
return <!EXPRESSION_EXPECTED!>while (true) {}<!>
}
@@ -18,6 +18,6 @@ fun box() : Boolean {
fun box2() : Boolean {
var <!UNUSED_VARIABLE!>c<!> = A()
var c = A()
return (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>c.p = "yeah"<!>) && true
}
@@ -326,9 +326,9 @@ public class JetTypeCheckerTest extends JetLiteFixture {
}
public void testLoops() throws Exception {
assertType("while (1) {1}", "Unit");
assertType("do {1} while(1)", "Unit");
assertType("for (i in 1) {1}", "Unit");
assertType("{ while (1) {1} }", "fun(): Unit");
assertType("{ do {1} while(1) }", "fun(): Unit");
assertType("{ for (i in 1) {1} }", "fun(): Unit");
}
public void testFunctionLiterals() throws Exception {