use of org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue in project kotlin by JetBrains.
the class BasicExpressionTypingVisitor method visitUnaryExpression.
@Override
public KotlinTypeInfo visitUnaryExpression(@NotNull KtUnaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
ExpressionTypingContext context = isUnaryExpressionDependentOnExpectedType(expression) ? contextWithExpectedType : contextWithExpectedType.replaceContextDependency(INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE);
KtExpression baseExpression = expression.getBaseExpression();
if (baseExpression == null)
return TypeInfoFactoryKt.noTypeInfo(context);
KtSimpleNameExpression operationSign = expression.getOperationReference();
IElementType operationType = operationSign.getReferencedNameElementType();
// Special case for expr!!
if (operationType == KtTokens.EXCLEXCL) {
return visitExclExclExpression(expression, context);
}
// Type check the base expression
KotlinTypeInfo typeInfo = facade.safeGetTypeInfo(baseExpression, context);
KotlinType type = ExpressionTypingUtils.safeGetType(typeInfo);
ExpressionReceiver receiver = ExpressionReceiver.Companion.create(baseExpression, type, context.trace.getBindingContext());
Call call = CallMaker.makeCall(receiver, expression);
// Conventions for unary operations
Name name = OperatorConventions.UNARY_OPERATION_NAMES.get(operationType);
if (name == null) {
context.trace.report(UNSUPPORTED.on(operationSign, "visitUnaryExpression"));
return typeInfo.clearType();
}
// a[i]++/-- takes special treatment because it is actually let j = i, arr = a in arr.set(j, a.get(j).inc())
if ((operationType == KtTokens.PLUSPLUS || operationType == KtTokens.MINUSMINUS) && baseExpression instanceof KtArrayAccessExpression) {
KtExpression stubExpression = ExpressionTypingUtils.createFakeExpressionOfType(baseExpression.getProject(), context.trace, "e", type);
TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve array access set method for unary expression", expression);
ExpressionTypingContext newContext = context.replaceBindingTrace(temporaryBindingTrace);
resolveImplicitArrayAccessSetMethod((KtArrayAccessExpression) baseExpression, stubExpression, newContext, context.trace);
}
// Resolve the operation reference
OverloadResolutionResults<FunctionDescriptor> resolutionResults = components.callResolver.resolveCallWithGivenName(context, call, expression.getOperationReference(), name);
if (!resolutionResults.isSuccess()) {
return typeInfo.clearType();
}
// Computing the return type
KotlinType returnType = resolutionResults.getResultingDescriptor().getReturnType();
KotlinType result;
if (operationType == KtTokens.PLUSPLUS || operationType == KtTokens.MINUSMINUS) {
assert returnType != null : "returnType is null for " + resolutionResults.getResultingDescriptor();
if (KotlinBuiltIns.isUnit(returnType)) {
result = ErrorUtils.createErrorType(components.builtIns.getUnit().getName().asString());
context.trace.report(INC_DEC_SHOULD_NOT_RETURN_UNIT.on(operationSign));
} else {
KotlinType receiverType = receiver.getType();
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(returnType, receiverType)) {
context.trace.report(RESULT_TYPE_MISMATCH.on(operationSign, name.asString(), receiverType, returnType));
} else {
context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression);
KtExpression stubExpression = ExpressionTypingUtils.createFakeExpressionOfType(baseExpression.getProject(), context.trace, "e", type);
checkLValue(context.trace, context, baseExpression, stubExpression, expression);
}
// x++ type is x type, but ++x type is x.inc() type
DataFlowValue receiverValue = DataFlowValueFactory.createDataFlowValue((ReceiverValue) call.getExplicitReceiver(), contextWithExpectedType);
if (expression instanceof KtPrefixExpression) {
result = returnType;
} else {
result = receiverType;
// Also record data flow information for x++ value (= x)
DataFlowValue returnValue = DataFlowValueFactory.createDataFlowValue(expression, receiverType, contextWithExpectedType);
typeInfo = typeInfo.replaceDataFlowInfo(typeInfo.getDataFlowInfo().assign(returnValue, receiverValue, components.languageVersionSettings));
}
}
} else {
result = returnType;
}
CompileTimeConstant<?> value = components.constantExpressionEvaluator.evaluateExpression(expression, contextWithExpectedType.trace, contextWithExpectedType.expectedType);
if (value != null) {
return components.dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType);
}
return components.dataFlowAnalyzer.checkType(typeInfo.replaceType(result), expression, contextWithExpectedType.replaceDataFlowInfo(typeInfo.getDataFlowInfo()));
}
use of org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue in project kotlin by JetBrains.
the class ExpressionTypingVisitorForStatements method visitAssignment.
@NotNull
protected KotlinTypeInfo visitAssignment(KtBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(scope).replaceContextDependency(INDEPENDENT);
KtExpression leftOperand = expression.getLeft();
if (leftOperand instanceof KtAnnotatedExpression) {
basic.resolveAnnotationsOnExpression((KtAnnotatedExpression) leftOperand, context);
}
KtExpression left = deparenthesize(leftOperand);
KtExpression right = expression.getRight();
if (left instanceof KtArrayAccessExpression) {
KtArrayAccessExpression arrayAccessExpression = (KtArrayAccessExpression) left;
if (right == null)
return TypeInfoFactoryKt.noTypeInfo(context);
KotlinTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace);
basic.checkLValue(context.trace, context, arrayAccessExpression, right, expression);
return typeInfo.replaceType(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType));
}
KotlinTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade);
KotlinType expectedType = refineTypeFromPropertySetterIfPossible(context.trace.getBindingContext(), leftOperand, leftInfo.getType());
DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
KotlinTypeInfo resultInfo;
if (right != null) {
resultInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(expectedType).replaceCallPosition(new CallPosition.PropertyAssignment(leftOperand)));
dataFlowInfo = resultInfo.getDataFlowInfo();
KotlinType rightType = resultInfo.getType();
if (left != null && expectedType != null && rightType != null) {
DataFlowValue leftValue = DataFlowValueFactory.createDataFlowValue(left, expectedType, context);
DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rightType, context);
// We cannot say here anything new about rightValue except it has the same value as leftValue
resultInfo = resultInfo.replaceDataFlowInfo(dataFlowInfo.assign(leftValue, rightValue, components.languageVersionSettings));
}
} else {
resultInfo = leftInfo;
}
if (expectedType != null && leftOperand != null) {
//if expectedType == null, some other error has been generated
basic.checkLValue(context.trace, context, leftOperand, right, expression);
}
return resultInfo.replaceType(components.dataFlowAnalyzer.checkStatementType(expression, contextWithExpectedType));
}
use of org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue in project kotlin by JetBrains.
the class BasicExpressionTypingVisitor method visitElvisExpression.
@NotNull
private KotlinTypeInfo visitElvisExpression(@NotNull KtBinaryExpression expression, @NotNull ExpressionTypingContext contextWithExpectedType) {
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE);
KtExpression left = expression.getLeft();
KtExpression right = expression.getRight();
if (left == null || right == null) {
getTypeInfoOrNullType(left, context, facade);
return TypeInfoFactoryKt.noTypeInfo(context);
}
Call call = createCallForSpecialConstruction(expression, expression.getOperationReference(), Lists.newArrayList(left, right));
ResolvedCall<FunctionDescriptor> resolvedCall = components.controlStructureTypingUtils.resolveSpecialConstructionAsCall(call, ResolveConstruct.ELVIS, Lists.newArrayList("left", "right"), Lists.newArrayList(true, false), contextWithExpectedType, null);
KotlinTypeInfo leftTypeInfo = BindingContextUtils.getRecordedTypeInfo(left, context.trace.getBindingContext());
if (ArgumentTypeResolver.isFunctionLiteralArgument(left, context)) {
context.trace.report(USELESS_ELVIS_ON_LAMBDA_EXPRESSION.on(expression.getOperationReference()));
if (leftTypeInfo == null)
return TypeInfoFactoryKt.noTypeInfo(context);
}
assert leftTypeInfo != null : "Left expression was not processed: " + expression;
KotlinType leftType = leftTypeInfo.getType();
if (leftType != null && isKnownToBeNotNull(left, leftType, context)) {
context.trace.report(USELESS_ELVIS.on(expression, leftType));
} else if (KtPsiUtil.isNullConstant(right) && leftType != null && !FlexibleTypesKt.isNullabilityFlexible(leftType)) {
context.trace.report(USELESS_ELVIS_RIGHT_IS_NULL.on(expression));
}
KotlinTypeInfo rightTypeInfo = BindingContextUtils.getRecordedTypeInfo(right, context.trace.getBindingContext());
if (rightTypeInfo == null && ArgumentTypeResolver.isFunctionLiteralArgument(right, context)) {
// the type is computed later in call completer according to the '?:' semantics as a function
return TypeInfoFactoryKt.noTypeInfo(context);
}
assert rightTypeInfo != null : "Right expression was not processed: " + expression;
boolean loopBreakContinuePossible = leftTypeInfo.getJumpOutPossible() || rightTypeInfo.getJumpOutPossible();
KotlinType rightType = rightTypeInfo.getType();
// Only left argument DFA is taken into account here: we cannot be sure that right argument is joined
// (we merge it with right DFA if right argument contains no jump outside)
DataFlowInfo dataFlowInfo = resolvedCall.getDataFlowInfoForArguments().getInfo(call.getValueArguments().get(1));
KotlinType type = resolvedCall.getResultingDescriptor().getReturnType();
if (type == null || rightType == null || leftType == null && KotlinBuiltIns.isNothing(rightType))
return TypeInfoFactoryKt.noTypeInfo(dataFlowInfo);
if (leftType != null) {
DataFlowValue leftValue = createDataFlowValue(left, leftType, context);
DataFlowInfo rightDataFlowInfo = resolvedCall.getDataFlowInfoForArguments().getResultInfo();
boolean jumpInRight = KotlinBuiltIns.isNothing(rightType);
DataFlowValue nullValue = DataFlowValue.nullValue(components.builtIns);
// left argument is considered not-null if it's not-null also in right part or if we have jump in right part
if (jumpInRight || !rightDataFlowInfo.getStableNullability(leftValue).canBeNull()) {
dataFlowInfo = dataFlowInfo.disequate(leftValue, nullValue, components.languageVersionSettings);
if (left instanceof KtBinaryExpressionWithTypeRHS) {
dataFlowInfo = establishSubtypingForTypeRHS((KtBinaryExpressionWithTypeRHS) left, dataFlowInfo, context, components.languageVersionSettings);
}
}
DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(expression, type, context);
dataFlowInfo = dataFlowInfo.assign(resultValue, leftValue, components.languageVersionSettings).disequate(resultValue, nullValue, components.languageVersionSettings);
if (!jumpInRight) {
DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rightType, context);
rightDataFlowInfo = rightDataFlowInfo.assign(resultValue, rightValue, components.languageVersionSettings);
dataFlowInfo = dataFlowInfo.or(rightDataFlowInfo);
}
}
// but result is not nullable if the right type is not nullable
if (!TypeUtils.isNullableType(rightType) && TypeUtils.isNullableType(type)) {
type = TypeUtils.makeNotNullable(type);
}
if (context.contextDependency == DEPENDENT) {
return TypeInfoFactoryKt.createTypeInfo(type, dataFlowInfo);
}
// If break or continue was possible, take condition check info as the jump info
return TypeInfoFactoryKt.createTypeInfo(components.dataFlowAnalyzer.checkType(type, expression, contextWithExpectedType), dataFlowInfo, loopBreakContinuePossible, context.dataFlowInfo);
}
use of org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue in project kotlin by JetBrains.
the class ControlStructureTypingVisitor method visitIfExpression.
public KotlinTypeInfo visitIfExpression(KtIfExpression ifExpression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
components.dataFlowAnalyzer.recordExpectedType(contextWithExpectedType.trace, ifExpression, contextWithExpectedType.expectedType);
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE);
KtExpression condition = ifExpression.getCondition();
DataFlowInfo conditionDataFlowInfo = checkCondition(context.scope, condition, context);
boolean loopBreakContinuePossibleInCondition = condition != null && containsJumpOutOfLoop(condition, context);
KtExpression elseBranch = ifExpression.getElse();
KtExpression thenBranch = ifExpression.getThen();
LexicalWritableScope thenScope = newWritableScopeImpl(context, LexicalScopeKind.THEN, components.overloadChecker);
LexicalWritableScope elseScope = newWritableScopeImpl(context, LexicalScopeKind.ELSE, components.overloadChecker);
DataFlowInfo thenInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(condition, true, context).and(conditionDataFlowInfo);
DataFlowInfo elseInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(condition, false, context).and(conditionDataFlowInfo);
if (elseBranch == null) {
if (thenBranch != null) {
KotlinTypeInfo result = getTypeInfoWhenOnlyOneBranchIsPresent(thenBranch, thenScope, thenInfo, elseInfo, contextWithExpectedType, ifExpression);
// If jump was possible, take condition check info as the jump info
return result.getJumpOutPossible() ? result.replaceJumpOutPossible(true).replaceJumpFlowInfo(conditionDataFlowInfo) : result;
}
return TypeInfoFactoryKt.createTypeInfo(components.builtIns.getUnitType(), thenInfo.or(elseInfo));
}
if (thenBranch == null) {
return getTypeInfoWhenOnlyOneBranchIsPresent(elseBranch, elseScope, elseInfo, thenInfo, contextWithExpectedType, ifExpression);
}
KtPsiFactory psiFactory = KtPsiFactoryKt.KtPsiFactory(ifExpression);
KtBlockExpression thenBlock = psiFactory.wrapInABlockWrapper(thenBranch);
KtBlockExpression elseBlock = psiFactory.wrapInABlockWrapper(elseBranch);
Call callForIf = createCallForSpecialConstruction(ifExpression, ifExpression, Lists.newArrayList(thenBlock, elseBlock));
MutableDataFlowInfoForArguments dataFlowInfoForArguments = createDataFlowInfoForArgumentsForIfCall(callForIf, conditionDataFlowInfo, thenInfo, elseInfo);
ResolvedCall<FunctionDescriptor> resolvedCall = components.controlStructureTypingUtils.resolveSpecialConstructionAsCall(callForIf, ResolveConstruct.IF, Lists.newArrayList("thenBranch", "elseBranch"), Lists.newArrayList(false, false), contextWithExpectedType, dataFlowInfoForArguments);
BindingContext bindingContext = context.trace.getBindingContext();
KotlinTypeInfo thenTypeInfo = BindingContextUtils.getRecordedTypeInfo(thenBranch, bindingContext);
KotlinTypeInfo elseTypeInfo = BindingContextUtils.getRecordedTypeInfo(elseBranch, bindingContext);
assert thenTypeInfo != null || elseTypeInfo != null : "Both branches of if expression were not processed: " + ifExpression.getText();
KotlinType resultType = resolvedCall.getResultingDescriptor().getReturnType();
boolean loopBreakContinuePossible = loopBreakContinuePossibleInCondition;
DataFlowInfo resultDataFlowInfo;
if (elseTypeInfo == null) {
loopBreakContinuePossible |= thenTypeInfo.getJumpOutPossible();
resultDataFlowInfo = thenTypeInfo.getDataFlowInfo();
} else if (thenTypeInfo == null) {
loopBreakContinuePossible |= elseTypeInfo.getJumpOutPossible();
resultDataFlowInfo = elseTypeInfo.getDataFlowInfo();
} else {
KotlinType thenType = thenTypeInfo.getType();
KotlinType elseType = elseTypeInfo.getType();
DataFlowInfo thenDataFlowInfo = thenTypeInfo.getDataFlowInfo();
DataFlowInfo elseDataFlowInfo = elseTypeInfo.getDataFlowInfo();
if (resultType != null && thenType != null && elseType != null) {
DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(ifExpression, resultType, context);
DataFlowValue thenValue = DataFlowValueFactory.createDataFlowValue(thenBranch, thenType, context);
thenDataFlowInfo = thenDataFlowInfo.assign(resultValue, thenValue, components.languageVersionSettings);
DataFlowValue elseValue = DataFlowValueFactory.createDataFlowValue(elseBranch, elseType, context);
elseDataFlowInfo = elseDataFlowInfo.assign(resultValue, elseValue, components.languageVersionSettings);
}
loopBreakContinuePossible |= thenTypeInfo.getJumpOutPossible() || elseTypeInfo.getJumpOutPossible();
boolean jumpInThen = thenType != null && KotlinBuiltIns.isNothing(thenType);
boolean jumpInElse = elseType != null && KotlinBuiltIns.isNothing(elseType);
if (thenType == null && elseType == null) {
resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo);
} else if (thenType == null || (jumpInThen && !jumpInElse)) {
resultDataFlowInfo = elseDataFlowInfo;
} else if (elseType == null || (jumpInElse && !jumpInThen)) {
resultDataFlowInfo = thenDataFlowInfo;
} else {
resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo);
}
if (thenType == null && jumpInElse || elseType == null && jumpInThen) {
return TypeInfoFactoryKt.noTypeInfo(resultDataFlowInfo);
}
}
// If break or continue was possible, take condition check info as the jump info
return TypeInfoFactoryKt.createTypeInfo(components.dataFlowAnalyzer.checkType(resultType, ifExpression, contextWithExpectedType), resultDataFlowInfo, loopBreakContinuePossible, loopBreakContinuePossibleInCondition ? context.dataFlowInfo : conditionDataFlowInfo);
}
use of org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue in project kotlin by JetBrains.
the class ExpressionTypingServices method getBlockReturnedTypeWithWritableScope.
/**
* Visits block statements propagating data flow information from the first to the last.
* Determines block returned type and data flow information at the end of the block AND
* at the nearest jump point from the block beginning.
*/
/*package*/
KotlinTypeInfo getBlockReturnedTypeWithWritableScope(@NotNull LexicalWritableScope scope, @NotNull List<? extends KtElement> block, @NotNull CoercionStrategy coercionStrategyForLastExpression, @NotNull ExpressionTypingContext context) {
if (block.isEmpty()) {
return TypeInfoFactoryKt.createTypeInfo(expressionTypingComponents.builtIns.getUnitType(), context);
}
ExpressionTypingInternals blockLevelVisitor = new ExpressionTypingVisitorDispatcher.ForBlock(expressionTypingComponents, annotationChecker, scope);
ExpressionTypingContext newContext = context.replaceScope(scope).replaceExpectedType(NO_EXPECTED_TYPE);
KotlinTypeInfo result = TypeInfoFactoryKt.noTypeInfo(context);
// Jump point data flow info
DataFlowInfo beforeJumpInfo = newContext.dataFlowInfo;
boolean jumpOutPossible = false;
for (Iterator<? extends KtElement> iterator = block.iterator(); iterator.hasNext(); ) {
KtElement statement = iterator.next();
if (!(statement instanceof KtExpression)) {
continue;
}
KtExpression statementExpression = (KtExpression) statement;
if (!iterator.hasNext()) {
result = getTypeOfLastExpressionInBlock(statementExpression, newContext.replaceExpectedType(context.expectedType), coercionStrategyForLastExpression, blockLevelVisitor);
if (result.getType() != null && statementExpression.getParent() instanceof KtBlockExpression) {
DataFlowValue lastExpressionValue = DataFlowValueFactory.createDataFlowValue(statementExpression, result.getType(), context);
DataFlowValue blockExpressionValue = DataFlowValueFactory.createDataFlowValue((KtBlockExpression) statementExpression.getParent(), result.getType(), context);
result = result.replaceDataFlowInfo(result.getDataFlowInfo().assign(blockExpressionValue, lastExpressionValue, expressionTypingComponents.languageVersionSettings));
}
} else {
result = blockLevelVisitor.getTypeInfo(statementExpression, newContext.replaceContextDependency(ContextDependency.INDEPENDENT), true);
}
DataFlowInfo newDataFlowInfo = result.getDataFlowInfo();
// If jump is not possible, we take new data flow info before jump
if (!jumpOutPossible) {
beforeJumpInfo = result.getJumpFlowInfo();
jumpOutPossible = result.getJumpOutPossible();
}
if (newDataFlowInfo != context.dataFlowInfo) {
newContext = newContext.replaceDataFlowInfo(newDataFlowInfo);
// We take current data flow info if jump there is not possible
}
blockLevelVisitor = new ExpressionTypingVisitorDispatcher.ForBlock(expressionTypingComponents, annotationChecker, scope);
}
return result.replaceJumpOutPossible(jumpOutPossible).replaceJumpFlowInfo(beforeJumpInfo);
}
Aggregations