示例#1
0
    def computeExpressionRaw(self, trace_collection):
        self.variable_trace = trace_collection.getVariableCurrentTrace(
            variable=self.variable
        )

        replacement = self.variable_trace.getReplacementNode(self)

        if replacement is not None:
            trace_collection.signalChange(
                "new_expression",
                self.source_ref,
                "Value propagated for '%s' from '%s'."
                % (
                    self.variable.getName(),
                    replacement.getSourceReference().getAsString(),
                ),
            )

            # Need to compute the replacement still.
            return replacement.computeExpressionRaw(trace_collection)

        # If we cannot be sure if the value is set, then we need the fallback,
        # otherwise we could remove it simply.
        if self.variable_trace.mustHaveValue():
            trace_collection.signalChange(
                "new_expression",
                self.source_ref,
                "Name '%s' must be in locals dict." % self.variable.getName(),
            )

            result = ExpressionLocalsVariableRef(
                locals_scope=self.locals_scope,
                variable_name=self.variable.getName(),
                source_ref=self.source_ref,
            )

            # Need to compute the replacement still.
            return result.computeExpressionRaw(trace_collection)
        else:
            trace_collection.onExceptionRaiseExit(BaseException)

            branch_fallback = TraceCollectionBranch(
                parent=trace_collection, name="fallback node usage"
            )

            branch_fallback.computeBranch(self.subnode_fallback)

            trace_collection.mergeBranches(branch_fallback, None)

        # if we can be sure if doesn't have a value set, go to the fallback directly.
        if self.variable_trace.mustNotHaveValue():
            return (
                self.subnode_fallback,
                "new_expression",
                "Name '%s' cannot be in locals dict." % self.variable.getName(),
            )
        else:
            return self, None, None
示例#2
0
    def computeExpressionRaw(self, trace_collection):
        # TODO: Use dictionary tracings for locals dict and then cut
        # to no branch variant if possible.

        possible = trace_collection.onLocalsDictGet(self.variable_name)

        if possible is not True:
            branch_fallback = TraceCollectionBranch(parent=trace_collection,
                                                    name="fallback node usage")

            branch_fallback.computeBranch(self.subnode_fallback)

            trace_collection.mergeBranches(branch_fallback, None)

        if possible is False:
            return self.subnode_fallback, "new_expression", "Name '%s' cannot be in locals dict." % self.variable_name
        else:
            return self, None, None
示例#3
0
    def computeExpressionRaw(self, trace_collection):
        # Query the truth value after the expression is evaluated, once it is
        # evaluated in onExpression, it is known.
        trace_collection.onExpression(
            expression = self.getCondition()
        )
        condition = self.getCondition()

        condition_may_raise = condition.mayRaiseException(BaseException)

        if condition_may_raise:
            trace_collection.onExceptionRaiseExit(
                BaseException
            )

        # No need to look any further, if the condition raises, the branches do
        # not matter at all.
        if condition.willRaiseException(BaseException):
            return condition, "new_raise", """\
Conditional expression already raises implicitly in condition, removing \
branches."""

        if not condition_may_raise and condition.mayRaiseExceptionBool(BaseException):
            trace_collection.onExceptionRaiseExit(
                BaseException
            )

        # Decide this based on truth value of condition.
        truth_value = condition.getTruthValue()

        # TODO: We now know that condition evaluates to true for the yes branch
        # and to not true for no branch, the branch should know that.
        yes_branch = self.getExpressionYes()

        # Continue to execute for yes branch unless we know it's not going to be
        # relevant.
        if truth_value is not False:
            branch_yes_collection = TraceCollectionBranch(
                parent = trace_collection,
                name   = "conditional expression yes branch"
            )

            branch_yes_collection.computeBranch(
                branch = yes_branch
            )

            # May have just gone away, so fetch it again.
            yes_branch = self.getExpressionYes()

            # If it's aborting, it doesn't contribute to merging.
            if yes_branch.willRaiseException(BaseException):
                branch_yes_collection = None
        else:
            branch_yes_collection = None

        no_branch = self.getExpressionNo()

        # Continue to execute for yes branch.
        if truth_value is not True:
            branch_no_collection = TraceCollectionBranch(
                parent = trace_collection,
                name   = "conditional expression no branch"
            )

            branch_no_collection.computeBranch(
                branch = no_branch
            )

            # May have just gone away, so fetch it again.
            no_branch = self.getExpressionNo()

            # If it's aborting, it doesn't contribute to merging.
            if no_branch.willRaiseException(BaseException):
                branch_no_collection = None
        else:
            branch_no_collection = None

        # Merge into parent execution.
        self.merge_traces = trace_collection.mergeBranches(
            branch_yes_collection,
            branch_no_collection
        )

        if truth_value is True:
            return (
                wrapExpressionWithNodeSideEffects(
                    new_node = self.getExpressionYes(),
                    old_node = condition
                ),
                "new_expression",
                "Conditional expression predicted to yes case"
            )
        elif truth_value is False:
            return (
                wrapExpressionWithNodeSideEffects(
                    new_node = self.getExpressionNo(),
                    old_node = condition
                ),
                "new_expression",
                "Conditional expression predicted to no case"
            )
        else:
            return self, None, None
