nitc: handle the new `implies` operator
[nit.git] / src / syntax / typing.nit
index 77f9779..18fc645 100644 (file)
@@ -40,7 +40,7 @@ private class TypingVisitor
        super AbsSyntaxVisitor
        redef fun visit(n)
        do
-               if n != null then n.accept_typing(self)
+               n.accept_typing(self)
        end
 
        # Current knowledge about scoped things (variable, labels, etc.)
@@ -289,6 +289,15 @@ redef class AExternInitPropdef
        end
 end
 
+redef class ASignature
+       redef fun after_typing(v)
+       do
+               if self.n_opar != null and self.n_params.is_empty then
+                       v.warning(self, "Warning: superfluous parentheses.")
+               end
+       end
+end
+
 redef class AParam
        redef fun after_typing(v)
        do
@@ -403,6 +412,15 @@ redef class AParExpr
        end
 end
 
+redef class AParExprs
+       redef fun after_typing(v)
+       do
+               if n_exprs.is_empty then
+                       v.warning(self, "Warning: superfluous parentheses.")
+               end
+       end
+end
+
 redef class AVardeclExpr
        var _variable: nullable VarVariable
        redef fun variable do return _variable.as(not null)
@@ -423,7 +441,13 @@ redef class AVardeclExpr
                        end
                else if ne != null then
                        if not v.check_expr(ne) then return
-                       va.stype = ne.stype
+                       var st = ne.stype
+                       if st isa MMTypeNone then
+                               va.stype = v.type_object.as_nullable
+                               v.flow_ctx = v.flow_ctx.sub_with(self, va, st)
+                       else
+                               va.stype = st
+                       end
                else
                        va.stype = v.type_object.as_nullable
                end
@@ -537,7 +561,7 @@ redef class AAbortExpr
 end
 
 # An abstract control structure with feature escapable block
-class AAbsControl
+abstract class AAbsControl
        super AExpr
        # The corresponding escapable block
        readable var _escapable: nullable EscapableBlock
@@ -970,6 +994,36 @@ redef class AOrExpr
        end
 end
 
+redef class AImpliesExpr
+       redef fun accept_typing(v)
+       do
+               var old_flow_ctx = v.flow_ctx
+               var stype = v.type_bool
+               _stype = stype
+
+               # Process left operand
+               v.enter_visit(n_expr)
+
+               # Prepare right operand context
+               v.use_if_true_flow_ctx(n_expr)
+
+               # Process right operand
+               v.enter_visit(n_expr2)
+               if n_expr2.if_false_flow_ctx != null then
+                       _if_false_flow_ctx = n_expr2.if_false_flow_ctx
+               else
+                       _if_false_flow_ctx = v.flow_ctx
+               end
+
+               v.flow_ctx = old_flow_ctx
+
+               v.check_conform_expr(n_expr, stype)
+               v.check_conform_expr(n_expr2, stype)
+               _stype = stype
+               _is_typed = true
+       end
+end
+
 redef class AAndExpr
        redef fun accept_typing(v)
        do
@@ -1538,7 +1592,7 @@ redef class AAbsSendExpr
                var lc = type_recv.local_class
                var prop: nullable MMMethod = null
                if lc.has_global_property_by_name(name) then prop = lc.select_method(name)
-               if prop == null and v.local_property.global.is_init then
+               if prop == null then
                        var props = lc.super_methods_named(name)
                        if props.length > 1 then
                                v.error(self, "Error: Ambigous method name '{name}' for {props.join(", ")}. Use explicit designation.")
@@ -1604,9 +1658,6 @@ redef class ASuperInitCall
                                if c == prev_class then
                                        prev_class = null
                                else if c == cla then
-                                       if prev_class != null then
-                                               v.error(self, "Error: Constructor of {c} must be invoked before constructor of {prev_class}")
-                                       end
                                        esic.add(property)
                                        break
                                end
@@ -1626,6 +1677,9 @@ redef class ANewExpr
                        v.error(self, "Error: try to instantiate abstract class {t.local_class}.")
                        return
                end
+               if t.is_nullable then
+                       v.error(self, "Type error: cannot instantiate the nullable type {t}.")
+               end
                var name: Symbol
                if n_id == null then
                        name = once "init".to_symbol
@@ -1640,6 +1694,10 @@ redef class ANewExpr
                        v.error(self, "Error: {prop} is not a constructor.")
                        return
                end
+               if not prop.global.is_init_for(t.local_class) then
+                       v.error(self, "Error: {prop} is not a constructor in {t.local_class}.")
+                       return
+               end
                _stype = t
                _is_typed = true
        end
@@ -1840,7 +1898,7 @@ redef class ACallFormExpr
                                        n = new AClosureCallExpr.init_aclosurecallexpr(n_id, n_args, n_closure_defs)
                                        n._variable = variable
                                else
-                                       if not n_args.n_exprs.is_empty then
+                                       if not n_args.n_exprs.is_empty or n_args isa AParExprs then
                                                v.error(self, "Error: {name} is variable, not a function.")
                                                return
                                        end
@@ -2020,7 +2078,7 @@ redef class AClosureDef
        end
 end
 
-class ATypeCheckExpr
+abstract class ATypeCheckExpr
        super AExpr
        private fun check_expr_cast(v: TypingVisitor, n_expr: AExpr, n_type: AType)
        do
@@ -2031,7 +2089,10 @@ class ATypeCheckExpr
                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}.")
+                       if not ttype.has_formal and not etype.has_formal then
+                               # the old metamodel is not that great with formal types
+                               v.warning(self, "Warning: Expression is already a {ttype} since it is a {etype}.")
+                       end
                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}.")
@@ -2123,3 +2184,15 @@ redef class AOnceExpr
        end
 end
 
+redef class ADebugTypeExpr
+       redef fun after_typing(v)
+       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 a {etype}, expected {ttype}.")
+               end
+       end
+end