Search in sources :

Example 11 with DataFlowInfo

use of org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo 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);
}
Also used : ResolvedCall(org.jetbrains.kotlin.resolve.calls.model.ResolvedCall) ControlStructureTypingUtils.createDataFlowInfoForArgumentsForIfCall(org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.createDataFlowInfoForArgumentsForIfCall) KotlinType(org.jetbrains.kotlin.types.KotlinType) MutableDataFlowInfoForArguments(org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments) BindingContext(org.jetbrains.kotlin.resolve.BindingContext) DataFlowValue(org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue) LexicalWritableScope(org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope) DataFlowInfo(org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo)

Example 12 with DataFlowInfo

use of org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo in project kotlin by JetBrains.

the class ControlStructureTypingVisitor method visitWhileExpression.

public KotlinTypeInfo visitWhileExpression(KtWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
    if (!isStatement)
        return components.dataFlowAnalyzer.illegalStatementType(expression, contextWithExpectedType, facade);
    ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
    // Preliminary analysis
    PreliminaryLoopVisitor loopVisitor = PreliminaryLoopVisitor.visitLoop(expression);
    context = context.replaceDataFlowInfo(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(context.dataFlowInfo, components.languageVersionSettings));
    KtExpression condition = expression.getCondition();
    // Extract data flow info from condition itself without taking value into account
    DataFlowInfo dataFlowInfo = checkCondition(context.scope, condition, context);
    KtExpression body = expression.getBody();
    KotlinTypeInfo bodyTypeInfo;
    DataFlowInfo conditionInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(condition, true, context).and(dataFlowInfo);
    if (body != null) {
        LexicalWritableScope scopeToExtend = newWritableScopeImpl(context, LexicalScopeKind.WHILE_BODY, components.overloadChecker);
        bodyTypeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(scopeToExtend, Collections.singletonList(body), CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(conditionInfo));
    } else {
        bodyTypeInfo = TypeInfoFactoryKt.noTypeInfo(conditionInfo);
    }
    // Condition is false at this point only if there is no jumps outside
    if (!containsJumpOutOfLoop(expression, context)) {
        dataFlowInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(condition, false, context).and(dataFlowInfo);
    }
    // See KT-6284
    if (body != null && KtPsiUtil.isTrueConstant(condition)) {
        // We should take data flow info from the first jump point,
        // but without affecting changing variables
        dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo(), components.languageVersionSettings));
    }
    return components.dataFlowAnalyzer.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType).replaceDataFlowInfo(dataFlowInfo);
}
Also used : LexicalWritableScope(org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope) DataFlowInfo(org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo)

Example 13 with DataFlowInfo

use of org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo in project kotlin by JetBrains.

the class ControlStructureTypingVisitor method getTypeInfoWhenOnlyOneBranchIsPresent.

@NotNull
private KotlinTypeInfo getTypeInfoWhenOnlyOneBranchIsPresent(@NotNull KtExpression presentBranch, @NotNull LexicalWritableScope presentScope, @NotNull DataFlowInfo presentInfo, @NotNull DataFlowInfo otherInfo, @NotNull ExpressionTypingContext context, @NotNull KtIfExpression ifExpression) {
    ExpressionTypingContext newContext = context.replaceDataFlowInfo(presentInfo).replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
    KotlinTypeInfo typeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(presentScope, Collections.singletonList(presentBranch), CoercionStrategy.NO_COERCION, newContext);
    KotlinType type = typeInfo.getType();
    DataFlowInfo dataFlowInfo;
    if (type != null && KotlinBuiltIns.isNothing(type)) {
        dataFlowInfo = otherInfo;
    } else {
        dataFlowInfo = typeInfo.getDataFlowInfo().or(otherInfo);
    }
    return components.dataFlowAnalyzer.checkType(typeInfo.replaceType(components.builtIns.getUnitType()), ifExpression, context).replaceDataFlowInfo(dataFlowInfo);
}
Also used : KotlinType(org.jetbrains.kotlin.types.KotlinType) DataFlowInfo(org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo) NotNull(org.jetbrains.annotations.NotNull)

Example 14 with DataFlowInfo