示例#4
0
    def computeStatement(self, trace_collection):
        # This is rather complex stuff, pylint: disable=too-many-branches,too-many-statements

        trace_collection.onExpression(
            expression = self.getCondition()
        )
        condition = self.getCondition()

        condition_may_raise = condition.mayRaiseException(BaseException)

        if condition_may_raise:
            trace_collection.onExceptionRaiseExit(
                BaseException
            )

        # No need to look any further, if the condition raises, the branches do
        # not matter at all.
        if condition.willRaiseException(BaseException):
            result = makeStatementExpressionOnlyReplacementNode(
                expression = condition,
                node       = self
            )

            return result, "new_raise", """\
Conditional statements already raises implicitly in condition, removing \
branches."""

        if not condition_may_raise and condition.mayRaiseExceptionBool(BaseException):
            trace_collection.onExceptionRaiseExit(
                BaseException
            )


        # Query the truth value after the expression is evaluated, once it is
        # evaluated in onExpression, it is known.
        truth_value = condition.getTruthValue()

        # TODO: We now know that condition evaluates to true for the yes branch
        # and to not true for no branch, the branch collection should know that.
        yes_branch = self.getBranchYes()
        no_branch = self.getBranchNo()

        # Handle branches that became empty behind our back.
        if yes_branch is not None:
            if not yes_branch.getStatements():
                yes_branch = None
        if no_branch is not None:
            if not no_branch.getStatements():
                no_branch = None

        # Consider to not remove branches that we know won't be taken.
        if yes_branch is not None and truth_value is False:
            trace_collection.signalChange(
                tags       = "new_statements",
                source_ref = yes_branch.source_ref,
                message    = "Removed conditional branch not taken due to false condition value."
            )

            self.setBranchYes(None)
            yes_branch = None

        if no_branch is not None and truth_value is True:
            trace_collection.signalChange(
                tags       = "new_statements",
                source_ref = no_branch.source_ref,
                message    = "Removed 'else' branch not taken due to true condition value."
            )

            self.setBranchNo(None)
            no_branch = None

        # Continue to execute for yes branch unless we know it's not going to be
        # relevant.
        if yes_branch is not None:
            branch_yes_collection = TraceCollectionBranch(
                parent = trace_collection,
                name   = "conditional yes branch",
            )

            branch_yes_collection.computeBranch(
                branch = yes_branch
            )

            # May have just gone away, so fetch it again.
            yes_branch = self.getBranchYes()

            # If it's aborting, it doesn't contribute to merging.
            if yes_branch is None or yes_branch.isStatementAborting():
                branch_yes_collection = None
        else:
            branch_yes_collection = None

        # Continue to execute for yes branch.
        if no_branch is not None:
            branch_no_collection = TraceCollectionBranch(
                parent = trace_collection,
                name   = "conditional no branch"
            )

            branch_no_collection.computeBranch(
                branch = no_branch
            )

            # May have just gone away, so fetch it again.
            no_branch = self.getBranchNo()

            # If it's aborting, it doesn't contribute to merging.
            if no_branch is None or no_branch.isStatementAborting():
                branch_no_collection = None
        else:
            branch_no_collection = None

        # Merge into parent execution.
        self.merge_traces = trace_collection.mergeBranches(
            branch_yes_collection,
            branch_no_collection
        )

        # Both branches may have become empty, which case, the statement needs
        # not remain.
        if yes_branch is None and no_branch is None:
            # Need to keep the boolean check.
            if truth_value is None:
                condition = ExpressionBuiltinBool(
                    value      = condition,
                    source_ref = condition.getSourceReference()
                )

            if condition.mayHaveSideEffects():
                # With both branches eliminated, the condition remains as a side
                # effect.
                result = makeStatementExpressionOnlyReplacementNode(
                    expression = condition,
                    node       = self
                )

                return result, "new_statements", """\
Both branches have no effect, reduced to evaluate condition."""
            else:
                return None, "new_statements", """\
Removed conditional statement without effect."""

        # Note: Checking the condition late, so that the surviving branch got
        # processed already. Returning without doing that, will corrupt the SSA
        # results. TODO: Could pretend the other branch didn't exist to save
        # complexity the merging of processing.
        if truth_value is not None:
            if truth_value is True:
                choice = "true"

                new_statement = self.getBranchYes()
            else:
                choice = "false"

                new_statement = self.getBranchNo()

            new_statement = wrapStatementWithSideEffects(
                new_node   = new_statement,
                old_node   = condition,
                allow_none = True # surviving branch may empty
            )

            return new_statement, "new_statements", """\
Condition for branch was predicted to be always %s.""" % choice

        # If there is no "yes" branch, remove that. Maybe a bad idea though.
        if yes_branch is None:
            # Would be eliminated already, if there wasn't any "no" branch
            # either.
            assert no_branch is not None

            from .OperatorNodes import ExpressionOperationNOT

            new_statement = StatementConditional(
                condition  = ExpressionOperationNOT(
                    operand    = condition,
                    source_ref = condition.getSourceReference()
                ),
                yes_branch = no_branch,
                no_branch  = None,
                source_ref = self.getSourceReference()
            )

            return new_statement, "new_statements", """\
Empty 'yes' branch for conditional statement treated with inverted condition check."""

        return self, None, None
