typing: error on foo() when foo is a variable
[nit.git] / src / syntax / typing.nit
index 5795cb6..0fb3def 100644 (file)
@@ -252,7 +252,7 @@ redef class AConcreteInitPropdef
                        var j = 0
                        while j < v.local_class.cshe.direct_greaters.length do
                                var c = v.local_class.cshe.direct_greaters[j]
-                               if c.global.is_interface or c.global.is_enum or c.global.is_mixin then
+                               if c.global.is_interface or c.global.is_enum or c.global.is_extern or c.global.is_mixin then
                                        j += 1
                                else if cur_c != null and (c.cshe <= cur_c or cur_c.global.is_mixin) then
                                        if c == cur_c then j += 1
@@ -277,6 +277,18 @@ redef class AConcreteInitPropdef
        end
 end
 
+redef class AExternInitPropdef
+       redef fun accept_typing(v)
+       do
+               v.explicit_other_init_call = false
+               super
+       end
+       redef fun after_typing(v)
+       do
+               super
+       end
+end
+
 redef class AParam
        redef fun after_typing(v)
        do
@@ -377,6 +389,27 @@ redef class AExpr
 
        # The control flow information if current boolean expression is false
        readable private var _if_false_flow_ctx: nullable FlowContext
+
+       # Wharn in case of superfluous parentheses
+       private fun warn_parentheses(v: AbsSyntaxVisitor)
+       do
+       end
+end
+
+redef class AParExpr
+       redef fun warn_parentheses(v)
+       do
+               v.warning(self, "Warning: superfluous parentheses.")
+       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
@@ -442,6 +475,9 @@ redef class AReturnExpr
                else if e != null and t != null then
                        v.check_conform_expr(e, t)
                end
+               if e != null then
+                       e.warn_parentheses(v)
+               end
                _is_typed = true
        end
 end
@@ -459,12 +495,16 @@ redef class AContinueExpr
                end
 
                var t = esc.continue_stype
-               if n_expr == null and t != null then
+               var e = n_expr
+               if e == null and t != null then
                        v.error(self, "Error: continue with a value required in this block.")
-               else if n_expr != null and t == null then
+               else if e != null and t == null then
                        v.error(self, "Error: continue without value required in this block.")
-               else if n_expr != null and t != null then
-                       v.check_conform_expr(n_expr.as(not null), t)
+               else if e != null and t != null then
+                       v.check_conform_expr(e, t)
+               end
+               if e != null then
+                       e.warn_parentheses(v)
                end
                _is_typed = true
        end
@@ -481,13 +521,17 @@ redef class ABreakExpr
                esc.break_flow_contexts.add(old_flow_ctx)
 
                var bl = esc.break_list
-               if n_expr == null and bl != null then
+               var e = n_expr
+               if e == null and bl != null then
                        v.error(self, "Error: break with a value required in this block.")
-               else if n_expr != null and bl == null then
+               else if e != null and bl == null then
                        v.error(self, "Error: break without value required in this block.")
-               else if n_expr != null and bl != null then
+               else if e != null and bl != null then
                        # Typing check can only be done later
-                       bl.add(n_expr.as(not null))
+                       bl.add(e)
+               end
+               if e != null then
+                       e.warn_parentheses(v)
                end
                _is_typed = true
        end
@@ -563,6 +607,8 @@ redef class AIfExpr
                v.enter_visit(n_expr)
                v.check_conform_expr(n_expr, v.type_bool)
 
+               n_expr.warn_parentheses(v)
+
                # Prepare 'then' context
                var old_flow_ctx = v.flow_ctx
                v.use_if_true_flow_ctx(n_expr)
@@ -603,6 +649,8 @@ redef class AWhileExpr
 
                if n_expr isa ATrueExpr then
                        v.warning(self, "Warning: use 'loop' instead of 'while true do'.")
+               else
+                       n_expr.warn_parentheses(v)
                end
 
                # Prepare inside context (assert cond)
@@ -680,6 +728,7 @@ redef class AForExpr
                        v.error(n_expr, "Type error: 'for' on a nullable expression.")
                        return
                end
+               n_expr.warn_parentheses(v)
 
                # Get iterate
                var iterate_name = once "iterate".to_symbol
@@ -725,6 +774,7 @@ redef class AAssertExpr
                # Process condition
                v.enter_visit(n_expr)
                v.check_conform_expr(n_expr, v.type_bool)
+               n_expr.warn_parentheses(v)
 
                # Process optional 'else' part
                if n_else != null then
@@ -984,7 +1034,7 @@ redef class AOrElseExpr
                # Consider the type of the left operand
                var t = n_expr.stype
                if not t.is_nullable then
-                       v.warning(n_expr, "Warning: left operant of a 'or else' is not a nullable type.")
+                       v.warning(n_expr, "Warning: left operand of a 'or else' is not a nullable type.")
                else
                        t = t.as_notnull
                end
@@ -1069,7 +1119,7 @@ end
 redef class AArrayExpr
        redef fun after_typing(v)
        do
-               var stype = v.check_conform_multiexpr(null, n_exprs)
+               var stype = v.check_conform_multiexpr(null, n_exprs.n_exprs)
                if stype != null then do_typing(v, stype)
        end
 
@@ -1127,7 +1177,7 @@ redef class ASuperExpr
                        assert p isa MMMethod
                        _init_in_superclass = p
                        register_super_init_call(v, p)
