KT-351 Distinguish statement and expression positions
This commit is contained in:
@@ -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;
|
||||
|
||||
+18
-4
@@ -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;
|
||||
}
|
||||
|
||||
+32
-13
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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);
|
||||
}
|
||||
|
||||
+2
@@ -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);
|
||||
}
|
||||
|
||||
+7
-7
@@ -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();
|
||||
|
||||
+16
-4
@@ -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
|
||||
|
||||
+61
-24
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-5
@@ -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");
|
||||
|
||||
+126
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user