src: add phase.nit & frontend.nit
[nit.git] / src / modelbuilder.nit
index f37a940..f12fc5c 100644 (file)
@@ -27,6 +27,7 @@ import model
 import poset
 import opts
 import toolcontext
+import phase
 
 ###
 
@@ -45,6 +46,9 @@ redef class ToolContext
                super
                option_context.add_option(opt_path, opt_only_parse, opt_only_metamodel)
        end
+
+       fun modelbuilder: ModelBuilder do return modelbuilder_real.as(not null)
+       private var modelbuilder_real: nullable ModelBuilder = null
 end
 
 # A model builder knows how to load nit source files and build the associated model
@@ -57,22 +61,35 @@ class ModelBuilder
        # The toolcontext used to control the interaction with the user (getting options and displaying messages)
        var toolcontext: ToolContext
 
+       fun run_phases
+       do
+               var mmodules = model.mmodules.to_a
+               model.mmodule_importation_hierarchy.sort(mmodules)
+               var nmodules = new Array[AModule]
+               for mm in mmodules do
+                       nmodules.add(mmodule2nmodule[mm])
+               end
+               toolcontext.run_phases(nmodules)
+       end
+
        # Instantiate a modelbuilder for a model and a toolcontext
        # Important, the options of the toolcontext must be correctly set (parse_option already called)
        init(model: Model, toolcontext: ToolContext)
        do
                self.model = model
                self.toolcontext = toolcontext
+               assert toolcontext.modelbuilder_real == null
+               toolcontext.modelbuilder_real = self
 
                # Setup the paths value
                paths.append(toolcontext.opt_path.value)
 
-               var path_env = once ("NIT_PATH".to_symbol).environ
+               var path_env = "NIT_PATH".environ
                if not path_env.is_empty then
                        paths.append(path_env.split_with(':'))
                end
 
-               path_env = once ("NIT_DIR".to_symbol).environ
+               path_env = "NIT_DIR".environ
                if not path_env.is_empty then
                        var libname = "{path_env}/lib"
                        if libname.file_exists then paths.add(libname)
@@ -91,6 +108,27 @@ class ModelBuilder
        # FIXME: Maybe just let the client do the loop (instead of playing with Sequences)
        fun parse_and_build(modules: Sequence[String]): Array[MModule]
        do
+               var mmodules = parse(modules)
+
+               if self.toolcontext.opt_only_parse.value then
+                       self.toolcontext.info("--only-parse: stop processing", 2)
+                       return new Array[MModule]
+               end
+
+               # Build the model
+               var time1 = get_time
+               self.toolcontext.info("*** BUILD MODEL ***", 1)
+               self.build_all_classes
+               var time2 = get_time
+               self.toolcontext.info("*** END BUILD MODEL: {time2-time1} ***", 2)
+
+               self.toolcontext.check_errors
+
+               return mmodules
+       end
+
+       fun parse(modules: Sequence[String]): Array[MModule]
+       do
                var time0 = get_time
                # Parse and recursively load
                self.toolcontext.info("*** PARSE ***", 1)
@@ -104,15 +142,6 @@ class ModelBuilder
                self.toolcontext.info("*** END PARSE: {time1-time0} ***", 2)
 
                self.toolcontext.check_errors
-
-               # Build the model
-               self.toolcontext.info("*** BUILD MODEL ***", 1)
-               self.build_all_classes
-               var time2 = get_time
-               self.toolcontext.info("*** END BUILD MODEL: {time2-time1} ***", 2)
-
-               self.toolcontext.check_errors
-
                return mmodules
        end
 
@@ -220,6 +249,8 @@ class ModelBuilder
                var origmmodule = mmodule
                var modules = model.get_mmodules_by_name(name)
 
+               var tries = new Array[String]
+
                var lastmodule = mmodule
                while mmodule != null do
                        var dirname = mmodule.location.file.filename.dirname
@@ -243,6 +274,7 @@ class ModelBuilder
 
                        # Second, try the directory to find a file
                        var try_file = dirname + "/" + name + ".nit"
+                       tries.add try_file
                        if try_file.file_exists then
                                var res = self.load_module(owner, try_file.simplify_path)
                                if res == null then return null # Forward error
@@ -287,6 +319,7 @@ class ModelBuilder
                var candidate: nullable String = null
                for dirname in lookpaths do
                        var try_file = (dirname + "/" + name + ".nit").simplify_path
+                       tries.add try_file
                        if try_file.file_exists then
                                if candidate == null then
                                        candidate = try_file
@@ -305,9 +338,9 @@ class ModelBuilder
                end
                if candidate == null then
                        if origmmodule != null then
-                               error(anode, "Error: cannot find module {name} from {origmmodule}")
+                               error(anode, "Error: cannot find module {name} from {origmmodule}. tried {tries.join(", ")}")
                        else