use of org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo in project kotlin by JetBrains.

the class ControlStructureTypingVisitor method visitDoWhileExpression.

public KotlinTypeInfo visitDoWhileExpression(KtDoWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
    if (!isStatement)
        return components.dataFlowAnalyzer.illegalStatementType(expression, contextWithExpectedType, facade);
    ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
    KtExpression body = expression.getBody();
    LexicalScope conditionScope = context.scope;
    // Preliminary analysis
    PreliminaryLoopVisitor loopVisitor = PreliminaryLoopVisitor.visitLoop(expression);
    context = context.replaceDataFlowInfo(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(context.dataFlowInfo, components.languageVersionSettings));
    // Here we must record data flow information at the end of the body (or at the first jump, to be precise) and
    // .and it with entrance data flow information, because do-while body is executed at least once
    // See KT-6283
    KotlinTypeInfo bodyTypeInfo;
    if (body instanceof KtLambdaExpression) {
        // As a matter of fact, function literal is always unused at this point
        bodyTypeInfo = facade.getTypeInfo(body, context.replaceScope(context.scope));
    } else if (body != null) {
        LexicalWritableScope writableScope = newWritableScopeImpl(context, LexicalScopeKind.DO_WHILE_BODY, components.overloadChecker);
        conditionScope = writableScope;
        List<KtExpression> block;
        if (body instanceof KtBlockExpression) {
            block = ((KtBlockExpression) body).getStatements();
        } else {
            block = Collections.singletonList(body);
        }
        bodyTypeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(writableScope, block, CoercionStrategy.NO_COERCION, context);
    } else {
        bodyTypeInfo = TypeInfoFactoryKt.noTypeInfo(context);
    }
    KtExpression condition = expression.getCondition();
    DataFlowInfo conditionDataFlowInfo = checkCondition(conditionScope, condition, context);
    DataFlowInfo dataFlowInfo;
    // Without jumps out, condition is entered and false, with jumps out, we know nothing about it
    if (!containsJumpOutOfLoop(expression, context)) {
        dataFlowInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(condition, false, context).and(conditionDataFlowInfo);
    } else {
        dataFlowInfo = context.dataFlowInfo;
    }
    // If it's a function literal, it appears always unused so it's no matter what we do at this point
    if (body != null) {
        // We should take data flow info from the first jump point,
        // but without affecting changing variables
        dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo(), components.languageVersionSettings));
    }
    return components.dataFlowAnalyzer.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType).replaceDataFlowInfo(dataFlowInfo);
}
Also used : LexicalScope(org.jetbrains.kotlin.resolve.scopes.LexicalScope) LexicalWritableScope(org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope) ArrayList(java.util.ArrayList) List(java.util.List) DataFlowInfo(org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo)

Example 15 with DataFlowInfo

use of org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo 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);
}
Also used : DataFlowValue(org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue) DataFlowInfo(org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo)

Aggregations

DataFlowInfo (org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo)16 DataFlowValue (org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue)6 NotNull (org.jetbrains.annotations.NotNull)5 ResolvedCall (org.jetbrains.kotlin.resolve.calls.model.ResolvedCall)4 LexicalWritableScope (org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope)4 DataFlowValueFactory.createDataFlowValue (org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory.createDataFlowValue)3 KotlinType (org.jetbrains.kotlin.types.KotlinType)3 ExpressionReceiver (org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver)2 PsiElement (com.intellij.psi.PsiElement)1 IElementType (com.intellij.psi.tree.IElementType)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 Function1 (kotlin.jvm.functions.Function1)1 SyntheticFieldDescriptor (org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor)1 ValueArgument (org.jetbrains.kotlin.psi.ValueArgument)1 BindingContext (org.jetbrains.kotlin.resolve.BindingContext)1 CallPosition (org.jetbrains.kotlin.resolve.calls.context.CallPosition)1 MutableDataFlowInfoForArguments (org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments)1 LexicalScope (org.jetbrains.kotlin.resolve.scopes.LexicalScope)1 ControlStructureTypingUtils.createDataFlowInfoForArgumentsForIfCall (org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.createDataFlowInfoForArgumentsForIfCall)1