+redef class AClosureCallExpr
+special AAbsAbsSendExpr
+ attr _variable: nullable ClosureVariable
+ redef meth variable do return _variable.as(not null)
+
+ redef meth after_typing(v)
+ do
+ var va = variable
+ if va.closure.is_break then v.variable_ctx.unreash = true
+ var sig = va.closure.signature
+ var args = process_signature(v, sig, n_id.to_symbol, n_args.to_a)
+ if not n_closure_defs.is_empty then
+ process_closures(v, sig, n_id.to_symbol, n_closure_defs.to_a)
+ end
+ if args == null then return
+ _prop_signature = sig
+ _arguments = args
+ _stype = sig.return_type
+ _is_typed = true
+ end
+end
+
+redef class PClosureDef
+ attr _closure: nullable MMClosure
+ redef meth closure do return _closure.as(not null)
+
+ # The corresponding escapable object
+ readable attr _escapable: nullable EscapableBlock
+
+ attr _accept_typing2: Bool = false
+ redef meth accept_typing(v)
+ do
+ # Typing is deferred, wait accept_typing2(v)
+ if _accept_typing2 then super
+ end
+
+ private meth accept_typing2(v: TypingVisitor, esc: EscapableClosure) is abstract
+end
+
+redef class AClosureDef
+ redef meth accept_typing2(v, esc)
+ do
+ _escapable = esc
+
+ var sig = esc.closure.signature
+ if sig.arity != n_id.length then
+ v.error(self, "Error: {sig.arity} automatic variable names expected, {n_id.length} found.")
+ return
+ end
+
+ _closure = esc.closure
+
+ var old_var_ctx = v.variable_ctx
+ var old_base_var_ctx = v.base_variable_ctx
+ v.base_variable_ctx = v.variable_ctx
+ v.variable_ctx = v.variable_ctx.sub(self)
+ variables = new Array[AutoVariable]
+ for i in [0..n_id.length[ do
+ var va = new AutoVariable(n_id[i].to_symbol, self)
+ variables.add(va)
+ va.stype = sig[i]
+ v.variable_ctx.add(va)
+ end
+
+ _accept_typing2 = true
+ accept_typing(v)
+
+ if v.variable_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 then
+ v.error(self, "Control error: Reached end of break block (a 'break' was expected).")
+ end
+ end
+ v.variable_ctx = old_var_ctx
+ v.base_variable_ctx = old_base_var_ctx
+ end
+end
+
+class ATypeCheckExpr
+special PExpr
+ private meth check_expr_cast(v: TypingVisitor, n_expr: PExpr, n_type: PType)
+ do
+ if not v.check_expr(n_expr) 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.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
+