+ var va = variable
+ if va.closure.is_break then v.mark_unreash(self)
+ var sig = va.closure.signature
+ var s = process_signature(v, sig, n_id.to_symbol, compute_raw_arguments)
+ if not n_closure_defs.is_empty then
+ process_closures(v, sig, n_id.to_symbol, n_closure_defs.to_a)
+ end
+ if not s then return
+ _prop_signature = sig
+ _stype = sig.return_type
+ _is_typed = true
+ end
+end
+
+redef class AClosureId
+ fun to_symbol: Symbol is abstract
+end
+redef class ASimpleClosureId
+ redef fun to_symbol: Symbol do return n_id.to_symbol
+end
+redef class ABreakClosureId
+ redef fun to_symbol: Symbol do return n_kwbreak.to_symbol
+end
+
+redef class AClosureDef
+ var _closure: nullable MMClosure
+ redef fun closure do return _closure.as(not null)
+
+ # The corresponding escapable object
+ readable var _escapable: nullable EscapableBlock
+
+ var _accept_typing2: Bool = false
+ redef fun accept_typing(v)
+ do
+ # Typing is deferred, wait accept_typing2(v)
+ if _accept_typing2 then super
+ end
+
+ private fun accept_typing2(v: TypingVisitor, esc: EscapableClosure)
+ do
+ _escapable = esc
+
+ var sig = esc.closure.signature
+ if sig.arity != n_ids.length then
+ v.error(self, "Error: {sig.arity} automatic variable names expected, {n_ids.length} found.")
+ return
+ end
+
+ _closure = esc.closure
+
+ v.scope_ctx.push(self)
+ var old_flow_ctx = v.flow_ctx
+ var old_base_flow_ctx = v.base_flow_ctx
+ v.base_flow_ctx = v.flow_ctx
+ variables = new Array[AutoVariable]
+ for i in [0..n_ids.length[ do
+ var va = new AutoVariable(n_ids[i].to_symbol, n_ids[i])
+ variables.add(va)
+ va.stype = sig[i]
+ v.scope_ctx.add_variable(va)
+ end
+
+ _accept_typing2 = true
+ accept_typing(v)
+
+ if v.flow_ctx.unreash == false then
+ if closure.signature.return_type != null then
+ v.error(self, "Control error: Reached end of block (a 'continue' with a value was expected).")
+ else if closure.is_break and esc.break_list != null then
+ v.error(self, "Control error: Reached end of break block (a 'break' with a value was expected).")
+ end
+ end
+ v.flow_ctx = old_flow_ctx
+ v.base_flow_ctx = old_base_flow_ctx
+ v.scope_ctx.pop
+ end
+end
+
+class ATypeCheckExpr
+special AExpr
+ private fun check_expr_cast(v: TypingVisitor, n_expr: AExpr, n_type: AType)
+ do
+ if not v.check_expr(n_expr) then return
+ if not n_type.is_typed then return
+ var etype = n_expr.stype
+ var ttype = n_type.stype
+ if etype == ttype then
+ v.warning(self, "Warning: Expression is already a {ttype}.")
+ else if etype < ttype then
+ v.warning(self, "Warning: Expression is already a {ttype} since it is a {etype}.")
+ else if etype isa MMTypeNone then
+ # ttype is not nullable because of prevous test
+ v.warning(self, "Warning: Expression is null therefore cannot be a {ttype}.")
+ else if etype.is_nullable and etype.as_notnull == ttype then
+ if ttype isa MMTypeFormal and ttype.bound.is_nullable then
+ # No warning in this case since with
+ # type T: nullable A
+ # var x: nullable T
+ # 'x.as(not null)' != 'x.as(T)'
+ # 'x != null' != 'x isa T'
+ else if self isa AIsaExpr then
+ v.warning(self, "Warning: Prefer '!= null'.")
+ else
+ v.warning(self, "Warning: Prefer '.as(not null)'.")
+ end
+ end
+ end
+end
+
+redef class AIsaExpr
+special ATypeCheckExpr
+ redef fun after_typing(v)
+ do
+ check_expr_cast(v, n_expr, n_type)
+ if not n_type.is_typed then return
+ var variable = n_expr.its_variable
+ if variable != null then
+ _if_true_flow_ctx = v.flow_ctx.sub_with(self, variable, n_type.stype)