示例#5
0
    def computeExpressionRaw(self, trace_collection):
        # Query the truth value after the expression is evaluated, once it is
        # evaluated in onExpression, it is known.
        trace_collection.onExpression(
            expression = self.getLeft()
        )
        left = self.getLeft()

        left_may_raise = left.mayRaiseException(BaseException)

        if left_may_raise:
            trace_collection.onExceptionRaiseExit(
                BaseException
            )
        # No need to look any further, if the condition raises, the branches do
        # not matter at all.
        if left.willRaiseException(BaseException):
            return left, "new_raise", """\
Conditional %s statements already raises implicitly in condition, removing \
branches.""" % self.conditional_kind

        if not left_may_raise and left.mayRaiseExceptionBool(BaseException):
            trace_collection.onExceptionRaiseExit(
                BaseException
            )

        # Decide this based on truth value of condition.
        truth_value = left.getTruthValue()

        truth_value_use_left = self.conditional_kind == "or"
        truth_value_use_right = not truth_value_use_left

        right = self.getRight()

        # Continue to execute for yes branch unless we know it's not going to be
        # relevant.
        if truth_value is not truth_value_use_left:
            # TODO: We now know that left evaluates and we should tell the
            # branch that.
            branch_yes_collection = TraceCollectionBranch(
                parent = trace_collection,
                name   = "boolean %s right branch" % self.conditional_kind
            )

            branch_yes_collection.computeBranch(
                branch = right
            )

            # May have just gone away, so fetch it again.
            right = self.getRight()

            # If it's aborting, it doesn't contribute to merging.
            if right.willRaiseException(BaseException):
                branch_yes_collection = None
        else:
            branch_yes_collection = None


        if branch_yes_collection:
            # Merge into parent execution.
            self.merge_traces = trace_collection.mergeBranches(
                branch_yes_collection,
                None
            )
        else:
            self.merge_traces = None

        if truth_value is truth_value_use_left:
            return (
                left,
                "new_expression",
                "Conditional '%s' expression predicted to left value." % self.conditional_kind
            )
        elif truth_value is truth_value_use_right:
            return (
                wrapExpressionWithNodeSideEffects(
                    new_node = right,
                    old_node = left
                ),
                "new_expression",
                "Conditional '%s' expression predicted right value." % self.conditional_kind
            )
        else:
            return self, None, None
