Merge remote branch 'origin/master'
This commit is contained in:
+3
-3
@@ -25,12 +25,11 @@ public class SemanticWhitespaceAwarePsiBuilderImpl extends PsiBuilderAdapter imp
|
||||
|
||||
@Override
|
||||
public boolean newlineBeforeCurrentToken() {
|
||||
|
||||
if (!newlinesEnabled.peek()) return false;
|
||||
|
||||
if (eof()) return true;
|
||||
|
||||
// TODO: maybe, memorize this somehow?
|
||||
// TODO: maybe, memoize this somehow?
|
||||
for (int i = 1; i <= getCurrentOffset(); i++) {
|
||||
IElementType previousToken = rawLookup(-i);
|
||||
|
||||
@@ -51,8 +50,9 @@ public class SemanticWhitespaceAwarePsiBuilderImpl extends PsiBuilderAdapter imp
|
||||
assert previousTokenEnd < getOriginalText().length();
|
||||
|
||||
for (int j = previousTokenStart; j < previousTokenEnd; j++) {
|
||||
if (getOriginalText().charAt(j) == '\n')
|
||||
if (getOriginalText().charAt(j) == '\n') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+69
-66
@@ -651,7 +651,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
return DataFlowUtils.checkType(result, expression, context);
|
||||
}
|
||||
|
||||
protected void checkLValue(BindingTrace trace, JetExpression expression) {
|
||||
public void checkLValue(BindingTrace trace, JetExpression expression) {
|
||||
checkLValue(trace, expression, false);
|
||||
}
|
||||
|
||||
@@ -685,8 +685,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
}
|
||||
}
|
||||
else if (OperatorConventions.BINARY_OPERATION_NAMES.containsKey(operationType)) {
|
||||
result = getTypeForBinaryCall(context.scope, OperatorConventions.BINARY_OPERATION_NAMES.get(operationType), context, expression);
|
||||
}
|
||||
result = getTypeForBinaryCall(context.scope, OperatorConventions.BINARY_OPERATION_NAMES.get(operationType), context, expression);
|
||||
}
|
||||
else if (operationType == JetTokens.EQ) {
|
||||
result = visitAssignment(expression, contextWithExpectedType);
|
||||
}
|
||||
@@ -706,74 +706,77 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (OperatorConventions.EQUALS_OPERATIONS.contains(operationType)) {
|
||||
String name = "equals";
|
||||
if (right != null) {
|
||||
ExpressionReceiver receiver = ExpressionTypingUtils.safeGetExpressionReceiver(facade, left, context.replaceScope(context.scope));
|
||||
OverloadResolutionResults<FunctionDescriptor> resolutionResults = context.resolveExactSignature(
|
||||
receiver, "equals",
|
||||
Collections.singletonList(JetStandardClasses.getNullableAnyType()));
|
||||
if (resolutionResults.isSuccess()) {
|
||||
FunctionDescriptor equals = resolutionResults.getResult().getResultingDescriptor();
|
||||
context.trace.record(REFERENCE_TARGET, operationSign, equals);
|
||||
if (ensureBooleanResult(operationSign, name, equals.getReturnType(), context)) {
|
||||
ensureNonemptyIntersectionOfOperandTypes(expression, context);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (resolutionResults.isAmbiguity()) {
|
||||
context.trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(operationSign, resolutionResults.getResults()));
|
||||
else {
|
||||
JetType booleanType = context.semanticServices.getStandardLibrary().getBooleanType();
|
||||
if (OperatorConventions.EQUALS_OPERATIONS.contains(operationType)) {
|
||||
String name = "equals";
|
||||
if (right != null) {
|
||||
ExpressionReceiver receiver = ExpressionTypingUtils.safeGetExpressionReceiver(facade, left, context.replaceScope(context.scope));
|
||||
OverloadResolutionResults<FunctionDescriptor> resolutionResults = context.resolveExactSignature(
|
||||
receiver, "equals",
|
||||
Collections.singletonList(JetStandardClasses.getNullableAnyType()));
|
||||
if (resolutionResults.isSuccess()) {
|
||||
FunctionDescriptor equals = resolutionResults.getResult().getResultingDescriptor();
|
||||
context.trace.record(REFERENCE_TARGET, operationSign, equals);
|
||||
if (ensureBooleanResult(operationSign, name, equals.getReturnType(), context)) {
|
||||
ensureNonemptyIntersectionOfOperandTypes(expression, context);
|
||||
}
|
||||
}
|
||||
else {
|
||||
context.trace.report(EQUALS_MISSING.on(operationSign));
|
||||
if (resolutionResults.isAmbiguity()) {
|
||||
context.trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(operationSign, resolutionResults.getResults()));
|
||||
}
|
||||
else {
|
||||
context.trace.report(EQUALS_MISSING.on(operationSign));
|
||||
}
|
||||
}
|
||||
}
|
||||
result = booleanType;
|
||||
}
|
||||
else if (operationType == JetTokens.EQEQEQ || operationType == JetTokens.EXCLEQEQEQ) {
|
||||
ensureNonemptyIntersectionOfOperandTypes(expression, context);
|
||||
|
||||
// TODO : Check comparison pointlessness
|
||||
result = booleanType;
|
||||
}
|
||||
else if (OperatorConventions.IN_OPERATIONS.contains(operationType)) {
|
||||
if (right == null) {
|
||||
result = ErrorUtils.createErrorType("No right argument"); // TODO
|
||||
return null;
|
||||
}
|
||||
checkInExpression(expression, expression.getOperationReference(), expression.getLeft(), expression.getRight(), context);
|
||||
result = booleanType;
|
||||
}
|
||||
else if (operationType == JetTokens.ANDAND || operationType == JetTokens.OROR) {
|
||||
JetType leftType = facade.getType(left, context.replaceScope(context.scope));
|
||||
WritableScopeImpl leftScope = newWritableScopeImpl(context).setDebugName("Left scope of && or ||");
|
||||
DataFlowInfo flowInfoLeft = DataFlowUtils.extractDataFlowInfoFromCondition(left, operationType == JetTokens.ANDAND, leftScope, context); // TODO: This gets computed twice: here and in extractDataFlowInfoFromCondition() for the whole condition
|
||||
WritableScopeImpl rightScope = operationType == JetTokens.ANDAND ? leftScope : newWritableScopeImpl(context).setDebugName("Right scope of && or ||");
|
||||
JetType rightType = right == null ? null : facade.getType(right, context.replaceDataFlowInfo(flowInfoLeft).replaceScope(rightScope));
|
||||
if (leftType != null && !isBoolean(context.semanticServices, leftType)) {
|
||||
context.trace.report(TYPE_MISMATCH.on(left, booleanType, leftType));
|
||||
}
|
||||
if (rightType != null && !isBoolean(context.semanticServices, rightType)) {
|
||||
context.trace.report(TYPE_MISMATCH.on(right, booleanType, rightType));
|
||||
}
|
||||
result = booleanType;
|
||||
}
|
||||
else if (operationType == JetTokens.ELVIS) {
|
||||
JetType leftType = facade.getType(left, context.replaceScope(context.scope));
|
||||
JetType rightType = right == null ? null : facade.getType(right, contextWithExpectedType.replaceScope(context.scope));
|
||||
if (leftType != null) {
|
||||
if (!leftType.isNullable()) {
|
||||
context.trace.report(USELESS_ELVIS.on(expression, left, leftType));
|
||||
}
|
||||
if (rightType != null) {
|
||||
DataFlowUtils.checkType(TypeUtils.makeNullableAsSpecified(leftType, rightType.isNullable()), left, contextWithExpectedType);
|
||||
return TypeUtils.makeNullableAsSpecified(CommonSupertypes.commonSupertype(Arrays.asList(leftType, rightType)), rightType.isNullable());
|
||||
}
|
||||
}
|
||||
}
|
||||
result = context.semanticServices.getStandardLibrary().getBooleanType();
|
||||
}
|
||||
else if (operationType == JetTokens.EQEQEQ || operationType == JetTokens.EXCLEQEQEQ) {
|
||||
ensureNonemptyIntersectionOfOperandTypes(expression, context);
|
||||
|
||||
// TODO : Check comparison pointlessness
|
||||
result = context.semanticServices.getStandardLibrary().getBooleanType();
|
||||
}
|
||||
else if (OperatorConventions.IN_OPERATIONS.contains(operationType)) {
|
||||
if (right == null) {
|
||||
result = ErrorUtils.createErrorType("No right argument"); // TODO
|
||||
return null;
|
||||
else {
|
||||
context.trace.report(UNSUPPORTED.on(operationSign, "Unknown operation"));
|
||||
}
|
||||
checkInExpression(expression, expression.getOperationReference(), expression.getLeft(), expression.getRight(), context);
|
||||
result = context.semanticServices.getStandardLibrary().getBooleanType();
|
||||
}
|
||||
else if (operationType == JetTokens.ANDAND || operationType == JetTokens.OROR) {
|
||||
JetType leftType = facade.getType(left, context.replaceScope(context.scope));
|
||||
WritableScopeImpl leftScope = newWritableScopeImpl(context).setDebugName("Left scope of && or ||");
|
||||
DataFlowInfo flowInfoLeft = DataFlowUtils.extractDataFlowInfoFromCondition(left, operationType == JetTokens.ANDAND, leftScope, context); // TODO: This gets computed twice: here and in extractDataFlowInfoFromCondition() for the whole condition
|
||||
WritableScopeImpl rightScope = operationType == JetTokens.ANDAND ? leftScope : newWritableScopeImpl(context).setDebugName("Right scope of && or ||");
|
||||
JetType rightType = right == null ? null : facade.getType(right, context.replaceDataFlowInfo(flowInfoLeft).replaceScope(rightScope));
|
||||
if (leftType != null && !isBoolean(context.semanticServices, leftType)) {
|
||||
context.trace.report(TYPE_MISMATCH.on(left, context.semanticServices.getStandardLibrary().getBooleanType(), leftType));
|
||||
}
|
||||
if (rightType != null && !isBoolean(context.semanticServices, rightType)) {
|
||||
context.trace.report(TYPE_MISMATCH.on(right, context.semanticServices.getStandardLibrary().getBooleanType(), rightType));
|
||||
}
|
||||
result = context.semanticServices.getStandardLibrary().getBooleanType();
|
||||
}
|
||||
else if (operationType == JetTokens.ELVIS) {
|
||||
JetType leftType = facade.getType(left, context.replaceScope(context.scope));
|
||||
JetType rightType = right == null ? null : facade.getType(right, contextWithExpectedType.replaceScope(context.scope));
|
||||
if (leftType != null) {
|
||||
if (!leftType.isNullable()) {
|
||||
context.trace.report(USELESS_ELVIS.on(expression, left, leftType));
|
||||
}
|
||||
if (rightType != null) {
|
||||
DataFlowUtils.checkType(TypeUtils.makeNullableAsSpecified(leftType, rightType.isNullable()), left, contextWithExpectedType);
|
||||
return TypeUtils.makeNullableAsSpecified(CommonSupertypes.commonSupertype(Arrays.asList(leftType, rightType)), rightType.isNullable());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
context.trace.report(UNSUPPORTED.on(operationSign, "Unknown operation"));
|
||||
}
|
||||
return DataFlowUtils.checkType(result, expression, contextWithExpectedType);
|
||||
}
|
||||
@@ -842,7 +845,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected JetType getTypeForBinaryCall(JetScope scope, String name, ExpressionTypingContext context, JetBinaryExpression binaryExpression) {
|
||||
public JetType getTypeForBinaryCall(JetScope scope, String name, ExpressionTypingContext context, JetBinaryExpression binaryExpression) {
|
||||
ExpressionReceiver receiver = safeGetExpressionReceiver(facade, binaryExpression.getLeft(), context.replaceScope(scope));
|
||||
FunctionDescriptor functionDescriptor = context.replaceScope(scope).resolveCallWithGivenNameToDescriptor(
|
||||
CallMaker.makeCall(receiver, binaryExpression),
|
||||
|
||||
+13
-15
@@ -10,10 +10,11 @@ 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.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.OverloadResolutionResults;
|
||||
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;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
|
||||
@@ -21,7 +22,10 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||
@@ -36,10 +40,6 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
super(facade);
|
||||
}
|
||||
|
||||
private JetType getTypeWithNewScopeAndDataFlowInfo(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull DataFlowInfo newDataFlowInfo, @NotNull ExpressionTypingContext context) {
|
||||
return facade.getType(expression, context.replaceScope(scope).replaceDataFlowInfo(newDataFlowInfo));
|
||||
}
|
||||
|
||||
private void checkCondition(@NotNull JetScope scope, @Nullable JetExpression condition, ExpressionTypingContext context) {
|
||||
if (condition != null) {
|
||||
JetType conditionType = facade.getType(condition, context.replaceScope(scope));
|
||||
@@ -63,30 +63,29 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
JetExpression thenBranch = expression.getThen();
|
||||
|
||||
WritableScopeImpl thenScope = newWritableScopeImpl(context).setDebugName("Then scope");
|
||||
WritableScopeImpl elseScope = newWritableScopeImpl(context).setDebugName("Else scope");
|
||||
DataFlowInfo thenInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, true, thenScope, context);
|
||||
DataFlowInfo elseInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, false, null, context);
|
||||
|
||||
if (elseBranch == null) {
|
||||
if (thenBranch != null) {
|
||||
JetType type = getTypeWithNewScopeAndDataFlowInfo(thenScope, thenBranch, thenInfo, context);
|
||||
JetType type = context.getServices().getBlockReturnedTypeWithWritableScope(thenScope, Collections.singletonList(thenBranch), CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(thenInfo));
|
||||
if (type != null && JetStandardClasses.isNothing(type)) {
|
||||
facade.setResultingDataFlowInfo(elseInfo);
|
||||
// resultScope = elseScope;
|
||||
}
|
||||
return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (thenBranch == null) {
|
||||
JetType type = getTypeWithNewScopeAndDataFlowInfo(context.scope, elseBranch, elseInfo, context);
|
||||
JetType type = context.getServices().getBlockReturnedTypeWithWritableScope(elseScope, Collections.singletonList(elseBranch), CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(elseInfo));
|
||||
if (type != null && JetStandardClasses.isNothing(type)) {
|
||||
facade.setResultingDataFlowInfo(thenInfo);
|
||||
// resultScope = thenScope;
|
||||
}
|
||||
return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
|
||||
}
|
||||
JetType thenType = getTypeWithNewScopeAndDataFlowInfo(thenScope, thenBranch, thenInfo, contextWithExpectedType);
|
||||
JetType elseType = getTypeWithNewScopeAndDataFlowInfo(context.scope, elseBranch, elseInfo, contextWithExpectedType);
|
||||
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));
|
||||
|
||||
JetType result;
|
||||
if (thenType == null) {
|
||||
@@ -120,7 +119,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
if (body != null) {
|
||||
WritableScopeImpl scopeToExtend = newWritableScopeImpl(context).setDebugName("Scope extended in while's condition");
|
||||
DataFlowInfo conditionInfo = condition == null ? context.dataFlowInfo : DataFlowUtils.extractDataFlowInfoFromCondition(condition, true, scopeToExtend, context);
|
||||
getTypeWithNewScopeAndDataFlowInfo(scopeToExtend, body, conditionInfo, context);
|
||||
context.getServices().getBlockReturnedTypeWithWritableScope(scopeToExtend, Collections.singletonList(body), CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(conditionInfo));
|
||||
}
|
||||
if (!containsBreak(expression, context)) {
|
||||
facade.setResultingDataFlowInfo(DataFlowUtils.extractDataFlowInfoFromCondition(condition, false, null, context));
|
||||
@@ -229,8 +228,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
|
||||
JetExpression body = expression.getBody();
|
||||
if (body != null) {
|
||||
ExpressionTypingInternals blockLevelVisitor = ExpressionTypingVisitorDispatcher.createForBlock(loopScope);
|
||||
blockLevelVisitor.getType(body, context.replaceScope(loopScope));
|
||||
context.getServices().getBlockReturnedTypeWithWritableScope(loopScope, Collections.singletonList(body), CoercionStrategy.NO_COERCION, context);
|
||||
}
|
||||
|
||||
return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
|
||||
|
||||
+3
@@ -14,4 +14,7 @@ public interface ExpressionTypingFacade {
|
||||
|
||||
@Nullable
|
||||
JetType getType(@NotNull JetExpression expression, ExpressionTypingContext context);
|
||||
|
||||
@Nullable
|
||||
JetType getTypeForStatement(@NotNull JetExpression expression, ExpressionTypingContext context);
|
||||
}
|
||||
|
||||
+5
-5
@@ -218,13 +218,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.getType(statementExpression, newContext);
|
||||
result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext);
|
||||
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.getType(statementExpression, newContext);
|
||||
result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext);
|
||||
if (mismatch[0]) {
|
||||
temporaryTraceExpectingUnit.commit();
|
||||
}
|
||||
@@ -238,11 +238,11 @@ public class ExpressionTypingServices {
|
||||
}
|
||||
else {
|
||||
newContext = createContext(newContext, trace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType);
|
||||
result = blockLevelVisitor.getType(statementExpression, newContext);
|
||||
result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext);
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = blockLevelVisitor.getType(statementExpression, newContext);
|
||||
result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext);
|
||||
if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT) {
|
||||
boolean mightBeUnit = false;
|
||||
if (statementExpression instanceof JetDeclaration) {
|
||||
@@ -264,7 +264,7 @@ public class ExpressionTypingServices {
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = blockLevelVisitor.getType(statementExpression, newContext);
|
||||
result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext);
|
||||
}
|
||||
|
||||
DataFlowInfo newDataFlowInfo = blockLevelVisitor.getResultingDataFlowInfo();
|
||||
|
||||
+28
-19
@@ -14,6 +14,7 @@ import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.util.lazy.ReenteringLazyValueComputationException;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.ELSE_MISPLACED_IN_WHEN;
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM;
|
||||
|
||||
/**
|
||||
@@ -21,36 +22,33 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.TYPECHECKER_HAS_RUN_INTO
|
||||
*/
|
||||
public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetType, ExpressionTypingContext> implements ExpressionTypingInternals {
|
||||
|
||||
private static Function<ExpressionTypingInternals, BasicExpressionTypingVisitor> BASIC_FACTORY = new Function<ExpressionTypingInternals, BasicExpressionTypingVisitor>() {
|
||||
@Override
|
||||
public BasicExpressionTypingVisitor fun(ExpressionTypingInternals facade) {
|
||||
return new BasicExpressionTypingVisitor(facade);
|
||||
}
|
||||
};
|
||||
private static ExpressionTypingVisitorDispatcher BASIC_DISPATCHER = new ExpressionTypingVisitorDispatcher(null);
|
||||
|
||||
@NotNull
|
||||
public static ExpressionTypingFacade create() {
|
||||
return new ExpressionTypingVisitorDispatcher(BASIC_FACTORY);
|
||||
return BASIC_DISPATCHER;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ExpressionTypingInternals createForBlock(final WritableScope writableScope) {
|
||||
return new ExpressionTypingVisitorDispatcher(new Function<ExpressionTypingInternals, BasicExpressionTypingVisitor>() {
|
||||
@Override
|
||||
public BasicExpressionTypingVisitor fun(ExpressionTypingInternals facade) {
|
||||
return new ExpressionTypingVisitorForStatements(facade, writableScope);
|
||||
}
|
||||
});
|
||||
return new ExpressionTypingVisitorDispatcher(writableScope);
|
||||
}
|
||||
|
||||
private final BasicExpressionTypingVisitor basic;
|
||||
private final ExpressionTypingVisitorForStatements statements;
|
||||
private final ClosureExpressionsTypingVisitor closures = new ClosureExpressionsTypingVisitor(this);
|
||||
private final ControlStructureTypingVisitor controlStructures = new ControlStructureTypingVisitor(this);
|
||||
private final PatternMatchingTypingVisitor patterns = new PatternMatchingTypingVisitor(this);
|
||||
protected DataFlowInfo resultDataFlowInfo;
|
||||
|
||||
private ExpressionTypingVisitorDispatcher(Function<ExpressionTypingInternals, BasicExpressionTypingVisitor> factoryForBasic) {
|
||||
this.basic = factoryForBasic.fun(this);
|
||||
private ExpressionTypingVisitorDispatcher(WritableScope writableScope) {
|
||||
this.basic = new BasicExpressionTypingVisitor(this);
|
||||
if (writableScope != null) {
|
||||
this.statements = new ExpressionTypingVisitorForStatements(this, writableScope, basic);
|
||||
}
|
||||
else {
|
||||
this.statements = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,12 +85,23 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetType, Expre
|
||||
@Override
|
||||
@Nullable
|
||||
public final JetType getType(@NotNull JetExpression expression, ExpressionTypingContext context) {
|
||||
return getType(expression, context, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public final JetType getTypeForStatement(@NotNull JetExpression expression, ExpressionTypingContext context) {
|
||||
return getType(expression, context, statements);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JetType getType(@NotNull JetExpression expression, ExpressionTypingContext context, JetVisitor<JetType, ExpressionTypingContext> visitor) {
|
||||
if (context.trace.get(BindingContext.PROCESSED, expression)) {
|
||||
return context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
|
||||
}
|
||||
JetType result;
|
||||
try {
|
||||
result = expression.accept(this, context);
|
||||
result = expression.accept(visitor, context);
|
||||
// Some recursive definitions (object expressions) must put their types in the cache manually:
|
||||
if (context.trace.get(BindingContext.PROCESSED, expression)) {
|
||||
return context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
|
||||
@@ -115,10 +124,10 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor<JetType, Expre
|
||||
context.trace.record(BindingContext.RESOLUTION_SCOPE, expression, context.scope);
|
||||
}
|
||||
context.trace.record(BindingContext.PROCESSED, expression);
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public JetType visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, ExpressionTypingContext data) {
|
||||
|
||||
+31
-8
@@ -27,12 +27,14 @@ import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.get
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingVisitor {
|
||||
public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisitor {
|
||||
private final WritableScope scope;
|
||||
private final BasicExpressionTypingVisitor basic;
|
||||
|
||||
public ExpressionTypingVisitorForStatements(@NotNull ExpressionTypingInternals facade, @NotNull WritableScope scope) {
|
||||
public ExpressionTypingVisitorForStatements(@NotNull ExpressionTypingInternals facade, @NotNull WritableScope scope, BasicExpressionTypingVisitor basic) {
|
||||
super(facade);
|
||||
this.scope = scope;
|
||||
this.basic = basic;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -126,6 +128,22 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetType visitBinaryExpression(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
|
||||
JetSimpleNameExpression operationSign = expression.getOperationReference();
|
||||
IElementType operationType = operationSign.getReferencedNameElementType();
|
||||
JetType result;
|
||||
if (operationType == JetTokens.EQ) {
|
||||
result = visitAssignment(expression, contextWithExpectedType);
|
||||
}
|
||||
else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
|
||||
result = visitAssignmentOperation(expression, contextWithExpectedType);
|
||||
}
|
||||
else {
|
||||
return facade.getType(expression, contextWithExpectedType);
|
||||
}
|
||||
return DataFlowUtils.checkType(result, expression, contextWithExpectedType);
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -134,7 +152,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
||||
String name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
|
||||
|
||||
TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(context.trace);
|
||||
JetType assignmentOperationType = getTypeForBinaryCall(scope, name, context.replaceBindingTrace(temporaryBindingTrace), expression);
|
||||
JetType assignmentOperationType = basic.getTypeForBinaryCall(scope, name, context.replaceBindingTrace(temporaryBindingTrace), expression);
|
||||
|
||||
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
||||
// If there isn't, we call plus (or like) and then assign
|
||||
@@ -145,7 +163,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
||||
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
||||
resolveArrayAccessToLValue(arrayAccessExpression, expression.getRight(), operationSign, context);
|
||||
}
|
||||
assignmentOperationType = getTypeForBinaryCall(scope, counterpartName, context, expression);
|
||||
assignmentOperationType = basic.getTypeForBinaryCall(scope, counterpartName, context, expression);
|
||||
if (assignmentOperationType != null) {
|
||||
context.trace.record(VARIABLE_REASSIGNMENT, expression);
|
||||
ExpressionTypingUtils.checkWrappingInRef(expression.getLeft(), context);
|
||||
@@ -155,7 +173,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
||||
temporaryBindingTrace.commit();
|
||||
checkReassignment(expression, context, assignmentOperationType, left);
|
||||
}
|
||||
checkLValue(context.trace, expression.getLeft());
|
||||
basic.checkLValue(context.trace, expression.getLeft());
|
||||
return checkAssignmentType(assignmentOperationType, expression, contextWithExpectedType);
|
||||
}
|
||||
|
||||
@@ -176,7 +194,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
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());
|
||||
@@ -184,7 +202,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
||||
if (left instanceof JetArrayAccessExpression) {
|
||||
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
||||
JetType assignmentType = resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference(), context);
|
||||
checkLValue(context.trace, arrayAccessExpression);
|
||||
basic.checkLValue(context.trace, arrayAccessExpression);
|
||||
return checkAssignmentType(assignmentType, expression, contextWithExpectedType);
|
||||
}
|
||||
JetType leftType = facade.getType(expression.getLeft(), context.replaceScope(scope));
|
||||
@@ -192,7 +210,7 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
||||
JetType rightType = facade.getType(right, context.replaceExpectedType(leftType).replaceScope(scope));
|
||||
}
|
||||
if (leftType != null) { //if leftType == null, some another error has been generated
|
||||
checkLValue(context.trace, expression.getLeft());
|
||||
basic.checkLValue(context.trace, expression.getLeft());
|
||||
}
|
||||
if (left instanceof JetSimpleNameExpression) {
|
||||
JetSimpleNameExpression simpleName = (JetSimpleNameExpression) left;
|
||||
@@ -237,6 +255,11 @@ public class ExpressionTypingVisitorForStatements extends BasicExpressionTypingV
|
||||
return setFunctionDescriptor.getReturnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetType visitExpression(JetExpression expression, ExpressionTypingContext context) {
|
||||
return facade.getType(expression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetType visitJetElement(JetElement element, ExpressionTypingContext context) {
|
||||
context.trace.report(UNSUPPORTED.on(element, "in a block"));
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//KT-629 Assignments are parsed as expressions.
|
||||
|
||||
namespace kt629
|
||||
|
||||
class A() {
|
||||
var p = "yeah"
|
||||
fun mod(other : A) : A {
|
||||
return A();
|
||||
}
|
||||
}
|
||||
|
||||
fun box() : Boolean {
|
||||
var c = A()
|
||||
val d = c;
|
||||
c %= A();
|
||||
return (c != d) && (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>c.p = "yeah"<!>)
|
||||
}
|
||||
|
||||
|
||||
fun box2() : Boolean {
|
||||
var <!UNUSED_VARIABLE!>c<!> = A()
|
||||
return (<!ASSIGNMENT_IN_EXPRESSION_CONTEXT!>c.p = "yeah"<!>) && true
|
||||
}
|
||||
@@ -113,7 +113,7 @@ public class JetTypeCheckerTest extends JetLiteFixture {
|
||||
assertType("if (true) 1 else '1'", "Any");
|
||||
|
||||
assertType("if (true) else '1'", "Unit");
|
||||
assertType("if (true) else a = 0", "Unit");
|
||||
assertType("if (true) else { var a = 0; a = 1 }", "Unit");
|
||||
}
|
||||
|
||||
public void testWhen() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user