+
+ 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
+ super 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