-                               error(anode, "Error: cannot find module {name}")
+                               error(anode, "Error: cannot find module {name}. tried {tries.join(", ")}")
                        end
                        return null
                end
@@ -372,6 +405,7 @@ class ModelBuilder
        private fun build_module_importation(nmodule: AModule)
        do
                if nmodule.is_importation_done then return
+               nmodule.is_importation_done = true
                var mmodule = nmodule.mmodule.as(not null)
                var stdimport = true
                var imported_modules = new Array[MModule]
@@ -397,7 +431,6 @@ class ModelBuilder
                end
                self.toolcontext.info("{mmodule} imports {imported_modules.join(", ")}", 3)
                mmodule.set_imported_mmodules(imported_modules)
-               nmodule.is_importation_done = true
        end
 
        # All the loaded modules
@@ -408,6 +441,9 @@ class ModelBuilder
        do
                for nmodule in self.nmodules do
                        build_classes(nmodule)
+                       for nclassdef in nmodule.n_classdefs do
+                               build_properties(nclassdef)
+                       end
                end
        end
 
@@ -449,6 +485,9 @@ class ModelBuilder
                if mclass == null then
                        mclass = new MClass(mmodule, name, arity, mkind, mvisibility)
                        #print "new class {mclass}"
+               else if nclassdef isa AStdClassdef and nmodule.mclass2nclassdef.has_key(mclass) then
+                       error(nclassdef, "Error: A class {name} is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
+                       return
                else if nclassdef isa AStdClassdef and nclassdef.n_kwredef == null then
                        error(nclassdef, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
                        return
@@ -461,6 +500,7 @@ class ModelBuilder
                        error(nvisibility, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
                end
                nclassdef.mclass = mclass
+               nmodule.mclass2nclassdef[mclass] = nclassdef
        end
 
        # Visit the AST and create the MClassDef objects
@@ -468,7 +508,8 @@ class ModelBuilder
        do
                var mmodule = nmodule.mmodule.as(not null)
                var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
-               var mclass = nclassdef.mclass.as(not null)
+               var mclass = nclassdef.mclass
+               if mclass == null then return # Skip error
                #var mclassdef = nclassdef.mclassdef.as(not null)
 
                var names = new Array[String]
@@ -490,7 +531,7 @@ class ModelBuilder
                                var nfd = nclassdef.n_formaldefs[i]
                                var nfdt = nfd.n_type
                                if nfdt != null then
-                                       var bound = resolve_mtype(nclassdef, nfdt)
+                                       var bound = resolve_mtype_unchecked(nclassdef, nfdt, false)
                                        if bound == null then return # Forward error
                                        if bound.need_anchor then
                                                # No F-bounds!
@@ -503,7 +544,7 @@ class ModelBuilder
                                        bounds.add(objectclass.mclass_type.as_nullable)
                                else
                                        # Inherit the bound
-                                       bounds.add(mclass.mclassdefs.first.bound_mtype.as(MGenericType).arguments[i])
+                                       bounds.add(mclass.intro.bound_mtype.arguments[i])
                                end
                        end
                end
@@ -520,8 +561,8 @@ class ModelBuilder
                end
        end
 
-       # Visit the AST and set the super-types of the MClass objects (ie compute the inheritance)
-       private fun build_a_mclassdef_inheritance(nmodule: AModule, nclassdef: AClassdef)
+       # Visit the AST and set the super-types of the MClassdef objects
+       private fun collect_a_mclassdef_inheritance(nmodule: AModule, nclassdef: AClassdef)
        do
                var mmodule = nmodule.mmodule.as(not null)
                var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
@@ -534,7 +575,7 @@ class ModelBuilder
                        for nsc in nclassdef.n_superclasses do
                                specobject = false
                                var ntype = nsc.n_type
-                               var mtype = resolve_mtype(nclassdef, ntype)
+                               var mtype = resolve_mtype_unchecked(nclassdef, ntype, false)
                                if mtype == null then continue # Skip because of error
                                if not mtype isa MClassType then
                                        error(ntype, "Error: supertypes cannot be a formal type")
@@ -553,13 +594,18 @@ class ModelBuilder
        end
 
        # Check the validity of the specialization heirarchy
-       # FIXME Stub implementation
        private fun check_supertypes(nmodule: AModule, nclassdef: AClassdef)
        do
                var mmodule = nmodule.mmodule.as(not null)
                var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
                var mclass = nclassdef.mclass.as(not null)
                var mclassdef = nclassdef.mclassdef.as(not null)
+
+               for s in mclassdef.supertypes do
+                       if s.is_subtype(mmodule, mclassdef.bound_mtype, mclassdef.bound_mtype) then
+                               error(nclassdef, "Error: Inheritance loop for class {mclass} with type {s}")
+                       end
+               end
        end
 
        # Build the classes of the module `nmodule'.
@@ -568,8 +614,10 @@ class ModelBuilder
        do
                # Force building recursively
                if nmodule.build_classes_is_done then return
+               nmodule.build_classes_is_done = true
                var mmodule = nmodule.mmodule.as(not null)
                for imp in mmodule.in_importation.direct_greaters do
+
                        build_classes(mmodule2nmodule[imp])
                end
 
@@ -583,20 +631,52 @@ class ModelBuilder
                        self.build_a_mclassdef(nmodule, nclassdef)
                end
 
+               for nclassdef in nmodule.n_classdefs do
+                       if nclassdef.mclassdef == null then return # forward error
+               end
+
                # Create inheritance on all classdefs
                for nclassdef in nmodule.n_classdefs do
-                       self.build_a_mclassdef_inheritance(nmodule, nclassdef)
+                       self.collect_a_mclassdef_inheritance(nmodule, nclassdef)
                end
 
-               # TODO: Check that the super-class is not intrusive
+               # Create the mclassdef hierarchy
+               for nclassdef in nmodule.n_classdefs do
+                       var mclassdef = nclassdef.mclassdef.as(not null)
+                       mclassdef.add_in_hierarchy
+               end
 
-               # TODO: Check that the super-class is not already known (by transitivity)
+               # Check inheritance
+               for nclassdef in nmodule.n_classdefs do
+                       self.check_supertypes(nmodule, nclassdef)
+               end
 
+               # Check unchecked ntypes
                for nclassdef in nmodule.n_classdefs do
-                       self.build_properties(nclassdef)
+                       if nclassdef isa AStdClassdef then
+                               # check bound of formal parameter
+                               for nfd in  nclassdef.n_formaldefs do
+                                       var nfdt = nfd.n_type
+                                       if nfdt != null and nfdt.mtype != null then
+                                               var bound = resolve_mtype(nclassdef, nfdt)
+                                               if bound == null then return # Forward error
+                                       end
+                               end
+                               # check declared super types
+                               for nsc in nclassdef.n_superclasses do
+                                       var ntype = nsc.n_type
+                                       if ntype.mtype != null then
+                                               var mtype = resolve_mtype(nclassdef, ntype)
+                                               if mtype == null then return # Forward error
+                                       end
+                               end
+                       end
+
                end
 
-               nmodule.build_classes_is_done = true
+               # TODO: Check that the super-class is not intrusive
+
+               # TODO: Check that the super-class is not already known (by transitivity)
        end
 
        # Register the nmodule associated to each mmodule
@@ -615,6 +695,7 @@ class ModelBuilder
        do
                # Force building recursively
                if nclassdef.build_properties_is_done then return
+               nclassdef.build_properties_is_done = true
                var mclassdef = nclassdef.mclassdef.as(not null)
                if mclassdef.in_hierarchy == null then return # Skip error
                for superclassdef in mclassdef.in_hierarchy.direct_greaters do
@@ -631,7 +712,6 @@ class ModelBuilder
                        npropdef.check_signature(self, nclassdef)
                end
                process_default_constructors(nclassdef)
-               nclassdef.build_properties_is_done = true
        end
 
        # Introduce or inherit default constructor
@@ -671,7 +751,7 @@ class ModelBuilder
                        if inhc2 == null then inhc2 = c
                        if inhc2 == inhc then continue
                        if inhc != null then
-                               self.error(nclassdef, "Cannot provide a defaut constructor: conflict for {inhc} and {c}")
+                               self.error(nclassdef, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
                        else
                                inhc = inhc2
                        end
@@ -683,7 +763,7 @@ class ModelBuilder
                        return
                end
                if not combine.is_empty and inhc != null then
-                       self.error(nclassdef, "Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
+                       self.error(nclassdef, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
                        return
                end
 
@@ -691,9 +771,8 @@ class ModelBuilder
                        nclassdef.super_inits = combine
                        var mprop = new MMethod(mclassdef, "init", mclassdef.mclass.visibility)
                        var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
-                       var param_names = new Array[String]
-                       var param_types = new Array[MType]
-                       var msignature = new MSignature(param_names, param_types, null, -1)
+                       var mparameters = new Array[MParameter]
+                       var msignature = new MSignature(mparameters, null)
                        mpropdef.msignature = msignature
                        mprop.is_init = true
                        nclassdef.mfree_init = mpropdef
@@ -702,20 +781,21 @@ class ModelBuilder
                end
 
                # Collect undefined attributes
-               var param_names = new Array[String]
-               var param_types = new Array[MType]
+               var mparameters = new Array[MParameter]
                for npropdef in nclassdef.n_propdefs do
                        if npropdef isa AAttrPropdef and npropdef.n_expr == null then
-                               param_names.add(npropdef.mpropdef.mproperty.name.substring_from(1))
+                               if npropdef.mpropdef == null then return # Skip broken attribute
+                               var paramname = npropdef.mpropdef.mproperty.name.substring_from(1)
                                var ret_type = npropdef.mpropdef.static_mtype
                                if ret_type == null then return
-                               param_types.add(ret_type)
+                               var mparameter = new MParameter(paramname, ret_type, false)
+                               mparameters.add(mparameter)
                        end
                end
 
                var mprop = new MMethod(mclassdef, "init", mclassdef.mclass.visibility)
                var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
-               var msignature = new MSignature(param_names, param_types, null, -1)
+               var msignature = new MSignature(mparameters, null)
                mpropdef.msignature = msignature
                mprop.is_init = true
                nclassdef.mfree_init = mpropdef
@@ -727,7 +807,7 @@ class ModelBuilder
        # The mmodule used as context is `nclassdef.mmodule'
        # In case of problem, an error is displayed on `ntype' and null is returned.
        # FIXME: the name "resolve_mtype" is awful
-       fun resolve_mtype(nclassdef: AClassdef, ntype: AType): nullable MType
+       fun resolve_mtype_unchecked(nclassdef: AClassdef, ntype: AType, with_virtual: Bool): nullable MType
        do
                var name = ntype.n_id.text
                var mclassdef = nclassdef.mclassdef
@@ -735,7 +815,7 @@ class ModelBuilder
                var res: MType
 
                # Check virtual type
-               if mclassdef != null then
+               if mclassdef != null and with_virtual then
                        var prop = try_get_mproperty_by_name(ntype, mclassdef, name).as(nullable MVirtualTypeProp)
                        if prop != null then
                                if not ntype.n_types.is_empty then
@@ -743,6 +823,7 @@ class ModelBuilder
                                end
                                res = prop.mvirtualtype
                                if ntype.n_kwnullable != null then res = res.as_nullable
+                               ntype.mtype = res
                                return res
                        end
                end
@@ -754,8 +835,9 @@ class ModelBuilder
                        end
                        for i in [0..mclassdef.parameter_names.length[ do
                                if mclassdef.parameter_names[i] == name then
-                                       res = mclassdef.mclass.mclass_type.as(MGenericType).arguments[i]
+                                       res = mclassdef.mclass.mclass_type.arguments[i]
                                        if ntype.n_kwnullable != null then res = res.as_nullable
+                                       ntype.mtype = res
                                        return res
                                end
                        end
@@ -779,16 +861,18 @@ class ModelBuilder
                        if arity == 0 then
                                res = mclass.mclass_type
                                if ntype.n_kwnullable != null then res = res.as_nullable
+                               ntype.mtype = res
                                return res
                        else
                                var mtypes = new Array[MType]
                                for nt in ntype.n_types do
-                                       var mt = resolve_mtype(nclassdef, nt)
+                                       var mt = resolve_mtype_unchecked(nclassdef, nt, with_virtual)
                                        if mt == null then return null # Forward error
                                        mtypes.add(mt)
                                end
                                res = mclass.get_mtype(mtypes)
                                if ntype.n_kwnullable != null then res = res.as_nullable
+                               ntype.mtype = res
                                return res
                        end
                end
@@ -798,6 +882,37 @@ class ModelBuilder
                return null
        end
 
+       # Return the static type associated to the node `ntype'.
+       # `classdef' is the context where the call is made (used to understand formal types)
+       # The mmodule used as context is `nclassdef.mmodule'
+       # In case of problem, an error is displayed on `ntype' and null is returned.
+       # FIXME: the name "resolve_mtype" is awful
+       fun resolve_mtype(nclassdef: AClassdef, ntype: AType): nullable MType
+       do
+               var mtype = ntype.mtype
+               if mtype == null then mtype = resolve_mtype_unchecked(nclassdef, ntype, true)
+               if mtype == null then return null # Forward error
+
+               if ntype.checked_mtype then return mtype
+               if mtype isa MGenericType then
+                       var mmodule = nclassdef.parent.as(AModule).mmodule.as(not null)
+                       var mclassdef = nclassdef.mclassdef
+                       var mclass = mtype.mclass
+                       for i in [0..mclass.arity[ do
+                               var bound = mclass.intro.bound_mtype.arguments[i]
+                               var nt = ntype.n_types[i]
+                               var mt = resolve_mtype(nclassdef, nt)
+                               if mt == null then return null # forward error
+                               if not mt.is_subtype(mmodule, mclassdef.bound_mtype, bound) then
+                                       error(nt, "Type error: expected {bound}, got {mt}")
+                                       return null
+                               end
+                       end
+               end
+               ntype.checked_mtype = true
+               return mtype
+       end
+
        # Helper function to display an error on a node.
        # Alias for `self.toolcontext.error(n.hot_location, text)'
        fun error(n: ANode, text: String)
@@ -811,6 +926,17 @@ class ModelBuilder
        do
                self.toolcontext.warning(n.hot_location, text)
        end
+
+       # Force to get the primitive method named `name' on the type `recv' or do a fatal error on `n'
+       fun force_get_primitive_method(n: ANode, name: String, recv: MType, mmodule: MModule): MMethod
+       do
+               var res = mmodule.try_get_primitive_method(name, recv)
+               if res == null then
+                       self.toolcontext.fatal_error(n.hot_location, "Fatal Error: {recv} must have a property named {name}.")
+                       abort
+               end
+               return res
+       end
 end
 
 redef class AModule
@@ -820,6 +946,10 @@ redef class AModule
        var is_importation_done: Bool = false
        # Flag that indicate if the class and prop building is already completed
        var build_classes_is_done: Bool = false
+       # What is the AClassdef associated to a MClass?
+       # Used to check multiple definition of a class.
+       var mclass2nclassdef: Map[MClass, AClassdef] = new HashMap[MClass, AClassdef]
+
 end
 
 redef class MClass
@@ -840,6 +970,10 @@ redef class AClassdef
 
        # The free init (implicitely constructed by the class if required)
        var mfree_init: nullable MMethodDef = null
+
+       # What is the APropdef associated to a MProperty?
+       # Used to check multiple definition of a property.
+       var mprop2npropdef: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
 end
 
 redef class AClasskind
@@ -879,6 +1013,13 @@ redef class APrivateVisibility
        redef fun mvisibility do return private_visibility
 end
 
+redef class AType
+       # The mtype associated to the node
+       var mtype: nullable MType = null
+
+       # Is the mtype a valid one?
+       var checked_mtype: Bool = false
+end
 
 #
 
@@ -941,17 +1082,98 @@ redef class APropdef
                end
        end
 
-       private fun check_redef_keyword(modelbuilder: ModelBuilder, nclassdef: AClassdef, kwredef: nullable Token, need_redef: Bool, mprop: MProperty)
+       private fun check_redef_keyword(modelbuilder: ModelBuilder, nclassdef: AClassdef, kwredef: nullable Token, need_redef: Bool, mprop: MProperty): Bool
        do
+               if nclassdef.mprop2npropdef.has_key(mprop) then
+                       modelbuilder.error(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
+                       return false
+               end
                if kwredef == null then
                        if need_redef then
                                modelbuilder.error(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
+                               return false
                        end
                else
                        if not need_redef then
                                modelbuilder.error(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
+                               return false
                        end
                end
+               return true
+       end
+
+end
+
+redef class ASignature
+       # Is the model builder has correctly visited the signature
+       var is_visited = false
+       # Names of parameters from the AST
+       # REQUIRE: is_visited
+       var param_names = new Array[String]
+       # Types of parameters from the AST
+       # REQUIRE: is_visited
+       var param_types = new Array[MType]
+       # Rank of the vararg (of -1 if none)
+       # REQUIRE: is_visited
+       var vararg_rank: Int = -1
+       # Return type
+       var ret_type: nullable MType = null
+
+       # Visit and fill information about a signature
+       private fun visit_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef): Bool
+       do
+               var param_names = self.param_names
+               var param_types = self.param_types
+               for np in self.n_params do
+                       param_names.add(np.n_id.text)
+                       var ntype = np.n_type
+                       if ntype != null then
+                               var mtype = modelbuilder.resolve_mtype(nclassdef, ntype)
+                               if mtype == null then return false # Skip error
+                               for i in [0..param_names.length-param_types.length[ do
+                                       param_types.add(mtype)
+                               end
+                               if np.n_dotdotdot != null then
+                                       if self.vararg_rank != -1 then
+                                               modelbuilder.error(np, "Error: {param_names[self.vararg_rank]} is already a vararg")
+                                               return false
+                                       else
+                                               self.vararg_rank = param_names.length - 1
+                                       end
+                               end
+                       end
+               end
+               var ntype = self.n_type
+               if ntype != null then
+                       self.ret_type = modelbuilder.resolve_mtype(nclassdef, ntype)
+                       if self.ret_type == null then return false # Skip errir
+               end
+
+               for nclosure in self.n_closure_decls do
+                       if not nclosure.n_signature.visit_signature(modelbuilder, nclassdef) then return false
+               end
+
+               self.is_visited = true
+               return true
+       end
+
+       # Build a visited signature
+       fun build_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef): nullable MSignature
+       do
+               if param_names.length != param_types.length then
+                       # Some parameters are typed, other parameters are not typed.
+                       modelbuilder.error(self.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
+                       return null
+               end
+
+               var mparameters = new Array[MParameter]
+               for i in [0..param_names.length[ do
+                       var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
+                       mparameters.add(mparameter)
+               end
+
+               var msignature = new MSignature(mparameters, ret_type)
+               return msignature
        end
 end
 
@@ -976,7 +1198,7 @@ redef class AMethPropdef
                                name = "init"
                                name_node = self.n_kwinit
                        else if self isa AExternInitPropdef then
-                               name = "new"
+                               name = "init"
                                name_node = self.n_kwnew
                        else
                                abort
@@ -1000,17 +1222,19 @@ redef class AMethPropdef
                        var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility)
                        mprop = new MMethod(mclassdef, name, mvisibility)
                        mprop.is_init = is_init
-                       self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mprop)
+                       mprop.is_new = self isa AExternInitPropdef
+                       if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mprop) then return
                else
                        if n_kwredef == null then
                                if self isa AMainMethPropdef then
                                        # no warning
                                else
-                                       self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mprop)
+                                       if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mprop) then return
                                end
                        end
                        check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop)
                end
+               nclassdef.mprop2npropdef[mprop] = self
 
                var mpropdef = new MMethodDef(mclassdef, mprop, self.location)
 
@@ -1036,29 +1260,11 @@ redef class AMethPropdef
                var vararg_rank = -1
                var ret_type: nullable MType = null # Return type from the AST
                if nsig != null then
-                       for np in nsig.n_params do
-                               param_names.add(np.n_id.text)
-                               var ntype = np.n_type
-                               if ntype != null then
-                                       var mtype = modelbuilder.resolve_mtype(nclassdef, ntype)
-                                       if mtype == null then return # Skip error
-                                       for i in [0..param_names.length-param_types.length[ do
-                                               param_types.add(mtype)
-                                       end
-                                       if np.n_dotdotdot != null then
-                                               if vararg_rank != -1 then
-                                                       modelbuilder.error(np, "Error: {param_names[vararg_rank]} is already a vararg")
-                                               else
-                                                       vararg_rank = param_names.length - 1
-                                               end
-                                       end
-                               end
-                       end
-                       var ntype = nsig.n_type
-                       if ntype != null then
-                               ret_type = modelbuilder.resolve_mtype(nclassdef, ntype)
-                               if ret_type == null then return # Skip errir
-                       end
+                       if not nsig.visit_signature(modelbuilder, nclassdef) then return
+                       param_names = nsig.param_names
+                       param_types = nsig.param_types
+                       vararg_rank = nsig.vararg_rank
+                       ret_type = nsig.ret_type
                end
 
                # Look for some signature to inherit
@@ -1067,6 +1273,14 @@ redef class AMethPropdef
                if not mpropdef.is_intro then
                        msignature = mpropdef.mproperty.intro.msignature
                        if msignature == null then return # Skip error
+
+                       # Check inherited signature arity
+                       if param_names.length != msignature.arity then
+                               var node: ANode
+                               if nsig != null then node = nsig else node = self
+                               modelbuilder.error(node, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
+                               return
+                       end
                else if mpropdef.mproperty.is_init then
                        # FIXME UGLY: inherit signature from a super-constructor
                        for msupertype in nclassdef.mclassdef.supertypes do
@@ -1080,10 +1294,14 @@ redef class AMethPropdef
                        end
                end
 
+
                # Inherit the signature
                if msignature != null and param_names.length != param_types.length and param_names.length == msignature.arity and param_types.length == 0 then
                        # Parameters are untyped, thus inherit them
-                       param_types = msignature.parameter_mtypes
+                       param_types = new Array[MType]
+                       for mparameter in msignature.mparameters do
+                               param_types.add(mparameter.mtype)
+                       end
                        vararg_rank = msignature.vararg_rank
                end
                if msignature != null and ret_type == null then
@@ -1092,12 +1310,28 @@ redef class AMethPropdef
 
                if param_names.length != param_types.length then
                        # Some parameters are typed, other parameters are not typed.
-                       modelbuilder.warning(nsig.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
+                       modelbuilder.error(nsig.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
                        return
                end
 
-               msignature = new MSignature(param_names, param_types, ret_type, vararg_rank)
+               var mparameters = new Array[MParameter]
+               for i in [0..param_names.length[ do
+                       var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
+                       mparameters.add(mparameter)
+               end
+
+               msignature = new MSignature(mparameters, ret_type)
                mpropdef.msignature = msignature
+
+               if nsig != null then
+                       for nclosure in nsig.n_closure_decls do
+                               var clos_signature = nclosure.n_signature.build_signature(modelbuilder, nclassdef)
+                               if clos_signature == null then return
+                               var mparameter = new MParameter(nclosure.n_id.text, clos_signature, false)
+                               msignature.mclosures.add(mparameter)
+                       end
+               end
+
        end
 
        redef fun check_signature(modelbuilder, nclassdef)
@@ -1115,12 +1349,6 @@ redef class AMethPropdef
                        var msignature = mpropdef.mproperty.intro.msignature
                        if msignature == null then return
 
-                       if mysignature.arity != msignature.arity then
-                               var node: ANode
-                               if nsig != null then node = nsig else node = self
-                               modelbuilder.error(node, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
-                               return
-                       end
                        var precursor_ret_type = msignature.return_mtype
                        var ret_type = mysignature.return_mtype
                        if ret_type != null and precursor_ret_type == null then
@@ -1131,11 +1359,11 @@ redef class AMethPropdef
                        if mysignature.arity > 0 then
                                # Check parameters types
                                for i in [0..mysignature.arity[ do
-                                       var myt = mysignature.parameter_mtypes[i]
-                                       var prt = msignature.parameter_mtypes[i]
+                                       var myt = mysignature.mparameters[i].mtype
+                                       var prt = msignature.mparameters[i].mtype
                                        if not myt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, prt) and
                                                        not prt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, myt) then
-                                               modelbuilder.error(nsig.n_params[i], "Redef Error: Wrong type for parameter `{mysignature.parameter_names[i]}'. found {myt}, expected {prt}.")
+                                               modelbuilder.error(nsig.n_params[i], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
                                        end
                                end
                        end
@@ -1174,6 +1402,8 @@ redef class AAttrPropdef
                        modelbuilder.error(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
                else if mclass.kind == enum_kind then
                        modelbuilder.error(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
+               else if mclass.kind == extern_kind then
+                       modelbuilder.error(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
                end
 
                var nid = self.n_id
@@ -1183,12 +1413,14 @@ redef class AAttrPropdef
                        if mprop == null then
                                var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility)
                                mprop = new MAttribute(mclassdef, name, mvisibility)
-                               self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop)
+                               if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop) then return
                        else
                                assert mprop isa MAttribute
                                check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop)
-                               self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop)
+                               if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop) then return
                        end
+                       nclassdef.mprop2npropdef[mprop] = self
+
                        var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
                        self.mpropdef = mpropdef
                        modelbuilder.mpropdef2npropdef[mpropdef] = self
@@ -1200,11 +1432,13 @@ redef class AAttrPropdef
                                if mreadprop == null then
                                        var mvisibility = new_property_visibility(modelbuilder, nclassdef, nreadable.n_visibility)
                                        mreadprop = new MMethod(mclassdef, readname, mvisibility)
-                                       self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, false, mreadprop)
+                                       if not self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, false, mreadprop) then return
                                else
-                                       self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, true, mreadprop)
+                                       if not self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, true, mreadprop) then return
                                        check_redef_property_visibility(modelbuilder, nclassdef, nreadable.n_visibility, mreadprop)
                                end
+                               nclassdef.mprop2npropdef[mreadprop] = self
+
                                var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
                                self.mreadpropdef = mreadpropdef
                                modelbuilder.mpropdef2npropdef[mreadpropdef] = self
@@ -1217,11 +1451,13 @@ redef class AAttrPropdef
                                if mwriteprop == null then
                                        var mvisibility = new_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility)
                                        mwriteprop = new MMethod(mclassdef, writename, mvisibility)
-                                       self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, false, mwriteprop)
+                                       if not self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, false, mwriteprop) then return
                                else
-                                       self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, true, mwriteprop)
+                                       if not self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, true, mwriteprop) then return
                                        check_redef_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility, mwriteprop)
                                end
+                               nclassdef.mprop2npropdef[mwriteprop] = self
+
                                var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
                                self.mwritepropdef = mwritepropdef
                                modelbuilder.mpropdef2npropdef[mwritepropdef] = self
@@ -1239,11 +1475,13 @@ redef class AAttrPropdef
                        if mreadprop == null then
                                var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility)
                                mreadprop = new MMethod(mclassdef, readname, mvisibility)
-                               self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mreadprop)
+                               if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mreadprop) then return
                        else
-                               self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mreadprop)
+                               if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mreadprop) then return
                                check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mreadprop)
                        end
