+ v.mark_unreash(self)
+ _is_typed = true
+ end
+end
+
+# An abstract control structure with feature escapable block
+class AAbsControl
+special AExpr
+ # The corresponding escapable block
+ readable var _escapable: nullable EscapableBlock
+
+ # Enter and process a control structure
+ private fun process_control(v: TypingVisitor, escapable: EscapableBlock, n_label: nullable ALabel, is_loop: Bool)
+ do
+ # Register the escapable block
+ _escapable = escapable
+ v.scope_ctx.push_escapable(escapable, n_label)
+
+ # Save an prepare the contextes
+ var old_flow_ctx = v.flow_ctx
+ var old_base_flow_ctx = v.base_flow_ctx
+ if is_loop then v.base_flow_ctx = v.flow_ctx
+
+ # Do the main processing
+ process_control_inside(v)
+
+ # Add the end of the block as an exit context
+ if not v.flow_ctx.unreash then
+ escapable.break_flow_contexts.add(v.flow_ctx)
+ end
+
+ # Merge all exit contexts
+ if escapable.break_flow_contexts.is_empty then
+ v.flow_ctx = old_flow_ctx
+ v.mark_unreash(self)
+ else
+ v.flow_ctx = old_base_flow_ctx.merge(self, escapable.break_flow_contexts)
+ end
+
+ if is_loop then v.base_flow_ctx = old_base_flow_ctx
+ v.scope_ctx.pop
+ _is_typed = true
+ end
+
+ # What to do inside the control block?
+ private fun process_control_inside(v: TypingVisitor) is abstract
+end
+
+redef class ADoExpr
+special AAbsControl
+ redef fun accept_typing(v)
+ do
+ process_control(v, new BreakOnlyEscapableBlock(self), n_label, false)
+ end
+
+ redef fun process_control_inside(v)
+ do
+ v.enter_visit_block(n_block)