MCPcopy Index your code
hub / github.com/python/mypy / accept_loop

Method accept_loop

mypy/checker.py:769–828  ·  view source on GitHub ↗

Repeatedly type check a loop body until the frame doesn't change.

(
        self,
        body: Statement,
        else_body: Statement | None = None,
        *,
        exit_condition: Expression | None = None,
        on_enter_body: Callable[[], None] | None = None,
    )

Source from the content-addressed store, hash-verified

767 report_internal_error(err, self.errors.file, stmt.line, self.errors, self.options)
768
769 def accept_loop(
770 self,
771 body: Statement,
772 else_body: Statement | None = None,
773 *,
774 exit_condition: Expression | None = None,
775 on_enter_body: Callable[[], None] | None = None,
776 ) -> None:
777 """Repeatedly type check a loop body until the frame doesn't change."""
778
779 # The outer frame accumulates the results of all iterations:
780 with self.binder.frame_context(can_skip=False, conditional_frame=True):
781 # Check for potential decreases in the number of partial types so as not to stop the
782 # iteration too early:
783 partials_old = sum(len(pts.map) for pts in self.partial_types)
784 # Check if assignment widened the inferred type of a variable; in this case we
785 # need to iterate again (we only do one extra iteration, since this could go
786 # on without bound otherwise)
787 widened_old = len(self.widened_vars)
788
789 iter_errors = IterationDependentErrors()
790 iter = 1
791 while True:
792 with self.binder.frame_context(can_skip=True, break_frame=2, continue_frame=1):
793 if on_enter_body is not None:
794 on_enter_body()
795
796 with IterationErrorWatcher(self.msg.errors, iter_errors):
797 self.accept(body)
798
799 partials_new = sum(len(pts.map) for pts in self.partial_types)
800 widened_new = len(self.widened_vars)
801 # Perform multiple iterations if something changed that might affect
802 # inferred types. Also limit the number of iterations. The limits are
803 # somewhat arbitrary, but they were chosen to 1) avoid slowdown from
804 # multiple iterations in common cases and 2) support common, valid use
805 # cases. Limits are needed since otherwise we could infer infinitely
806 # complex types.
807 if (
808 (partials_new == partials_old)
809 and (not self.binder.last_pop_changed or iter > 3)
810 and (widened_new == widened_old or iter > 1)
811 ):
812 break
813 partials_old = partials_new
814 widened_old = widened_new
815 iter += 1
816 if iter == 20:
817 raise RuntimeError("Too many iterations when checking a loop")
818
819 self.msg.iteration_dependent_errors(iter_errors)
820
821 # If exit_condition is set, assume it must be False on exit from the loop:
822 if exit_condition:
823 _, else_map = self.find_isinstance_check(exit_condition)
824 self.push_type_map(else_map)
825
826 # Check the else body:

Callers 2

visit_while_stmtMethod · 0.95
visit_for_stmtMethod · 0.95

Calls 10

acceptMethod · 0.95
find_isinstance_checkMethod · 0.95
push_type_mapMethod · 0.95
sumFunction · 0.85
lenFunction · 0.85
RuntimeErrorClass · 0.85
frame_contextMethod · 0.80

Tested by

no test coverage detected