DataFlowUtils -> DataFlowAnalyzer and make it a component

This commit is contained in:
Pavel V. Talanov
2015-07-22 16:09:23 +03:00
parent 985336d6cc
commit be98c4f96d
13 changed files with 167 additions and 137 deletions
@@ -41,13 +41,14 @@ import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.expressions.DataFlowUtils import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer
import java.util.ArrayList import java.util.ArrayList
public class CallCompleter( public class CallCompleter(
private val argumentTypeResolver: ArgumentTypeResolver, private val argumentTypeResolver: ArgumentTypeResolver,
private val candidateResolver: CandidateResolver, private val candidateResolver: CandidateResolver,
private val symbolUsageValidator: SymbolUsageValidator, private val symbolUsageValidator: SymbolUsageValidator,
private val dataFlowAnalyzer: DataFlowAnalyzer,
private val builtIns: KotlinBuiltIns private val builtIns: KotlinBuiltIns
) { ) {
fun <D : CallableDescriptor> completeCall( fun <D : CallableDescriptor> completeCall(
@@ -260,7 +261,7 @@ public class CallCompleter(
argumentTypeResolver.getCallableReferenceTypeInfo(expression, callableReferenceArgument, context, RESOLVE_FUNCTION_ARGUMENTS) argumentTypeResolver.getCallableReferenceTypeInfo(expression, callableReferenceArgument, context, RESOLVE_FUNCTION_ARGUMENTS)
} }
DataFlowUtils.checkType(updatedType, deparenthesized, context) dataFlowAnalyzer.checkType(updatedType, deparenthesized, context)
} }
private fun completeCallForArgument( private fun completeCallForArgument(
@@ -45,7 +45,10 @@ import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
import org.jetbrains.kotlin.types.ErrorUtils; import org.jetbrains.kotlin.types.ErrorUtils;
import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.TypeUtils; import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.expressions.*; import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
import org.jetbrains.kotlin.types.expressions.JetTypeInfo;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage; import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage;
import javax.inject.Inject; import javax.inject.Inject;
@@ -63,15 +66,18 @@ public class CallExpressionResolver {
private final CallResolver callResolver; private final CallResolver callResolver;
private final ConstantExpressionEvaluator constantExpressionEvaluator; private final ConstantExpressionEvaluator constantExpressionEvaluator;
private final SymbolUsageValidator symbolUsageValidator; private final SymbolUsageValidator symbolUsageValidator;
private final DataFlowAnalyzer dataFlowAnalyzer;
public CallExpressionResolver( public CallExpressionResolver(
@NotNull CallResolver callResolver, @NotNull CallResolver callResolver,
@NotNull ConstantExpressionEvaluator constantExpressionEvaluator, @NotNull ConstantExpressionEvaluator constantExpressionEvaluator,
@NotNull SymbolUsageValidator symbolUsageValidator @NotNull SymbolUsageValidator symbolUsageValidator,
@NotNull DataFlowAnalyzer dataFlowAnalyzer
) { ) {
this.callResolver = callResolver; this.callResolver = callResolver;
this.constantExpressionEvaluator = constantExpressionEvaluator; this.constantExpressionEvaluator = constantExpressionEvaluator;
this.symbolUsageValidator = symbolUsageValidator; this.symbolUsageValidator = symbolUsageValidator;
this.dataFlowAnalyzer = dataFlowAnalyzer;
} }
private ExpressionTypingServices expressionTypingServices; private ExpressionTypingServices expressionTypingServices;
@@ -182,7 +188,7 @@ public class CallExpressionResolver {
) { ) {
JetTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(callExpression, receiver, callOperationNode, context); JetTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(callExpression, receiver, callOperationNode, context);
if (context.contextDependency == INDEPENDENT) { if (context.contextDependency == INDEPENDENT) {
DataFlowUtils.checkType(typeInfo.getType(), callExpression, context); dataFlowAnalyzer.checkType(typeInfo.getType(), callExpression, context);
} }
return typeInfo; return typeInfo;
} }
@@ -379,7 +385,7 @@ public class CallExpressionResolver {
CompileTimeConstant<?> value = constantExpressionEvaluator.evaluateExpression(expression, context.trace, context.expectedType); CompileTimeConstant<?> value = constantExpressionEvaluator.evaluateExpression(expression, context.trace, context.expectedType);
if (value != null && value.getIsPure()) { if (value != null && value.getIsPure()) {
return ExpressionTypingUtils.createCompileTimeConstantTypeInfo(value, expression, context); return dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, expression, context);
} }
JetTypeInfo typeInfo; JetTypeInfo typeInfo;
@@ -424,7 +430,7 @@ public class CallExpressionResolver {
} }
} }
if (context.contextDependency == INDEPENDENT) { if (context.contextDependency == INDEPENDENT) {
DataFlowUtils.checkType(typeInfo.getType(), expression, context); dataFlowAnalyzer.checkType(typeInfo.getType(), expression, context);
} }
return typeInfo; return typeInfo;
} }
@@ -96,7 +96,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
// TODO : type substitutions??? // TODO : type substitutions???
CallExpressionResolver callExpressionResolver = components.callExpressionResolver; CallExpressionResolver callExpressionResolver = components.callExpressionResolver;
JetTypeInfo typeInfo = callExpressionResolver.getSimpleNameExpressionTypeInfo(expression, NO_RECEIVER, null, context); JetTypeInfo typeInfo = callExpressionResolver.getSimpleNameExpressionTypeInfo(expression, NO_RECEIVER, null, context);
return DataFlowUtils.checkType(typeInfo, expression, context); // TODO : Extensions to this return components.dataFlowAnalyzer.checkType(typeInfo, expression, context); // TODO : Extensions to this
} }
@Override @Override
@@ -125,7 +125,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
} }
assert compileTimeConstant != null : "CompileTimeConstant should be evaluated for constant expression or an error should be recorded " + expression.getText(); assert compileTimeConstant != null : "CompileTimeConstant should be evaluated for constant expression or an error should be recorded " + expression.getText();
return createCompileTimeConstantTypeInfo(compileTimeConstant, expression, context); return components.dataFlowAnalyzer.createCompileTimeConstantTypeInfo(compileTimeConstant, expression, context);
} }
@NotNull @NotNull
@@ -175,7 +175,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType.replaceExpectedType(targetType)); JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType.replaceExpectedType(targetType));
checkBinaryWithTypeRHS(expression, context, targetType, typeInfo.getType()); checkBinaryWithTypeRHS(expression, context, targetType, typeInfo.getType());
return DataFlowUtils.checkType(typeInfo.replaceType(targetType), expression, context); return components.dataFlowAnalyzer.checkType(typeInfo.replaceType(targetType), expression, context);
} }
JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType); JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType);
@@ -193,7 +193,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
} }
JetType result = operationType == AS_SAFE ? TypeUtils.makeNullable(targetType) : targetType; JetType result = operationType == AS_SAFE ? TypeUtils.makeNullable(targetType) : targetType;
return DataFlowUtils.checkType(typeInfo.replaceType(result), expression, context); return components.dataFlowAnalyzer.checkType(typeInfo.replaceType(result), expression, context);
} }
private void checkBinaryWithTypeRHS( private void checkBinaryWithTypeRHS(
@@ -241,7 +241,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(USELESS_CAST.on(expression)); context.trace.report(USELESS_CAST.on(expression));
return; return;
} }
Collection<JetType> possibleTypes = DataFlowUtils.getAllPossibleTypes( Collection<JetType> possibleTypes = components.dataFlowAnalyzer.getAllPossibleTypes(
expression.getLeft(), context.dataFlowInfo, actualType, context); expression.getLeft(), context.dataFlowInfo, actualType, context);
boolean checkExactType = checkExactTypeForUselessCast(expression); boolean checkExactType = checkExactTypeForUselessCast(expression);
@@ -295,7 +295,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.recordType(expression.getInstanceReference(), result); context.trace.recordType(expression.getInstanceReference(), result);
break; break;
} }
return TypeInfoFactoryPackage.createCheckedTypeInfo(result, context, expression); return components.dataFlowAnalyzer.createCheckedTypeInfo(result, context, expression);
} }
@Override @Override
@@ -319,7 +319,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (result != null) { if (result != null) {
context.trace.recordType(expression.getInstanceReference(), result); context.trace.recordType(expression.getInstanceReference(), result);
} }
return TypeInfoFactoryPackage.createCheckedTypeInfo(result, context, expression); return components.dataFlowAnalyzer.createCheckedTypeInfo(result, context, expression);
} }
throw new IllegalStateException("Unknown code: " + resolutionResult.getCode()); throw new IllegalStateException("Unknown code: " + resolutionResult.getCode());
} }
@@ -509,7 +509,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
public JetTypeInfo visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression, ExpressionTypingContext c) { public JetTypeInfo visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression, ExpressionTypingContext c) {
JetType type = resolveClassLiteral(expression, c); JetType type = resolveClassLiteral(expression, c);
if (type != null && !type.isError()) { if (type != null && !type.isError()) {
return TypeInfoFactoryPackage.createCheckedTypeInfo( return components.dataFlowAnalyzer.createCheckedTypeInfo(
components.reflectionTypes.getKClassType(Annotations.EMPTY, type), c, expression components.reflectionTypes.getKClassType(Annotations.EMPTY, type), c, expression
); );
} }
@@ -604,11 +604,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (callableReference.getReferencedName().isEmpty()) { if (callableReference.getReferencedName().isEmpty()) {
c.trace.report(UNRESOLVED_REFERENCE.on(callableReference, callableReference)); c.trace.report(UNRESOLVED_REFERENCE.on(callableReference, callableReference));
JetType errorType = ErrorUtils.createErrorType("Empty callable reference"); JetType errorType = ErrorUtils.createErrorType("Empty callable reference");
return TypeInfoFactoryPackage.createCheckedTypeInfo(errorType, c, expression); return components.dataFlowAnalyzer.createCheckedTypeInfo(errorType, c, expression);
} }
JetType result = getCallableReferenceType(expression, receiverType, c); JetType result = getCallableReferenceType(expression, receiverType, c);
return TypeInfoFactoryPackage.createCheckedTypeInfo(result, c, expression); return components.dataFlowAnalyzer.createCheckedTypeInfo(result, c, expression);
} }
@Override @Override
@@ -651,9 +651,9 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
} }
} }
// Breaks are not possible inside constructor arguments, so jumpPossible or jumpFlowInfo are not necessary here // Breaks are not possible inside constructor arguments, so jumpPossible or jumpFlowInfo are not necessary here
JetTypeInfo resultTypeInfo = DataFlowUtils.checkType(TypeInfoFactoryPackage.createTypeInfo(result[0], resultFlowInfo), JetTypeInfo resultTypeInfo = components.dataFlowAnalyzer.checkType(TypeInfoFactoryPackage.createTypeInfo(result[0], resultFlowInfo),
expression, expression,
context); context);
// We have to record it here, // We have to record it here,
// otherwise ExpressionTypingVisitorDispatcher records wrong information // otherwise ExpressionTypingVisitorDispatcher records wrong information
context.trace.record(EXPRESSION_TYPE_INFO, expression, resultTypeInfo); context.trace.record(EXPRESSION_TYPE_INFO, expression, resultTypeInfo);
@@ -781,12 +781,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
expression, contextWithExpectedType.trace, contextWithExpectedType.expectedType expression, contextWithExpectedType.trace, contextWithExpectedType.expectedType
); );
if (value != null) { if (value != null) {
return createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType); return components.dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType);
} }
return DataFlowUtils.checkType(typeInfo.replaceType(result), return components.dataFlowAnalyzer.checkType(typeInfo.replaceType(result),
expression, expression,
contextWithExpectedType.replaceDataFlowInfo(typeInfo.getDataFlowInfo())); contextWithExpectedType.replaceDataFlowInfo(typeInfo.getDataFlowInfo()));
} }
private JetTypeInfo visitExclExclExpression(@NotNull JetUnaryExpression expression, @NotNull ExpressionTypingContext context) { private JetTypeInfo visitExclExclExpression(@NotNull JetUnaryExpression expression, @NotNull ExpressionTypingContext context) {
@@ -820,7 +820,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
} }
// The call to checkType() is only needed here to execute additionalTypeCheckers, hence the NO_EXPECTED_TYPE // The call to checkType() is only needed here to execute additionalTypeCheckers, hence the NO_EXPECTED_TYPE
return DataFlowUtils.checkType(baseTypeInfo.replaceType(resultingType), expression, context.replaceExpectedType(NO_EXPECTED_TYPE)); return components.dataFlowAnalyzer.checkType(baseTypeInfo.replaceType(resultingType), expression, context.replaceExpectedType(NO_EXPECTED_TYPE));
} }
@Override @Override
@@ -977,9 +977,9 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
expression, contextWithExpectedType.trace, contextWithExpectedType.expectedType expression, contextWithExpectedType.trace, contextWithExpectedType.expectedType
); );
if (value != null) { if (value != null) {
return createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType); return components.dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType);
} }
return DataFlowUtils.checkType(result, expression, contextWithExpectedType); return components.dataFlowAnalyzer.checkType(result, expression, contextWithExpectedType);
} }
private JetTypeInfo visitEquality( private JetTypeInfo visitEquality(
@@ -1092,7 +1092,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
WritableScopeImpl leftScope = newWritableScopeImpl(context, "Left scope of && or ||"); WritableScopeImpl leftScope = newWritableScopeImpl(context, "Left scope of && or ||");
// TODO: This gets computed twice: here and in extractDataFlowInfoFromCondition() for the whole condition // TODO: This gets computed twice: here and in extractDataFlowInfoFromCondition() for the whole condition
boolean isAnd = operationType == JetTokens.ANDAND; boolean isAnd = operationType == JetTokens.ANDAND;
DataFlowInfo flowInfoLeft = DataFlowUtils.extractDataFlowInfoFromCondition(left, isAnd, context).and(dataFlowInfo); DataFlowInfo flowInfoLeft = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(left, isAnd, context).and(dataFlowInfo);
WritableScopeImpl rightScope = isAnd ? leftScope : newWritableScopeImpl(context, "Right scope of && or ||"); WritableScopeImpl rightScope = isAnd ? leftScope : newWritableScopeImpl(context, "Right scope of && or ||");
ExpressionTypingContext contextForRightExpr = ExpressionTypingContext contextForRightExpr =
@@ -1149,10 +1149,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
} }
// If break or continue was possible, take condition check info as the jump info // If break or continue was possible, take condition check info as the jump info
return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkType(type, expression, contextWithExpectedType), return TypeInfoFactoryPackage.createTypeInfo(components.dataFlowAnalyzer.checkType(type, expression, contextWithExpectedType),
dataFlowInfo, dataFlowInfo,
loopBreakContinuePossible, loopBreakContinuePossible,
context.dataFlowInfo); context.dataFlowInfo);
} }
@NotNull @NotNull
@@ -1265,7 +1265,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@Override @Override
public JetTypeInfo visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, ExpressionTypingContext context) { public JetTypeInfo visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, ExpressionTypingContext context) {
return DataFlowUtils.checkType(resolveArrayAccessGetMethod(expression, context), expression, context); return components.dataFlowAnalyzer.checkType(resolveArrayAccessGetMethod(expression, context), expression, context);
} }
@NotNull @NotNull
@@ -1345,9 +1345,9 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
entry.accept(visitor); entry.accept(visitor);
} }
components.constantExpressionEvaluator.evaluateExpression(expression, context.trace, contextWithExpectedType.expectedType); components.constantExpressionEvaluator.evaluateExpression(expression, context.trace, contextWithExpectedType.expectedType);
return DataFlowUtils.checkType(visitor.typeInfo.replaceType(components.builtIns.getStringType()), return components.dataFlowAnalyzer.checkType(visitor.typeInfo.replaceType(components.builtIns.getStringType()),
expression, expression,
contextWithExpectedType); contextWithExpectedType);
} }
@Override @Override
@@ -60,9 +60,14 @@ public class ControlStructureTypingUtils {
private static final Logger LOG = Logger.getInstance(ControlStructureTypingUtils.class); private static final Logger LOG = Logger.getInstance(ControlStructureTypingUtils.class);
private final CallResolver callResolver; private final CallResolver callResolver;
private final DataFlowAnalyzer dataFlowAnalyzer;
public ControlStructureTypingUtils(@NotNull CallResolver callResolver) { public ControlStructureTypingUtils(
@NotNull CallResolver callResolver,
@NotNull DataFlowAnalyzer dataFlowAnalyzer
) {
this.callResolver = callResolver; this.callResolver = callResolver;
this.dataFlowAnalyzer = dataFlowAnalyzer;
} }
/*package*/ ResolvedCall<FunctionDescriptor> resolveSpecialConstructionAsCall( /*package*/ ResolvedCall<FunctionDescriptor> resolveSpecialConstructionAsCall(
@@ -245,7 +250,7 @@ public class ControlStructureTypingUtils {
} }
@NotNull @NotNull
/*package*/ static TracingStrategy createTracingForSpecialConstruction( /*package*/ TracingStrategy createTracingForSpecialConstruction(
final @NotNull Call call, final @NotNull Call call,
@NotNull String constructionName, @NotNull String constructionName,
final @NotNull ExpressionTypingContext context final @NotNull ExpressionTypingContext context
@@ -272,7 +277,7 @@ public class ControlStructureTypingUtils {
if (typeInfo == null) return false; if (typeInfo == null) return false;
Ref<Boolean> hasError = Ref.create(); Ref<Boolean> hasError = Ref.create();
DataFlowUtils.checkType( dataFlowAnalyzer.checkType(
typeInfo.getType(), typeInfo.getType(),
expression, expression,
context context
@@ -26,7 +26,10 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.ModifiersChecker;
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments; import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
@@ -99,8 +102,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
WritableScopeImpl thenScope = newWritableScopeImpl(context, "Then scope"); WritableScopeImpl thenScope = newWritableScopeImpl(context, "Then scope");
WritableScopeImpl elseScope = newWritableScopeImpl(context, "Else scope"); WritableScopeImpl elseScope = newWritableScopeImpl(context, "Else scope");
DataFlowInfo thenInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, true, context).and(conditionDataFlowInfo); DataFlowInfo thenInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(condition, true, context).and(conditionDataFlowInfo);
DataFlowInfo elseInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, false, context).and(conditionDataFlowInfo); DataFlowInfo elseInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(condition, false, context).and(conditionDataFlowInfo);
if (elseBranch == null) { if (elseBranch == null) {
if (thenBranch != null) { if (thenBranch != null) {
@@ -111,7 +114,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
? result.replaceJumpOutPossible(true).replaceJumpFlowInfo(conditionDataFlowInfo) ? result.replaceJumpOutPossible(true).replaceJumpFlowInfo(conditionDataFlowInfo)
: result; : result;
} }
return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkImplicitCast( return TypeInfoFactoryPackage.createTypeInfo(components.dataFlowAnalyzer.checkImplicitCast(
components.builtIns.getUnitType(), ifExpression, components.builtIns.getUnitType(), ifExpression,
contextWithExpectedType, isStatement contextWithExpectedType, isStatement
), ),
@@ -165,7 +168,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
JetType resultType = resolvedCall.getResultingDescriptor().getReturnType(); JetType resultType = resolvedCall.getResultingDescriptor().getReturnType();
// If break or continue was possible, take condition check info as the jump info // If break or continue was possible, take condition check info as the jump info
return TypeInfoFactoryPackage return TypeInfoFactoryPackage
.createTypeInfo(DataFlowUtils.checkImplicitCast(resultType, ifExpression, contextWithExpectedType, isStatement), .createTypeInfo(components.dataFlowAnalyzer.checkImplicitCast(resultType, ifExpression, contextWithExpectedType, isStatement),
resultDataFlowInfo, loopBreakContinuePossible, conditionDataFlowInfo); resultDataFlowInfo, loopBreakContinuePossible, conditionDataFlowInfo);
} }
@@ -190,12 +193,16 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
} else { } else {
dataFlowInfo = typeInfo.getDataFlowInfo().or(otherInfo); dataFlowInfo = typeInfo.getDataFlowInfo().or(otherInfo);
} }
return DataFlowUtils.checkImplicitCast(DataFlowUtils.checkType(typeInfo.replaceType(components.builtIns.getUnitType()), return components.dataFlowAnalyzer.checkImplicitCast(
ifExpression, components.dataFlowAnalyzer.checkType(
context), typeInfo.replaceType(components.builtIns.getUnitType()),
ifExpression, ifExpression,
context, context
isStatement).replaceDataFlowInfo(dataFlowInfo); ),
ifExpression,
context,
isStatement
).replaceDataFlowInfo(dataFlowInfo);
} }
@Override @Override
@@ -204,7 +211,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
} }
public JetTypeInfo visitWhileExpression(JetWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { public JetTypeInfo visitWhileExpression(JetWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
if (!isStatement) return DataFlowUtils.illegalStatementType(expression, contextWithExpectedType, facade); if (!isStatement) return components.dataFlowAnalyzer.illegalStatementType(expression, contextWithExpectedType, facade);
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency( ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(
INDEPENDENT); INDEPENDENT);
@@ -220,7 +227,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
JetExpression body = expression.getBody(); JetExpression body = expression.getBody();
JetTypeInfo bodyTypeInfo; JetTypeInfo bodyTypeInfo;
DataFlowInfo conditionInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, true, context).and(dataFlowInfo); DataFlowInfo conditionInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(condition, true, context).and(dataFlowInfo);
if (body != null) { if (body != null) {
WritableScopeImpl scopeToExtend = newWritableScopeImpl(context, "Scope extended in while's condition"); WritableScopeImpl scopeToExtend = newWritableScopeImpl(context, "Scope extended in while's condition");
bodyTypeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope( bodyTypeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(
@@ -233,7 +240,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
// Condition is false at this point only if there is no jumps outside // Condition is false at this point only if there is no jumps outside
if (!containsJumpOutOfLoop(expression, context)) { if (!containsJumpOutOfLoop(expression, context)) {
dataFlowInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, false, context).and(dataFlowInfo); dataFlowInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(condition, false, context).and(dataFlowInfo);
} }
// Special case: while (true) // Special case: while (true)
@@ -245,7 +252,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
// but without affecting changing variables // but without affecting changing variables
dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo())); dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo()));
} }
return DataFlowUtils return components.dataFlowAnalyzer
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType) .checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
.replaceDataFlowInfo(dataFlowInfo); .replaceDataFlowInfo(dataFlowInfo);
} }
@@ -295,7 +302,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
} }
public JetTypeInfo visitDoWhileExpression(JetDoWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { public JetTypeInfo visitDoWhileExpression(JetDoWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
if (!isStatement) return DataFlowUtils.illegalStatementType(expression, contextWithExpectedType, facade); if (!isStatement) return components.dataFlowAnalyzer.illegalStatementType(expression, contextWithExpectedType, facade);
ExpressionTypingContext context = ExpressionTypingContext context =
contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
@@ -335,7 +342,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
DataFlowInfo dataFlowInfo; DataFlowInfo dataFlowInfo;
// Without jumps out, condition is entered and false, with jumps out, we know nothing about it // Without jumps out, condition is entered and false, with jumps out, we know nothing about it
if (!containsJumpOutOfLoop(expression, context)) { if (!containsJumpOutOfLoop(expression, context)) {
dataFlowInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, false, context).and(conditionDataFlowInfo); dataFlowInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(condition, false, context).and(conditionDataFlowInfo);
} }
else { else {
dataFlowInfo = context.dataFlowInfo; dataFlowInfo = context.dataFlowInfo;
@@ -350,7 +357,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
// but without affecting changing variables // but without affecting changing variables
dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo())); dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo()));
} }
return DataFlowUtils return components.dataFlowAnalyzer
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType) .checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
.replaceDataFlowInfo(dataFlowInfo); .replaceDataFlowInfo(dataFlowInfo);
} }
@@ -361,7 +368,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
} }
public JetTypeInfo visitForExpression(JetForExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { public JetTypeInfo visitForExpression(JetForExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
if (!isStatement) return DataFlowUtils.illegalStatementType(expression, contextWithExpectedType, facade); if (!isStatement) return components.dataFlowAnalyzer.illegalStatementType(expression, contextWithExpectedType, facade);
ExpressionTypingContext context = ExpressionTypingContext context =
contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
@@ -413,7 +420,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
bodyTypeInfo = loopRangeInfo; bodyTypeInfo = loopRangeInfo;
} }
return DataFlowUtils return components.dataFlowAnalyzer
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType) .checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
.replaceDataFlowInfo(loopRangeInfo.getDataFlowInfo()); .replaceDataFlowInfo(loopRangeInfo.getDataFlowInfo());
} }
@@ -472,7 +479,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
VariableDescriptor variableDescriptor = components.descriptorResolver.resolveLocalVariableDescriptor( VariableDescriptor variableDescriptor = components.descriptorResolver.resolveLocalVariableDescriptor(
context.scope, catchParameter, context.trace); context.scope, catchParameter, context.trace);
JetType throwableType = components.builtIns.getThrowable().getDefaultType(); JetType throwableType = components.builtIns.getThrowable().getDefaultType();
DataFlowUtils.checkType(variableDescriptor.getType(), catchParameter, context.replaceExpectedType(throwableType)); components.dataFlowAnalyzer.checkType(variableDescriptor.getType(), catchParameter, context.replaceExpectedType(throwableType));
if (catchBody != null) { if (catchBody != null) {
WritableScope catchScope = newWritableScopeImpl(context, "Catch scope"); WritableScope catchScope = newWritableScopeImpl(context, "Catch scope");
catchScope.addVariableDescriptor(variableDescriptor); catchScope.addVariableDescriptor(variableDescriptor);
@@ -510,7 +517,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
facade.getTypeInfo(thrownExpression, context facade.getTypeInfo(thrownExpression, context
.replaceExpectedType(throwableType).replaceScope(context.scope).replaceContextDependency(INDEPENDENT)); .replaceExpectedType(throwableType).replaceScope(context.scope).replaceContextDependency(INDEPENDENT));
} }
return TypeInfoFactoryPackage.createCheckedTypeInfo(components.builtIns.getNothingType(), context, expression); return components.dataFlowAnalyzer.createCheckedTypeInfo(components.builtIns.getNothingType(), context, expression);
} }
@Override @Override
@@ -583,7 +590,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(RETURN_TYPE_MISMATCH.on(expression, expectedType)); context.trace.report(RETURN_TYPE_MISMATCH.on(expression, expectedType));
} }
} }
return TypeInfoFactoryPackage.createCheckedTypeInfo(resultType, context, expression); return components.dataFlowAnalyzer.createCheckedTypeInfo(resultType, context, expression);
} }
private static boolean isClassInitializer(@NotNull Pair<FunctionDescriptor, PsiElement> containingFunInfo) { private static boolean isClassInitializer(@NotNull Pair<FunctionDescriptor, PsiElement> containingFunInfo) {
@@ -594,14 +601,14 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
@Override @Override
public JetTypeInfo visitBreakExpression(@NotNull JetBreakExpression expression, ExpressionTypingContext context) { public JetTypeInfo visitBreakExpression(@NotNull JetBreakExpression expression, ExpressionTypingContext context) {
LabelResolver.INSTANCE.resolveControlLabel(expression, context); LabelResolver.INSTANCE.resolveControlLabel(expression, context);
return TypeInfoFactoryPackage.createCheckedTypeInfo(components.builtIns.getNothingType(), context, expression). return components.dataFlowAnalyzer.createCheckedTypeInfo(components.builtIns.getNothingType(), context, expression).
replaceJumpOutPossible(true); replaceJumpOutPossible(true);
} }
@Override @Override
public JetTypeInfo visitContinueExpression(@NotNull JetContinueExpression expression, ExpressionTypingContext context) { public JetTypeInfo visitContinueExpression(@NotNull JetContinueExpression expression, ExpressionTypingContext context) {
LabelResolver.INSTANCE.resolveControlLabel(expression, context); LabelResolver.INSTANCE.resolveControlLabel(expression, context);
return TypeInfoFactoryPackage.createCheckedTypeInfo(components.builtIns.getNothingType(), context, expression). return components.dataFlowAnalyzer.createCheckedTypeInfo(components.builtIns.getNothingType(), context, expression).
replaceJumpOutPossible(true); replaceJumpOutPossible(true);
} }
@@ -26,13 +26,13 @@ import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext; import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils; import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils;
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstantChecker; import org.jetbrains.kotlin.resolve.constants.*;
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.TypeUtils; import org.jetbrains.kotlin.types.TypeUtils;
@@ -46,12 +46,10 @@ import static org.jetbrains.kotlin.diagnostics.Errors.*;
import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT; import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
import static org.jetbrains.kotlin.types.TypeUtils.*; import static org.jetbrains.kotlin.types.TypeUtils.*;
public class DataFlowUtils { public class DataFlowAnalyzer {
private DataFlowUtils() {
}
@NotNull @NotNull
public static DataFlowInfo extractDataFlowInfoFromCondition( public DataFlowInfo extractDataFlowInfoFromCondition(
@Nullable JetExpression condition, @Nullable JetExpression condition,
final boolean conditionValue, final boolean conditionValue,
final ExpressionTypingContext context final ExpressionTypingContext context
@@ -143,17 +141,17 @@ public class DataFlowUtils {
} }
@Nullable @Nullable
public static JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ResolutionContext context) { public JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ResolutionContext context) {
return checkType(expressionType, expression, context, null); return checkType(expressionType, expression, context, null);
} }
@NotNull @NotNull
public static JetTypeInfo checkType(@NotNull JetTypeInfo typeInfo, @NotNull JetExpression expression, @NotNull ResolutionContext context) { public JetTypeInfo checkType(@NotNull JetTypeInfo typeInfo, @NotNull JetExpression expression, @NotNull ResolutionContext context) {
return typeInfo.replaceType(checkType(typeInfo.getType(), expression, context)); return typeInfo.replaceType(checkType(typeInfo.getType(), expression, context));
} }
@Nullable @Nullable
public static JetType checkType( public JetType checkType(
@Nullable JetType expressionType, @Nullable JetType expressionType,
@NotNull JetExpression expressionToCheck, @NotNull JetExpression expressionToCheck,
@NotNull ResolutionContext c, @NotNull ResolutionContext c,
@@ -195,7 +193,7 @@ public class DataFlowUtils {
} }
@Nullable @Nullable
public static JetType checkPossibleCast( public JetType checkPossibleCast(
@NotNull JetType expressionType, @NotNull JetType expressionType,
@NotNull JetExpression expression, @NotNull JetExpression expression,
@NotNull ResolutionContext c @NotNull ResolutionContext c
@@ -212,7 +210,7 @@ public class DataFlowUtils {
return null; return null;
} }
public static void recordExpectedType(@NotNull BindingTrace trace, @NotNull JetExpression expression, @NotNull JetType expectedType) { public void recordExpectedType(@NotNull BindingTrace trace, @NotNull JetExpression expression, @NotNull JetType expectedType) {
if (expectedType != NO_EXPECTED_TYPE) { if (expectedType != NO_EXPECTED_TYPE) {
JetType normalizeExpectedType = expectedType == UNIT_EXPECTED_TYPE ? KotlinBuiltIns.getInstance().getUnitType() : expectedType; JetType normalizeExpectedType = expectedType == UNIT_EXPECTED_TYPE ? KotlinBuiltIns.getInstance().getUnitType() : expectedType;
trace.record(BindingContext.EXPECTED_EXPRESSION_TYPE, expression, normalizeExpectedType); trace.record(BindingContext.EXPECTED_EXPRESSION_TYPE, expression, normalizeExpectedType);
@@ -220,7 +218,7 @@ public class DataFlowUtils {
} }
@Nullable @Nullable
public static JetType checkStatementType(@NotNull JetExpression expression, @NotNull ResolutionContext context) { public JetType checkStatementType(@NotNull JetExpression expression, @NotNull ResolutionContext context) {
if (!noExpectedType(context.expectedType) && !KotlinBuiltIns.isUnit(context.expectedType) && !context.expectedType.isError()) { if (!noExpectedType(context.expectedType) && !KotlinBuiltIns.isUnit(context.expectedType) && !context.expectedType.isError()) {
context.trace.report(EXPECTED_TYPE_MISMATCH.on(expression, context.expectedType)); context.trace.report(EXPECTED_TYPE_MISMATCH.on(expression, context.expectedType));
return null; return null;
@@ -229,7 +227,7 @@ public class DataFlowUtils {
} }
@Nullable @Nullable
public static JetType checkImplicitCast(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ResolutionContext context, boolean isStatement) { public JetType checkImplicitCast(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ResolutionContext context, boolean isStatement) {
if (expressionType != null && context.expectedType == NO_EXPECTED_TYPE && context.contextDependency == INDEPENDENT && !isStatement if (expressionType != null && context.expectedType == NO_EXPECTED_TYPE && context.contextDependency == INDEPENDENT && !isStatement
&& (KotlinBuiltIns.isUnit(expressionType) || KotlinBuiltIns.isAnyOrNullableAny(expressionType)) && (KotlinBuiltIns.isUnit(expressionType) || KotlinBuiltIns.isAnyOrNullableAny(expressionType))
&& !TypesPackage.isDynamic(expressionType)) { && !TypesPackage.isDynamic(expressionType)) {
@@ -239,12 +237,12 @@ public class DataFlowUtils {
} }
@NotNull @NotNull
public static JetTypeInfo checkImplicitCast(@NotNull JetTypeInfo typeInfo, @NotNull JetExpression expression, @NotNull ResolutionContext context, boolean isStatement) { public JetTypeInfo checkImplicitCast(@NotNull JetTypeInfo typeInfo, @NotNull JetExpression expression, @NotNull ResolutionContext context, boolean isStatement) {
return typeInfo.replaceType(checkImplicitCast(typeInfo.getType(), expression, context, isStatement)); return typeInfo.replaceType(checkImplicitCast(typeInfo.getType(), expression, context, isStatement));
} }
@NotNull @NotNull
public static JetTypeInfo illegalStatementType(@NotNull JetExpression expression, @NotNull ExpressionTypingContext context, @NotNull ExpressionTypingInternals facade) { public JetTypeInfo illegalStatementType(@NotNull JetExpression expression, @NotNull ExpressionTypingContext context, @NotNull ExpressionTypingInternals facade) {
facade.checkStatementType( facade.checkStatementType(
expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT)); expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT));
context.trace.report(EXPRESSION_EXPECTED.on(expression, expression)); context.trace.report(EXPRESSION_EXPECTED.on(expression, expression));
@@ -252,7 +250,7 @@ public class DataFlowUtils {
} }
@NotNull @NotNull
public static Collection<JetType> getAllPossibleTypes( public Collection<JetType> getAllPossibleTypes(
@NotNull JetExpression expression, @NotNull JetExpression expression,
@NotNull DataFlowInfo dataFlowInfo, @NotNull DataFlowInfo dataFlowInfo,
@NotNull JetType type, @NotNull JetType type,
@@ -265,4 +263,37 @@ public class DataFlowUtils {
} }
return possibleTypes; return possibleTypes;
} }
@NotNull
public JetTypeInfo createCheckedTypeInfo(
@Nullable JetType type,
@NotNull ResolutionContext<?> context,
@NotNull JetExpression expression
) {
return checkType(TypeInfoFactoryPackage.createTypeInfo(type, context), expression, context);
}
@NotNull
public JetTypeInfo createCompileTimeConstantTypeInfo(
@NotNull CompileTimeConstant<?> value,
@NotNull JetExpression expression,
@NotNull ExpressionTypingContext context
) {
JetType expressionType;
if (value instanceof IntegerValueTypeConstant) {
IntegerValueTypeConstant integerValueTypeConstant = (IntegerValueTypeConstant) value;
if (context.contextDependency == INDEPENDENT) {
expressionType = integerValueTypeConstant.getType(context.expectedType);
ArgumentTypeResolver.updateNumberType(expressionType, expression, context.statementFilter, context.trace);
}
else {
expressionType = integerValueTypeConstant.getUnknownIntegerType();
}
}
else {
expressionType = ((TypedCompileTimeConstant<?>) value).getType();
}
return createCheckedTypeInfo(expressionType, context, expression);
}
} }
@@ -52,6 +52,7 @@ public class ExpressionTypingComponents {
/*package*/ MultiDeclarationResolver multiDeclarationResolver; /*package*/ MultiDeclarationResolver multiDeclarationResolver;
/*package*/ ConstantExpressionEvaluator constantExpressionEvaluator; /*package*/ ConstantExpressionEvaluator constantExpressionEvaluator;
/*package*/ ModifiersChecker modifiersChecker; /*package*/ ModifiersChecker modifiersChecker;
/*package*/ DataFlowAnalyzer dataFlowAnalyzer;
@Inject @Inject
public void setGlobalContext(@NotNull GlobalContext globalContext) { public void setGlobalContext(@NotNull GlobalContext globalContext) {
@@ -164,7 +165,12 @@ public class ExpressionTypingComponents {
} }
@Inject @Inject
public void setModifiersChecker(ModifiersChecker modifiersChecker) { public void setModifiersChecker(@NotNull ModifiersChecker modifiersChecker) {
this.modifiersChecker = modifiersChecker; this.modifiersChecker = modifiersChecker;
} }
@Inject
public void setDataFlowAnalyzer(@NotNull DataFlowAnalyzer dataFlowAnalyzer) {
this.dataFlowAnalyzer = dataFlowAnalyzer;
}
} }
@@ -21,18 +21,14 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.analyzer.AnalyzerPackage; import org.jetbrains.kotlin.analyzer.AnalyzerPackage;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor; import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.ScriptDescriptor; import org.jetbrains.kotlin.descriptors.ScriptDescriptor;
import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.callableReferences.CallableReferencesPackage;
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode;
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency; import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext; import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.scopes.JetScope; import org.jetbrains.kotlin.resolve.scopes.JetScope;
import org.jetbrains.kotlin.resolve.scopes.WritableScope; import org.jetbrains.kotlin.resolve.scopes.WritableScope;
@@ -174,7 +170,8 @@ public class ExpressionTypingServices {
JetTypeInfo r; JetTypeInfo r;
if (block.isEmpty()) { if (block.isEmpty()) {
r = TypeInfoFactoryPackage.createCheckedTypeInfo(expressionTypingComponents.builtIns.getUnitType(), context, expression); r = expressionTypingComponents.dataFlowAnalyzer
.createCheckedTypeInfo(expressionTypingComponents.builtIns.getUnitType(), context, expression);
} }
else { else {
r = getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression, r = getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression,
@@ -242,27 +242,4 @@ public class ExpressionTypingUtils {
private ExpressionTypingUtils() { private ExpressionTypingUtils() {
} }
@NotNull
public static JetTypeInfo createCompileTimeConstantTypeInfo(
@NotNull CompileTimeConstant<?> value,
@NotNull JetExpression expression,
@NotNull ExpressionTypingContext context
) {
JetType expressionType;
if (value instanceof IntegerValueTypeConstant) {
IntegerValueTypeConstant integerValueTypeConstant = (IntegerValueTypeConstant) value;
if (context.contextDependency == INDEPENDENT) {
expressionType = integerValueTypeConstant.getType(context.expectedType);
ArgumentTypeResolver.updateNumberType(expressionType, expression, context.statementFilter, context.trace);
}
else {
expressionType = integerValueTypeConstant.getUnknownIntegerType();
}
}
else {
expressionType = ((TypedCompileTimeConstant<?>) value).getType();
}
return TypeInfoFactoryPackage.createCheckedTypeInfo(expressionType, context, expression);
}
} }
@@ -29,7 +29,9 @@ import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.AnnotationResolver;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache; import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
@@ -80,7 +82,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
} }
@Nullable @Nullable
private static JetType checkAssignmentType( private JetType checkAssignmentType(
@Nullable JetType assignmentType, @Nullable JetType assignmentType,
@NotNull JetBinaryExpression expression, @NotNull JetBinaryExpression expression,
@NotNull ExpressionTypingContext context @NotNull ExpressionTypingContext context
@@ -90,7 +92,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
context.trace.report(Errors.ASSIGNMENT_TYPE_MISMATCH.on(expression, context.expectedType)); context.trace.report(Errors.ASSIGNMENT_TYPE_MISMATCH.on(expression, context.expectedType));
return null; return null;
} }
return DataFlowUtils.checkStatementType(expression, context); return components.dataFlowAnalyzer.checkStatementType(expression, context);
} }
@Override @Override
@@ -99,7 +101,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT),
scope.getContainingDeclaration(), scope.getContainingDeclaration(),
declaration); declaration);
return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkStatementType(declaration, context), context); return TypeInfoFactoryPackage.createTypeInfo(components.dataFlowAnalyzer.checkStatementType(declaration, context), context);
} }
@Override @Override
@@ -163,7 +165,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
scope.addVariableDescriptor(propertyDescriptor); scope.addVariableDescriptor(propertyDescriptor);
components.modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(property, propertyDescriptor); components.modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(property, propertyDescriptor);
return typeInfo.replaceType(DataFlowUtils.checkStatementType(property, context)); return typeInfo.replaceType(components.dataFlowAnalyzer.checkStatementType(property, context));
} }
@Override @Override
@@ -183,7 +185,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
return TypeInfoFactoryPackage.noTypeInfo(context); return TypeInfoFactoryPackage.noTypeInfo(context);
} }
components.multiDeclarationResolver.defineLocalVariablesFromMultiDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context); components.multiDeclarationResolver.defineLocalVariablesFromMultiDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context);
return typeInfo.replaceType(DataFlowUtils.checkStatementType(multiDeclaration, context)); return typeInfo.replaceType(components.dataFlowAnalyzer.checkStatementType(multiDeclaration, context));
} }
@Override @Override
@@ -197,7 +199,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT),
scope.getContainingDeclaration(), scope.getContainingDeclaration(),
klass); klass);
return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkStatementType(klass, context), context); return TypeInfoFactoryPackage.createTypeInfo(components.dataFlowAnalyzer.checkStatementType(klass, context), context);
} }
@Override @Override
@@ -208,7 +210,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
@Override @Override
public JetTypeInfo visitDeclaration(@NotNull JetDeclaration dcl, ExpressionTypingContext context) { public JetTypeInfo visitDeclaration(@NotNull JetDeclaration dcl, ExpressionTypingContext context) {
return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkStatementType(dcl, context), context); return TypeInfoFactoryPackage.createTypeInfo(components.dataFlowAnalyzer.checkStatementType(dcl, context), context);
} }
@Override @Override
@@ -225,7 +227,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
else { else {
return facade.getTypeInfo(expression, context); return facade.getTypeInfo(expression, context);
} }
return DataFlowUtils.checkType(result, expression, context); return components.dataFlowAnalyzer.checkType(result, expression, context);
} }
@NotNull @NotNull
@@ -320,7 +322,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
basic.resolveArrayAccessSetMethod((JetArrayAccessExpression) left, right, contextForResolve, context.trace); basic.resolveArrayAccessSetMethod((JetArrayAccessExpression) left, right, contextForResolve, context.trace);
} }
rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo())); rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
DataFlowUtils.checkType(binaryOperationType, expression, context.replaceExpectedType(leftType).replaceDataFlowInfo(rightInfo.getDataFlowInfo())); components.dataFlowAnalyzer.checkType(binaryOperationType, expression, context.replaceExpectedType(leftType).replaceDataFlowInfo(rightInfo.getDataFlowInfo()));
basic.checkLValue(context.trace, context, leftOperand, right); basic.checkLValue(context.trace, context, leftOperand, right);
} }
temporary.commit(); temporary.commit();
@@ -368,7 +370,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated
basic.checkLValue(context.trace, context, leftOperand, right); basic.checkLValue(context.trace, context, leftOperand, right);
} }
return resultInfo.replaceType(DataFlowUtils.checkStatementType(expression, contextWithExpectedType)); return resultInfo.replaceType(components.dataFlowAnalyzer.checkStatementType(expression, contextWithExpectedType));
} }
@@ -27,8 +27,11 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries
import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContext.EXPECTED_RETURN_TYPE import org.jetbrains.kotlin.resolve.BindingContext.EXPECTED_RETURN_TYPE
import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
import org.jetbrains.kotlin.resolve.scopes.WritableScope import org.jetbrains.kotlin.resolve.scopes.WritableScope
import org.jetbrains.kotlin.resolve.source.toSourceElement import org.jetbrains.kotlin.resolve.source.toSourceElement
@@ -39,9 +42,7 @@ import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE
import org.jetbrains.kotlin.types.TypeUtils.noExpectedType import org.jetbrains.kotlin.types.TypeUtils.noExpectedType
import org.jetbrains.kotlin.types.checker.JetTypeChecker import org.jetbrains.kotlin.types.checker.JetTypeChecker
import org.jetbrains.kotlin.types.expressions.CoercionStrategy.COERCION_TO_UNIT import org.jetbrains.kotlin.types.expressions.CoercionStrategy.COERCION_TO_UNIT
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createCheckedTypeInfo
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : ExpressionTypingVisitor(facade) { public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : ExpressionTypingVisitor(facade) {
@@ -109,10 +110,10 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express
} }
if (isStatement) { if (isStatement) {
return createTypeInfo(DataFlowUtils.checkStatementType(function, context), context) return createTypeInfo(components.dataFlowAnalyzer.checkStatementType(function, context), context)
} }
else { else {
return createCheckedTypeInfo(createFunctionType(functionDescriptor), context, function) return components.dataFlowAnalyzer.createCheckedTypeInfo(createFunctionType(functionDescriptor), context, function)
} }
} }
@@ -151,7 +152,7 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express
return createTypeInfo(resultType, context) return createTypeInfo(resultType, context)
} }
return createCheckedTypeInfo(resultType, context, expression) return components.dataFlowAnalyzer.createCheckedTypeInfo(resultType, context, expression)
} }
private fun createFunctionLiteralDescriptor( private fun createFunctionLiteralDescriptor(
@@ -67,7 +67,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
DataFlowInfo newDataFlowInfo = conditionInfo.and(typeInfo.getDataFlowInfo()); DataFlowInfo newDataFlowInfo = conditionInfo.and(typeInfo.getDataFlowInfo());
context.trace.record(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression, newDataFlowInfo); context.trace.record(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression, newDataFlowInfo);
} }
return DataFlowUtils.checkType(typeInfo.replaceType(components.builtIns.getBooleanType()), expression, contextWithExpectedType); return components.dataFlowAnalyzer.checkType(typeInfo.replaceType(components.builtIns.getBooleanType()), expression, contextWithExpectedType);
} }
@Override @Override
@@ -76,7 +76,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
} }
public JetTypeInfo visitWhenExpression(JetWhenExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { public JetTypeInfo visitWhenExpression(JetWhenExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
DataFlowUtils.recordExpectedType(contextWithExpectedType.trace, expression, contextWithExpectedType.expectedType); components.dataFlowAnalyzer.recordExpectedType(contextWithExpectedType.trace, expression, contextWithExpectedType.expectedType);
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
// TODO :change scope according to the bound value in the when header // TODO :change scope according to the bound value in the when header
@@ -94,7 +94,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
assert subjectType != null; assert subjectType != null;
if (TypeUtils.isNullableType(subjectType) && !WhenChecker.containsNullCase(expression, context.trace)) { if (TypeUtils.isNullableType(subjectType) && !WhenChecker.containsNullCase(expression, context.trace)) {
ExpressionTypingContext subjectContext = context.replaceExpectedType(TypeUtils.makeNotNullable(subjectType)); ExpressionTypingContext subjectContext = context.replaceExpectedType(TypeUtils.makeNotNullable(subjectType));
DataFlowUtils.checkPossibleCast(subjectType, JetPsiUtil.safeDeparenthesize(subjectExpression, false), subjectContext); components.dataFlowAnalyzer.checkPossibleCast(subjectType, JetPsiUtil.safeDeparenthesize(subjectExpression, false), subjectContext);
} }
context = context.replaceDataFlowInfo(typeInfo.getDataFlowInfo()); context = context.replaceDataFlowInfo(typeInfo.getDataFlowInfo());
} }
@@ -143,8 +143,8 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
commonDataFlowInfo = commonDataFlowInfo.or(context.dataFlowInfo); commonDataFlowInfo = commonDataFlowInfo.or(context.dataFlowInfo);
} }
return TypeInfoFactoryPackage.createTypeInfo(expressionTypes.isEmpty() ? null : DataFlowUtils.checkType( return TypeInfoFactoryPackage.createTypeInfo(expressionTypes.isEmpty() ? null : components.dataFlowAnalyzer.checkType(
DataFlowUtils.checkImplicitCast( components.dataFlowAnalyzer.checkImplicitCast(
CommonSupertypes.commonSupertype(expressionTypes), expression, CommonSupertypes.commonSupertype(expressionTypes), expression,
contextWithExpectedType, isStatement), contextWithExpectedType, isStatement),
expression, contextWithExpectedType), expression, contextWithExpectedType),
@@ -280,8 +280,8 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(TYPE_MISMATCH_IN_CONDITION.on(expression, type)); context.trace.report(TYPE_MISMATCH_IN_CONDITION.on(expression, type));
} }
else { else {
DataFlowInfo ifInfo = DataFlowUtils.extractDataFlowInfoFromCondition(expression, true, context); DataFlowInfo ifInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(expression, true, context);
DataFlowInfo elseInfo = DataFlowUtils.extractDataFlowInfoFromCondition(expression, false, context); DataFlowInfo elseInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(expression, false, context);
return new DataFlowInfos(ifInfo, elseInfo); return new DataFlowInfos(ifInfo, elseInfo);
} }
return noChange(context); return noChange(context);
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.expressions.DataFlowUtils import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer
import org.jetbrains.kotlin.types.expressions.JetTypeInfo import org.jetbrains.kotlin.types.expressions.JetTypeInfo
/* /*
@@ -39,6 +39,3 @@ public fun createTypeInfo(type: JetType?, context: ResolutionContext<*>): JetTyp
public fun noTypeInfo(dataFlowInfo: DataFlowInfo): JetTypeInfo = createTypeInfo(null, dataFlowInfo) public fun noTypeInfo(dataFlowInfo: DataFlowInfo): JetTypeInfo = createTypeInfo(null, dataFlowInfo)
public fun noTypeInfo(context: ResolutionContext<*>): JetTypeInfo = noTypeInfo(context.dataFlowInfo) public fun noTypeInfo(context: ResolutionContext<*>): JetTypeInfo = noTypeInfo(context.dataFlowInfo)
public fun createCheckedTypeInfo(type: JetType?, context: ResolutionContext<*>, expression: JetExpression): JetTypeInfo =
DataFlowUtils.checkType(createTypeInfo(type, context), expression, context)