Search in sources :

Example 11 with ResolvedCall

use of org.jetbrains.kotlin.resolve.calls.model.ResolvedCall 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)

Aggregations

ResolvedCall (org.jetbrains.kotlin.resolve.calls.model.ResolvedCall)11 NotNull (org.jetbrains.annotations.NotNull)4 PsiElement (com.intellij.psi.PsiElement)2 IElementType (com.intellij.psi.tree.IElementType)2 DeclarationDescriptor (org.jetbrains.kotlin.descriptors.DeclarationDescriptor)2 DataFlowInfoForArgumentsImpl (org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl)2 DataFlowInfo (org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo)2 DataFlowValue (org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue)2 KotlinType (org.jetbrains.kotlin.types.KotlinType)2 Collection (java.util.Collection)1 Nullable (org.jetbrains.annotations.Nullable)1 AccessTarget (org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessTarget)1 CallableDescriptor (org.jetbrains.kotlin.descriptors.CallableDescriptor)1 PropertyDescriptor (org.jetbrains.kotlin.descriptors.PropertyDescriptor)1 VariableDescriptor (org.jetbrains.kotlin.descriptors.VariableDescriptor)1 Diagnostic (org.jetbrains.kotlin.diagnostics.Diagnostic)1 DiagnosticFactory (org.jetbrains.kotlin.diagnostics.DiagnosticFactory)1 BindingContext (org.jetbrains.kotlin.resolve.BindingContext)1 BindingTrace (org.jetbrains.kotlin.resolve.BindingTrace)1 ResolutionContext (org.jetbrains.kotlin.resolve.calls.context.ResolutionContext)1