示例#6
0
    def computeExpressionRaw(self, trace_collection):
        # This is rather complex stuff, pylint: disable=too-many-branches

        # Query the truth value after the expression is evaluated, once it is
        # evaluated in onExpression, it is known.
        condition = trace_collection.onExpression(
            expression=self.subnode_condition)

        # No need to look any further, if the condition raises, the branches do
        # not matter at all.
        if condition.willRaiseException(BaseException):
            return (
                condition,
                "new_raise",
                """\
Conditional expression already raises implicitly in condition, removing \
branches.""",
            )

        # Tell it we are evaluation it for boolean value only, it may demote
        # itself possibly.
        condition.computeExpressionBool(trace_collection)
        condition = self.subnode_condition

        # Decide this based on truth value of condition.
        truth_value = condition.getTruthValue()

        # TODO: We now know that condition evaluates to true for the yes branch
        # and to not true for no branch, the branch should know that.
        yes_branch = self.subnode_expression_yes

        # Continue to execute for yes branch unless we know it's not going to be
        # relevant.
        if truth_value is not False:
            branch_yes_collection = TraceCollectionBranch(
                parent=trace_collection,
                name="conditional expression yes branch")

            branch_yes_collection.computeBranch(branch=yes_branch)

            # May have just gone away, so fetch it again.
            yes_branch = self.subnode_expression_yes

            # If it's aborting, it doesn't contribute to merging.
            if yes_branch.willRaiseException(BaseException):
                branch_yes_collection = None
        else:
            branch_yes_collection = None

        no_branch = self.subnode_expression_no

        # Continue to execute for yes branch.
        if truth_value is not True:
            branch_no_collection = TraceCollectionBranch(
                parent=trace_collection,
                name="conditional expression no branch")

            branch_no_collection.computeBranch(branch=no_branch)

            # May have just gone away, so fetch it again.
            no_branch = self.subnode_expression_no

            # If it's aborting, it doesn't contribute to merging.
            if no_branch.willRaiseException(BaseException):
                branch_no_collection = None
        else:
            branch_no_collection = None

        if truth_value is True:
            trace_collection.replaceBranch(branch_yes_collection)
        elif truth_value is False:
            trace_collection.replaceBranch(branch_no_collection)
        else:
            # Merge into parent execution.
            trace_collection.mergeBranches(branch_yes_collection,
                                           branch_no_collection)

        if truth_value is True:
            return (
                wrapExpressionWithNodeSideEffects(
                    new_node=self.subnode_expression_yes, old_node=condition),
                "new_expression",
                "Conditional expression predicted to yes case.",
            )
        elif truth_value is False:
            return (
                wrapExpressionWithNodeSideEffects(
                    new_node=self.subnode_expression_no, old_node=condition),
                "new_expression",
                "Conditional expression predicted to no case.",
            )
        else:
            return self, None, None
示例#7
0
    def computeExpressionRaw(self, trace_collection):
        # This is rather complex stuff, pylint: disable=too-many-branches

        # Query the truth value after the expression is evaluated, once it is
        # evaluated in onExpression, it is known.
        trace_collection.onExpression(expression=self.getCondition())
        condition = self.getCondition()

        # No need to look any further, if the condition raises, the branches do
        # not matter at all.
        if condition.willRaiseException(BaseException):
            return (
                condition,
                "new_raise",
                """\
Conditional expression already raises implicitly in condition, removing \
branches.""",
            )

        # Tell it we are evaluation it for boolean value only, it may demote
        # itself possibly.
        condition.computeExpressionBool(trace_collection)
        condition = self.getCondition()

        # Decide this based on truth value of condition.
        truth_value = condition.getTruthValue()

        # TODO: We now know that condition evaluates to true for the yes branch
        # and to not true for no branch, the branch should know that.
        yes_branch = self.getExpressionYes()

        # Continue to execute for yes branch unless we know it's not going to be
        # relevant.
        if truth_value is not False:
            branch_yes_collection = TraceCollectionBranch(
                parent=trace_collection, name="conditional expression yes branch"
            )

            branch_yes_collection.computeBranch(branch=yes_branch)

            # May have just gone away, so fetch it again.
            yes_branch = self.getExpressionYes()

            # If it's aborting, it doesn't contribute to merging.
            if yes_branch.willRaiseException(BaseException):
                branch_yes_collection = None
        else:
            branch_yes_collection = None

        no_branch = self.getExpressionNo()

        # Continue to execute for yes branch.
        if truth_value is not True:
            branch_no_collection = TraceCollectionBranch(
                parent=trace_collection, name="conditional expression no branch"
            )

            branch_no_collection.computeBranch(branch=no_branch)

            # May have just gone away, so fetch it again.
            no_branch = self.getExpressionNo()

            # If it's aborting, it doesn't contribute to merging.
            if no_branch.willRaiseException(BaseException):
                branch_no_collection = None
        else:
            branch_no_collection = None

        if truth_value is True:
            trace_collection.replaceBranch(branch_yes_collection)
        elif truth_value is False:
            trace_collection.replaceBranch(branch_no_collection)
        else:
            # Merge into parent execution.
            trace_collection.mergeBranches(branch_yes_collection, branch_no_collection)

        if truth_value is True:
            return (
                wrapExpressionWithNodeSideEffects(
                    new_node=self.getExpressionYes(), old_node=condition
                ),
                "new_expression",
                "Conditional expression predicted to yes case.",
            )
        elif truth_value is False:
            return (
                wrapExpressionWithNodeSideEffects(
                    new_node=self.getExpressionNo(), old_node=condition
                ),
                "new_expression",
                "Conditional expression predicted to no case.",
            )
        else:
            return self, None, None