+                       nclassdef.mprop2npropdef[mreadprop] = self
+
                        var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
                        self.mreadpropdef = mreadpropdef
                        modelbuilder.mpropdef2npropdef[mreadpropdef] = self
@@ -1261,13 +1499,15 @@ redef class AAttrPropdef
                                        mvisibility = private_visibility
                                end
                                mwriteprop = new MMethod(mclassdef, writename, mvisibility)
-                               self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, false, mwriteprop)
+                               if not self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, false, mwriteprop) then return
                        else
-                               self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, true, mwriteprop)
+                               if not self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, true, mwriteprop) then return
                                if nwritable != null then
                                        check_redef_property_visibility(modelbuilder, nclassdef, nwritable.n_visibility, mwriteprop)
                                end
                        end
+                       nclassdef.mprop2npropdef[mwriteprop] = self
+
                        var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
                        self.mwritepropdef = mwritepropdef
                        modelbuilder.mpropdef2npropdef[mwritepropdef] = self
@@ -1288,15 +1528,44 @@ redef class AAttrPropdef
                end
 
                if mtype == null then
-                       modelbuilder.warning(self, "Error: Untyped attribute {mpropdef}")
-                       return
+                       var nexpr = self.n_expr
+                       if nexpr != null then
+                               if nexpr isa ANewExpr then
+                                       mtype = modelbuilder.resolve_mtype(nclassdef, nexpr.n_type)
+                               else if nexpr isa AIntExpr then
+                                       var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int")
+                                       if cla != null then mtype = cla.mclass_type
+                               else if nexpr isa AFloatExpr then
+                                       var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Float")
+                                       if cla != null then mtype = cla.mclass_type
+                               else if nexpr isa ACharExpr then
+                                       var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Char")
+                                       if cla != null then mtype = cla.mclass_type
+                               else if nexpr isa ABoolExpr then
+                                       var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Bool")
+                                       if cla != null then mtype = cla.mclass_type
+                               else if nexpr isa ASuperstringExpr then
+                                       var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
+                                       if cla != null then mtype = cla.mclass_type
+                               else if nexpr isa AStringFormExpr then
+                                       var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
+                                       if cla != null then mtype = cla.mclass_type
+                               else
+                                       modelbuilder.error(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
+                               end
+
+                       else
+                               modelbuilder.error(self, "Error: Untyped attribute {mpropdef}")
+                       end
                end
 
+               if mtype == null then return
+
                mpropdef.static_mtype = mtype
 
                var mreadpropdef = self.mreadpropdef
                if mreadpropdef != null then
-                       var msignature = new MSignature(new Array[String], new Array[MType], mtype, -1)
+                       var msignature = new MSignature(new Array[MParameter], mtype)
                        mreadpropdef.msignature = msignature
                end
 
@@ -1308,7 +1577,8 @@ redef class AAttrPropdef
                        else
                                name = n_id2.text
                        end
-                       var msignature = new MSignature([name], [mtype], null, -1)
+                       var mparameter = new MParameter(name, mtype, false)
+                       var msignature = new MSignature([mparameter], null)
                        mwritepropdef.msignature = msignature
                end
        end
@@ -1334,7 +1604,65 @@ redef class AAttrPropdef
                        end
                end
 
-               # FIXME: Check getter ans setter
+               # Check getter and setter
+               var meth = self.mreadpropdef
+               if meth != null then self.check_method_signature(modelbuilder, nclassdef, meth)
+               meth = self.mwritepropdef
+               if meth != null then self.check_method_signature(modelbuilder, nclassdef, meth)
+       end
+
+       private fun check_method_signature(modelbuilder: ModelBuilder, nclassdef: AClassdef, mpropdef: MMethodDef)
+       do
+               var mmodule = mpropdef.mclassdef.mmodule
+               var nsig = self.n_type
+               var mysignature = mpropdef.msignature
+               if mysignature == null then return # Error thus skiped
+
+               # Lookup for signature in the precursor
+               # FIXME all precursors should be considered
+               if not mpropdef.is_intro then
+                       var msignature = mpropdef.mproperty.intro.msignature
+                       if msignature == null then return
+
+                       if mysignature.arity != msignature.arity then
+                               var node: ANode
+                               if nsig != null then node = nsig else node = self
+                               modelbuilder.error(node, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
+                               return
+                       end
+                       var precursor_ret_type = msignature.return_mtype
+                       var ret_type = mysignature.return_mtype
+                       if ret_type != null and precursor_ret_type == null then
+                               var node: ANode
+                               if nsig != null then node = nsig else node = self
+                               modelbuilder.error(node, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
+                               return
+                       end
+
+                       if mysignature.arity > 0 then
+                               # Check parameters types
+                               for i in [0..mysignature.arity[ do
+                                       var myt = mysignature.mparameters[i].mtype
+                                       var prt = msignature.mparameters[i].mtype
+                                       if not myt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, prt) and
+                                                       not prt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, myt) then
+                                               var node: ANode
+                                               if nsig != null then node = nsig else node = self
+                                               modelbuilder.error(node, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
+                                       end
+                               end
+                       end
+                       if precursor_ret_type != null then
+                               if ret_type == null then
+                                       # Inherit the return type
+                                       ret_type = precursor_ret_type
+                               else if not ret_type.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, precursor_ret_type) then
+                                       var node: ANode
+                                       if nsig != null then node = nsig else node = self
+                                       modelbuilder.error(node, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
+                               end
+                       end
+               end
        end
 end
 
@@ -1349,12 +1677,14 @@ redef class ATypePropdef
                if mprop == null then
                        var mvisibility = new_property_visibility(modelbuilder, nclassdef, self.n_visibility)
                        mprop = new MVirtualTypeProp(mclassdef, name, mvisibility)
-                       self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop)
+                       if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop) then return
                else
-                       self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop)
+                       if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop) then return
                        assert mprop isa MVirtualTypeProp
                        check_redef_property_visibility(modelbuilder, nclassdef, self.n_visibility, mprop)
                end
+               nclassdef.mprop2npropdef[mprop] = self
+
                var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location)
                self.mpropdef = mpropdef
        end