-                       if n_args.length > 0 then
+                       if n_args.n_exprs.length > 0 then
                                var signature = get_signature(v, v.self_var.stype.as(not null), p, true)
                                process_signature(v, signature, p.name, compute_raw_arguments)
                        end
@@ -1159,6 +1209,123 @@ redef class ASuperExpr
        end
 end
 
+redef class AExternCall
+       fun target_class_name : nullable Symbol do return null
+       fun target_method_name : Symbol is abstract
+
+       redef fun after_typing(v)
+       do
+               var target_class_name = self.target_class_name
+               var target_method_name = self.target_method_name
+
+               var target_class : MMLocalClass
+               var target_method : MMMethod
+
+               # find class
+               # self.target_class_name can be redef'd by sub-classes
+               if target_class_name == null then
+                       target_class = v.local_property.local_class
+               else
+                       if v.local_property.mmmodule.has_global_class_named( target_class_name ) then
+                               var global_class = v.local_property.mmmodule.global_class_named( target_class_name )
+                               target_class = v.local_property.mmmodule[ global_class ]
+                       else
+                               v.error( self, "Error: class {target_class_name.to_s}, not found." )
+                               return
+                       end
+               end
+
+               if target_class.has_global_property_by_name( target_method_name ) then
+                       var global_property = target_class.get_property_by_name( target_method_name )
+
+                       var target_property = target_class[global_property]
+
+                       if target_property isa MMMethod then
+                               target_method = target_property
+                       else
+                               v.error( self, "Error: property {target_method_name.to_s} is not a method." )
+                               return
+                       end
+               else
+                       v.error( self, "Error: property {target_method_name.to_s} not found in target class." )
+                       return
+               end
+
+               var explicit_import = new MMExplicitImport( target_class, target_method )
+               v.local_property.as(MMSrcMethod).explicit_imports.add( explicit_import )
+       end
+end
+
+redef class ALocalPropExternCall
+       redef fun target_class_name do return null
+       redef fun target_method_name do return n_methid.name.as(not null)
+end
+
+redef class ASuperExternCall
+       redef fun after_typing(v)
+       do
+               var precs: Array[MMLocalProperty] = v.local_property.prhe.direct_greaters
+               if not precs.is_empty then
+                       v.local_property.need_super = true
+               else
+                       v.error(self, "Error: No super method to call for {v.local_property}.")
+                       return
+               end
+       end
+end
+
+redef class AFullPropExternCall
+       redef fun target_class_name do return n_classid.to_symbol
+       redef fun target_method_name do return n_methid.name.as(not null)
+end
+
+redef class AInitPropExternCall
+       redef fun target_class_name do return n_classid.to_symbol
+       redef fun target_method_name do return "init".to_symbol
+end
+
+redef class ACastExternCall
+       fun from_type : MMType is abstract
+       fun to_type : MMType is abstract
+
+       redef fun after_typing(v)
+       do
+               if from_type == to_type
+               then
+                       v.error( self, "Attepting to cast from and to the same type." )
+               end
+
+               var cast = new MMImportedCast( from_type, to_type )
+               var m = v.local_property
+               assert m isa MMMethod
+               m.explicit_casts.add( cast )
+       end
+end
+
+redef class ACastAsExternCall
+       redef fun from_type do return n_from_type.stype
+       redef fun to_type do return n_to_type.stype
+end
+
+redef class AAsNullableExternCall
+       redef fun from_type do return n_type.stype
+       redef fun to_type do return n_type.stype.as_nullable
+end
+
+redef class AAsNotNullableExternCall
+       redef fun from_type
+       do
+               var t = n_type.stype
+               if t.is_nullable
+               then
+                       return t
+               else
+                       return t.as_nullable
+               end
+       end
+       redef fun to_type do return n_type.stype.as_notnull
+end
+
 redef class AAttrFormExpr
        redef fun prop do return _prop.as(not null)
        var _prop: nullable MMAttribute
@@ -1579,7 +1746,7 @@ redef class AEqExpr
 
                if n_expr.stype isa MMTypeNone then
                        if n_expr2.stype isa MMTypeNone then
-                               v.warning(self, "Warning: comparaison between 2 null values.")
+                               v.warning(self, "Warning: comparaison between two null values.")
                        else
                                try_to_isa(v, n_expr2)
                        end
@@ -1610,7 +1777,7 @@ redef class ANeExpr
 
                if n_expr.stype isa MMTypeNone then
                        if n_expr2.stype isa MMTypeNone then
-                               v.warning(self, "Warning: comparaison between 2 null values.")
+                               v.warning(self, "Warning: comparaison between two null values.")
                        else
                                try_to_isa(v, n_expr2)
                        end
@@ -1682,7 +1849,7 @@ redef class ACallFormExpr
                                        n = new AClosureCallExpr.init_aclosurecallexpr(n_id, n_args, n_closure_defs)
                                        n._variable = variable
                                else
-                                       if not n_args.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
@@ -1942,7 +2109,13 @@ redef class AProxyExpr
                _is_typed = true
                if n_expr.is_statement then return
                _stype = n_expr.stype
+               _if_true_flow_ctx = n_expr._if_true_flow_ctx
+               _if_false_flow_ctx = n_expr._if_false_flow_ctx
        end
+
+       redef fun is_self do return n_expr.is_self
+
+       redef fun its_variable do return n_expr.its_variable
 end
 
 redef class AOnceExpr