示例#8
0
    def computeStatement(self, trace_collection):
        # This is rather complex stuff, pylint: disable=too-many-branches,too-many-statements

        trace_collection.onExpression(expression=self.getCondition())
        condition = self.getCondition()

        # No need to look any further, if the condition raises, the branches do
        # not matter at all.
        if condition.willRaiseException(BaseException):
            result = makeStatementExpressionOnlyReplacementNode(
                expression=condition, node=self
            )

            return (
                result,
                "new_raise",
                """\
Conditional statements already raises implicitly in condition, removing \
branches.""",
            )

        # Tell it we are evaluation it for boolean value only, it may demote
        # itself possibly.
        condition.computeExpressionBool(trace_collection)
        condition = self.getCondition()

        # Query the truth value after the expression is evaluated, once it is
        # evaluated in onExpression, it is known.
        truth_value = condition.getTruthValue()

        # TODO: We now know that condition evaluates to true for the yes branch
        # and to not true for no branch, the branch collection should know that.
        yes_branch = self.getBranchYes()
        no_branch = self.getBranchNo()

        # Handle branches that became empty behind our back.
        if yes_branch is not None:
            if not yes_branch.getStatements():
                yes_branch.finalize()
                yes_branch = None

                self.setBranchYes(None)

        if no_branch is not None:
            if not no_branch.getStatements():
                no_branch.finalize()
                no_branch = None

                self.setBranchNo(None)

        # Consider to not remove branches that we know won't be taken.
        if yes_branch is not None and truth_value is False:
            trace_collection.signalChange(
                tags="new_statements",
                source_ref=yes_branch.source_ref,
                message="Removed conditional branch not taken due to false condition value.",
            )

            yes_branch.finalize()
            self.setBranchYes(None)
            yes_branch = None

        if no_branch is not None and truth_value is True:
            trace_collection.signalChange(
                tags="new_statements",
                source_ref=no_branch.source_ref,
                message="Removed 'else' branch not taken due to true condition value.",
            )

            no_branch.finalize()
            self.setBranchNo(None)
            no_branch = None

        # Continue to execute for yes branch unless we know it's not going to be
        # relevant.
        if yes_branch is not None:
            branch_yes_collection = TraceCollectionBranch(
                parent=trace_collection, name="conditional yes branch"
            )

            branch_yes_collection.computeBranch(branch=yes_branch)

            # May have just gone away, so fetch it again.
            yes_branch = self.getBranchYes()

            # If it's aborting, it doesn't contribute to merging.
            if yes_branch is None or yes_branch.isStatementAborting():
                branch_yes_collection = None
        else:
            branch_yes_collection = None

        # Continue to execute for yes branch.
        if no_branch is not None:
            branch_no_collection = TraceCollectionBranch(
                parent=trace_collection, name="conditional no branch"
            )

            branch_no_collection.computeBranch(branch=no_branch)

            # May have just gone away, so fetch it again.
            no_branch = self.getBranchNo()

            # If it's aborting, it doesn't contribute to merging.
            if no_branch is None or no_branch.isStatementAborting():
                branch_no_collection = None
        else:
            branch_no_collection = None

        if truth_value is True:
            if branch_yes_collection is not None:
                trace_collection.replaceBranch(branch_yes_collection)
        elif truth_value is False:
            if branch_no_collection is not None:
                trace_collection.replaceBranch(branch_no_collection)
        else:
            trace_collection.mergeBranches(branch_yes_collection, branch_no_collection)

        # Both branches may have become empty, which case, the statement needs
        # not remain.
        if yes_branch is None and no_branch is None:
            # Need to keep the boolean check.
            if truth_value is None:
                condition = ExpressionBuiltinBool(
                    value=condition, source_ref=condition.getSourceReference()
                )

            if condition.mayHaveSideEffects():
                # With both branches eliminated, the condition remains as a side
                # effect.
                result = makeStatementExpressionOnlyReplacementNode(
                    expression=condition, node=self
                )

                del self.parent

                return (
                    result,
                    "new_statements",
                    """\
Both branches have no effect, reduced to evaluate condition.""",
                )
            else:
                self.finalize()

                return (
                    None,
                    "new_statements",
                    """\
Removed conditional statement without effect.""",
                )

        # Note: Checking the condition late, so that the surviving branch got
        # processed already. Returning without doing that, will corrupt the SSA
        # results. TODO: Could pretend the other branch didn't exist to save
        # complexity the merging of processing.
        if truth_value is not None:
            if truth_value is True:
                choice = "true"

                new_statement = yes_branch
                if no_branch is not None:
                    no_branch.finalize()
            else:
                choice = "false"

                new_statement = no_branch
                if yes_branch is not None:
                    yes_branch.finalize()

            new_statement = wrapStatementWithSideEffects(
                new_node=new_statement,
                old_node=condition,
                allow_none=True,  # surviving branch may empty
            )

            del self.parent

            return (
                new_statement,
                "new_statements",
                """\
Condition for branch statement was predicted to be always %s."""
                % choice,
            )

        # If there is no "yes" branch, remove that. Maybe a bad idea though.
        if yes_branch is None:
            # Would be eliminated already, if there wasn't any "no" branch
            # either.
            assert no_branch is not None

            new_statement = makeStatementConditional(
                condition=ExpressionOperationNOT(
                    operand=condition, source_ref=condition.getSourceReference()
                ),
                yes_branch=no_branch,
                no_branch=None,
                source_ref=self.getSourceReference(),
            )

            del self.parent

            return (
                new_statement,
                "new_statements",
                """\
Empty 'yes' branch for conditional statement treated with inverted condition check.""",
            )

        return self, None, None
