syntax: warn on 'while true do' and suggests 'loop'
[nit.git] / src / syntax / typing.nit
index fb4c838..f9fb4a6 100644 (file)
@@ -136,6 +136,9 @@ special AbsSyntaxVisitor
        end
 end
 
+redef class VarVariable
+       redef readable var _is_typed: Bool = false
+end
 
 ###############################################################################
 
@@ -271,7 +274,10 @@ redef class AClosureDecl
                v.base_variable_ctx = v.variable_ctx
                v.variable_ctx = v.variable_ctx.sub(self)
 
-               var escapable = new EscapableClosure(self, variable.closure, null)
+               var blist: nullable Array[AExpr] = null
+               var t = v.local_property.signature.return_type
+               if t != null then blist = new Array[AExpr]
+               var escapable = new EscapableClosure(self, variable.closure, blist)
                _escapable = escapable
                v.escapable_ctx.push(escapable, null)
 
@@ -281,11 +287,14 @@ redef class AClosureDecl
                        if v.variable_ctx.unreash == false then
                                if variable.closure.signature.return_type != null then
                                        v.error(self, "Control error: Reached end of block (a 'continue' with a value was expected).")
-                               else if variable.closure.is_break then
-                                       v.error(self, "Control error: Reached end of break block (an 'abort' was expected).")
+                               else if variable.closure.is_break and escapable.break_list != null then
+                                       v.error(self, "Control error: Reached end of break block (a 'break' with a value was expected).")
                                end
                        end
                end
+               if blist != null then for x in blist do
+                       v.check_conform_expr(x, t)
+               end
 
                old_var_ctx.merge(v.variable_ctx)
                v.variable_ctx = old_var_ctx
@@ -353,18 +362,20 @@ redef class AVardeclExpr
                var va = new VarVariable(n_id.to_symbol, n_id)
                _variable = va
                v.variable_ctx.add(va)
-               if n_expr != null then v.variable_ctx.mark_is_set(va)
+               var ne = n_expr
+               if ne != null then v.variable_ctx.mark_is_set(va)
 
                if n_type != null then
                        if not n_type.is_typed then return
                        va.stype = n_type.stype
-                       if n_expr != null then
-                               v.check_conform_expr(n_expr.as(not null), va.stype)
+                       if ne != null then
+                               v.check_conform_expr(ne, va.stype)
                        end
-               else
-                       if not v.check_expr(n_expr.as(not null)) then return
+               else if ne != null then
+                       if not v.check_expr(ne) then return
                        va.stype = n_expr.stype
                end
+               va._is_typed = true
                _is_typed = true
        end
 end
@@ -529,6 +540,10 @@ redef class AWhileExpr
                v.enter_visit(n_expr)
                v.check_conform_expr(n_expr, v.type_bool)
 
+               if n_expr isa ATrueExpr then
+                       v.warning(self, "Warning: use 'loop' instead of 'while true do'.")
+               end
+
                # Prepare inside context (assert cond)
                v.use_if_true_variable_ctx(n_expr)
 
@@ -1672,8 +1687,8 @@ redef class AClosureDef
                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).")
+                       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.variable_ctx = old_var_ctx