示例#9
0
    def computeExpressionRaw(self, trace_collection):
        # Query the truth value after the expression is evaluated, once it is
        # evaluated in onExpression, it is known.
        trace_collection.onExpression(expression=self.getLeft())
        left = self.getLeft()

        # No need to look any further, if the condition raises, the branches do
        # not matter at all.
        if left.willRaiseException(BaseException):
            return (
                left,
                "new_raise",
                """\
Conditional %s statements already raises implicitly in condition, removing \
branches."""
                % self.conditional_kind,
            )

        if not left.mayRaiseException(BaseException) and left.mayRaiseExceptionBool(
            BaseException
        ):
            trace_collection.onExceptionRaiseExit(BaseException)

        # Decide this based on truth value of condition.
        truth_value = left.getTruthValue()

        truth_value_use_left = self.conditional_kind == "or"
        truth_value_use_right = not truth_value_use_left

        right = self.getRight()

        # Continue to execute for yes branch unless we know it's not going to be
        # relevant.
        if truth_value is not truth_value_use_left:
            # TODO: We now know that left evaluates and we should tell the
            # branch that.
            branch_yes_collection = TraceCollectionBranch(
                parent=trace_collection,
                name="boolean %s right branch" % self.conditional_kind,
            )

            branch_yes_collection.computeBranch(branch=right)

            # May have just gone away, so fetch it again.
            right = self.getRight()

            # If it's aborting, it doesn't contribute to merging.
            if right.willRaiseException(BaseException):
                branch_yes_collection = None
        else:
            branch_yes_collection = None

        if branch_yes_collection:
            # Merge into parent execution.
            trace_collection.mergeBranches(branch_yes_collection, None)

        if truth_value is truth_value_use_left:
            return (
                left,
                "new_expression",
                "Conditional '%s' expression predicted to left value."
                % self.conditional_kind,
            )
        elif truth_value is truth_value_use_right:
            return (
                wrapExpressionWithNodeSideEffects(new_node=right, old_node=left),
                "new_expression",
                "Conditional '%s' expression predicted right value."
                % self.conditional_kind,
            )
        else:
            return self, None, None