src: add new hub modules to regroup related things together.
[nit.git] / src / typing.nit
index bf5cc99..3dd9024 100644 (file)
@@ -19,8 +19,8 @@
 module typing
 
 import flow
-import modelize_property
 import phase
+import modelize
 import local_var_init
 
 redef class ToolContext
@@ -34,65 +34,78 @@ end
 
 private class TypeVisitor
        var modelbuilder:  ModelBuilder
-       var nclassdef: AClassdef
-       var mpropdef: MPropDef
+
+       # The module of the analysis
+       # Used to correctly query the model
+       var mmodule: MModule
+
+       # The static type of the receiver
+       # Mainly used for type tests and type resolutions
+       var anchor: nullable MClassType
+
+       # The analyzed mclassdef
+       var mclassdef: nullable MClassDef
+
+       # The analyzed property
+       var mpropdef: nullable MPropDef
 
        var selfvariable: Variable = new Variable("self")
 
-       init(modelbuilder: ModelBuilder, nclassdef: AClassdef, mpropdef: MPropDef)
+       # Is `self` use restricted?
+       # * no explicit `self`
+       # * method called on the implicit self must be top-level
+       var is_toplevel_context = false
+
+       init(modelbuilder: ModelBuilder, mmodule: MModule, mpropdef: nullable MPropDef)
        do
                self.modelbuilder = modelbuilder
-               self.nclassdef = nclassdef
-               self.mpropdef = mpropdef
+               self.mmodule = mmodule
 
-               var mclass = nclassdef.mclassdef.mclass
+               if mpropdef != null then
+                       self.mpropdef = mpropdef
+                       var mclassdef = mpropdef.mclassdef
+                       self.mclassdef = mclassdef
+                       self.anchor = mclassdef.bound_mtype
 
-               var selfvariable = new Variable("self")
-               self.selfvariable = selfvariable
-               selfvariable.declared_type = mclass.mclass_type
-       end
+                       var mclass = mclassdef.mclass
 
-       fun mmodule: MModule do return self.nclassdef.mclassdef.mmodule
+                       var selfvariable = new Variable("self")
+                       self.selfvariable = selfvariable
+                       selfvariable.declared_type = mclass.mclass_type
 
-       fun anchor: MClassType do return self.nclassdef.mclassdef.bound_mtype
+                       var mprop = mpropdef.mproperty
+                       if mprop isa MMethod and mprop.is_toplevel then
+                               is_toplevel_context = true
+                       end
+               end
+       end
 
        fun anchor_to(mtype: MType): MType
        do
-               var mmodule = self.nclassdef.mclassdef.mmodule
-               var anchor = self.nclassdef.mclassdef.bound_mtype
+               var anchor = anchor
+               if anchor == null then
+                       assert not mtype.need_anchor
+                       return mtype
+               end
                return mtype.anchor_to(mmodule, anchor)
        end
 
        fun is_subtype(sub, sup: MType): Bool
        do
-               var mmodule = self.nclassdef.mclassdef.mmodule
-               var anchor = self.nclassdef.mclassdef.bound_mtype
                return sub.is_subtype(mmodule, anchor, sup)
        end
 
        fun resolve_for(mtype, subtype: MType, for_self: Bool): MType
        do
-               var mmodule = self.nclassdef.mclassdef.mmodule
-               var anchor = self.nclassdef.mclassdef.bound_mtype
                #print "resolve_for {mtype} sub={subtype} forself={for_self} mmodule={mmodule} anchor={anchor}"
                var res = mtype.resolve_for(subtype, anchor, mmodule, not for_self)
                return res
        end
 
-       # Retrieve the signature of a MMethodDef resolved for a specific call.
-       # This method is an helper to symplify the query on the model.
-       #
-       # Note: `for_self` indicates if the reciever is self or not.
-       # If yes, virtual types are not resolved.
-       fun resolve_signature_for(mmethoddef: MMethodDef, recv: MType, for_self: Bool): MSignature
-       do
-               return self.resolve_for(mmethoddef.msignature.as(not null), recv, for_self).as(MSignature)
-       end
-
        # Check that `sub` is a subtype of `sup`.
        # If `sub` is not a valud suptype, then display an error on `node` an return null.
        # If `sub` is a safe subtype of `sup` then return `sub`.
-       # If `sun` is an insafe subtype (ie an imlicit cast is required), then return `sup`.
+       # If `sub` is an insafe subtype (ie an imlicit cast is required), then return `sup`.
        #
        # The point of the return type is to determinate the usable type on an expression:
        # If the suptype is safe, then the return type is the one on the expression typed by `sub`.
@@ -120,7 +133,7 @@ private class TypeVisitor
        # Return the type of the expression
        # Display an error and return null if:
        #  * the type cannot be determined or
-       #  * `nexpr' is a statement
+       #  * `nexpr` is a statement
        fun visit_expr(nexpr: AExpr): nullable MType
        do
                nexpr.accept_typing(self)
@@ -138,11 +151,11 @@ private class TypeVisitor
                return null
        end
 
-       # Visit an expression and expect its static type is a least a `sup'
-       # Return the type of the expression
+       # Visit an expression and expect its static type is a least a `sup`
+       # Return the type of the expression or null if
        #  * the type cannot be determined or
-       #  * `nexpr' is a statement
-       #  * `nexpt' is not a `sup'
+       #  * `nexpr` is a statement or
+       #  * `nexpr` is not a `sup`
        fun visit_expr_subtype(nexpr: AExpr, sup: nullable MType): nullable MType
        do
                var sub = visit_expr(nexpr)
@@ -157,11 +170,11 @@ private class TypeVisitor
                return res
        end
 
-       # Visit an expression and expect its static type is a bool
-       # Return the type of the expression
+       # Visit an expression and expect its static type is a `Bool`
+       # Return the type of the expression or null if
        #  * the type cannot be determined or
-       #  * `nexpr' is a statement
-       #  * `nexpt' is not a `sup'
+       #  * `nexpr` is a statement or
+       #  * `nexpr` is not a `Bool`
        fun visit_expr_bool(nexpr: AExpr): nullable MType
        do
                return self.visit_expr_subtype(nexpr, self.type_bool(nexpr))
@@ -176,11 +189,9 @@ private class TypeVisitor
                var sup = self.resolve_mtype(ntype)
                if sup == null then return null # Forward error
 
-               var mmodule = self.nclassdef.mclassdef.mmodule
-               var anchor = self.nclassdef.mclassdef.bound_mtype
                if sup == sub then
                        self.modelbuilder.warning(node, "Warning: Expression is already a {sup}.")
-               else if self.is_subtype(sub, sup) and not sup.need_anchor then
+               else if self.is_subtype(sub, sup) then
                        self.modelbuilder.warning(node, "Warning: Expression is already a {sup} since it is a {sub}.")
                end
                return sup
@@ -188,24 +199,22 @@ private class TypeVisitor
 
        fun try_get_mproperty_by_name2(anode: ANode, mtype: MType, name: String): nullable MProperty
        do
-               return self.modelbuilder.try_get_mproperty_by_name2(anode, self.nclassdef.mclassdef.mmodule, mtype, name)
+               return self.modelbuilder.try_get_mproperty_by_name2(anode, mmodule, mtype, name)
        end
 
        fun resolve_mtype(node: AType): nullable MType
        do
-               return self.modelbuilder.resolve_mtype(self.nclassdef, node)
+               return self.modelbuilder.resolve_mtype(mmodule, mclassdef, node)
        end
 
        fun try_get_mclass(node: ANode, name: String): nullable MClass
        do
-               var mmodule = self.nclassdef.mclassdef.mmodule
                var mclass = modelbuilder.try_get_mclass_by_name(node, mmodule, name)
                return mclass
        end
 
        fun get_mclass(node: ANode, name: String): nullable MClass
        do
-               var mmodule = self.nclassdef.mclassdef.mmodule
                var mclass = modelbuilder.try_get_mclass_by_name(node, mmodule, name)
                if mclass == null then
                        self.modelbuilder.error(node, "Type Error: missing primitive class `{name}'.")
@@ -242,8 +251,16 @@ private class TypeVisitor
                end
 
                assert mproperty isa MMethod
-               if mproperty.visibility == protected_visibility and not recv_is_self and self.mmodule.visibility_for(mproperty.intro_mclassdef.mmodule) < intrude_visibility then
-                       self.modelbuilder.error(node, "Error: Method '{name}' is protected and can only acceded by self. {mproperty.intro_mclassdef.mmodule.visibility_for(self.mmodule)}")
+
+               if is_toplevel_context and recv_is_self and not mproperty.is_toplevel then
+                       error(node, "Error: '{name}' is not a top-level method, thus need a receiver.")
+               end
+               if not recv_is_self and mproperty.is_toplevel then
+                       error(node, "Error: cannot call '{name}', a top-level method, with a receiver.")
+               end
+
+               if mproperty.visibility == protected_visibility and not recv_is_self and self.mmodule.visibility_for(mproperty.intro_mclassdef.mmodule) < intrude_visibility and not modelbuilder.toolcontext.opt_ignore_visibility.value then
+                       self.modelbuilder.error(node, "Error: Method '{name}' is protected and can only acceded by self.")
                        return null
                end
 
@@ -260,12 +277,13 @@ private class TypeVisitor
                end
 
 
-               var msignature = self.resolve_signature_for(mpropdef, recvtype, recv_is_self)
+               var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
+               msignature = resolve_for(msignature, recvtype, recv_is_self).as(MSignature)
 
                var erasure_cast = false
                var rettype = mpropdef.msignature.return_mtype
                if not recv_is_self and rettype != null then
-                       if rettype isa MNullableType then rettype = rettype.mtype
+                       rettype = rettype.as_notnullable
                        if rettype isa MParameterType then
                                var erased_rettype = msignature.return_mtype
                                assert erased_rettype != null
@@ -274,7 +292,7 @@ private class TypeVisitor
                        end
                end
 
-               var callsite = new CallSite(node, recvtype, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
+               var callsite = new CallSite(node, recvtype, mmodule, anchor, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
                return callsite
        end
 
@@ -386,9 +404,15 @@ class CallSite
        # The assiciated node for location
        var node: ANode
 
-       # The statis type of the receiver
+       # The static type of the receiver (possibly unresolved)
        var recv: MType
 
+       # The module where the callsite is present
+       var mmodule: MModule
+
+       # The anchor to use with `recv` or `msignature`
+       var anchor: nullable MClassType
+
        # Is the receiver self?
        # If "for_self", virtual types of the signature are keeped
        # If "not_for_self", virtual type are erased
@@ -473,17 +497,16 @@ redef class APropdef
        var selfvariable: nullable Variable
 end
 
-redef class AConcreteMethPropdef
+redef class AMethPropdef
        redef fun do_typing(modelbuilder: ModelBuilder)
        do
-               var nclassdef = self.parent.as(AClassdef)
-               var mpropdef = self.mpropdef.as(not null)
-               var v = new TypeVisitor(modelbuilder, nclassdef, mpropdef)
-               self.selfvariable = v.selfvariable
-
                var nblock = self.n_block
                if nblock == null then return
 
+               var mpropdef = self.mpropdef.as(not null)
+               var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
+               self.selfvariable = v.selfvariable
+
                var mmethoddef = self.mpropdef.as(not null)
                for i in [0..mmethoddef.msignature.arity[ do
                        var mtype = mmethoddef.msignature.mparameters[i].mtype
@@ -496,12 +519,6 @@ redef class AConcreteMethPropdef
                        assert variable != null
                        variable.declared_type = mtype
                end
-               for i in [0..mmethoddef.msignature.mclosures.length[ do
-                       var mclosure = mmethoddef.msignature.mclosures[i]
-                       var variable = self.n_signature.n_closure_decls[i].variable
-                       assert variable != null
-                       variable.declared_type = mclosure.mtype
-               end
                v.visit_stmt(nblock)
 
                if not nblock.after_flow_context.is_unreachable and mmethoddef.msignature.return_mtype != null then
@@ -514,8 +531,8 @@ end
 redef class AAttrPropdef
        redef fun do_typing(modelbuilder: ModelBuilder)
        do
-               var nclassdef = self.parent.as(AClassdef)
-               var v = new TypeVisitor(modelbuilder, nclassdef, self.mpropdef.as(not null))
+               var mpropdef = self.mpropdef.as(not null)
+               var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
                self.selfvariable = v.selfvariable
 
                var nexpr = self.n_expr
@@ -530,14 +547,14 @@ end
 
 redef class AExpr
        # The static type of the expression.
-       # null if self is a statement of in case of error
+       # null if self is a statement or in case of error
        var mtype: nullable MType = null
 
        # Is the statement correctly typed?
-       # Used to distinguish errors and statements when `mtype' == null
+       # Used to distinguish errors and statements when `mtype == null`
        var is_typed: Bool = false
 
-       # If required, the following implicit cast ".as(XXX)"
+       # If required, the following implicit cast `.as(XXX)`
        # Such a cast may by required after evaluating the expression when
        # a unsafe operation is detected (silently accepted by the Nit language).
        # The attribute is computed by `check_subtype`
@@ -559,6 +576,13 @@ redef class ABlockExpr
                for e in self.n_expr do v.visit_stmt(e)
                self.is_typed = true
        end
+
+       # The type of a blockexpr is the one of the last expression (or null if empty)
+       redef fun mtype
+       do
+               if self.n_expr.is_empty then return null
+               return self.n_expr.last.mtype
+       end
 end
 
 redef class AVardeclExpr
@@ -634,18 +658,15 @@ redef class AVarAssignExpr
 end
 
 redef class AReassignFormExpr
-       # @depreciated use `reassign_callsite`
-       fun reassign_property: nullable MMethodDef do return self.reassign_callsite.mpropdef
-
        # The method designed by the reassign operator.
        var reassign_callsite: nullable CallSite
 
        var read_type: nullable MType = null
 
-       # Determine the `reassign_property'
-       # `readtype' is the type of the reading of the left value.
-       # `writetype' is the type of the writing of the left value.
-       # (Because of ACallReassignExpr, both can be different.
+       # Determine the `reassign_property`
+       # `readtype` is the type of the reading of the left value.
+       # `writetype` is the type of the writing of the left value.
+       # (Because of `ACallReassignExpr`, both can be different.
        # Return the static type of the value to store.
        private fun resolve_reassignment(v: TypeVisitor, readtype, writetype: MType): nullable MType
        do
@@ -690,6 +711,8 @@ redef class AVarReassignExpr
                var readtype = v.get_variable(self, variable)
                if readtype == null then return
 
+               read_type = readtype
+
                var writetype = variable.declared_type
                if writetype == null then return
 
@@ -810,40 +833,62 @@ end
 redef class AForExpr
        var coltype: nullable MClassType
 
-       var method_iterator: nullable MMethod
-       var method_is_ok: nullable MMethod
-       var method_item: nullable MMethod
-       var method_next: nullable MMethod
-       var method_key: nullable MMethod
+       var method_iterator: nullable CallSite
+       var method_is_ok: nullable CallSite
+       var method_item: nullable CallSite
+       var method_next: nullable CallSite
+       var method_key: nullable CallSite
 
        private fun do_type_iterator(v: TypeVisitor, mtype: MType)
        do
+               if mtype isa MNullType then
+                       v.error(self, "Type error: 'for' cannot iterate over 'null'")
+                       return
+               end
+
+               # get obj class
                var objcla = v.get_mclass(self, "Object")
                if objcla == null then return
 
+               # check iterator method
+               var itdef = v.get_method(self, mtype, "iterator", n_expr isa ASelfExpr)
+               if itdef == null then
+                       v.error(self, "Type Error: 'for' expects a type providing 'iterator' method, got '{mtype}'.")
+                       return
+               end
+               self.method_iterator = itdef
+
+               # check that iterator return something
+               var ittype = itdef.msignature.return_mtype
+               if ittype == null then
+                       v.error(self, "Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'.")
+                       return
+               end
+
+               # get iterator type
+               var colit_cla = v.try_get_mclass(self, "Iterator")
+               var mapit_cla = v.try_get_mclass(self, "MapIterator")
                var is_col = false
                var is_map = false
 
-               var colcla = v.try_get_mclass(self, "Collection")
-               if colcla != null and v.is_subtype(mtype, colcla.get_mtype([objcla.mclass_type.as_nullable])) then
-                       var coltype = mtype.supertype_to(v.mmodule, v.anchor, colcla)
-                       self.coltype = coltype
+               if colit_cla != null and v.is_subtype(ittype, colit_cla.get_mtype([objcla.mclass_type.as_nullable])) then
+                       # Iterator
+                       var coltype = ittype.supertype_to(v.mmodule, v.anchor, colit_cla)
                        var variables =  self.variables
                        if variables.length != 1 then
-                               v.error(self, "Type Error: Expected one variable")
+                               v.error(self, "Type Error: 'for' expects only one variable when using 'Iterator'.")
                        else
                                variables.first.declared_type = coltype.arguments.first
                        end
                        is_col = true
                end
 
-               var mapcla = v.try_get_mclass(self, "Map")
-               if mapcla != null and v.is_subtype(mtype, mapcla.get_mtype([objcla.mclass_type.as_nullable, objcla.mclass_type.as_nullable])) then
-                       var coltype = mtype.supertype_to(v.mmodule, v.anchor, mapcla)
-                       self.coltype = coltype
+               if mapit_cla != null and v.is_subtype(ittype, mapit_cla.get_mtype([objcla.mclass_type, objcla.mclass_type.as_nullable])) then
+                       # Map Iterator
+                       var coltype = ittype.supertype_to(v.mmodule, v.anchor, mapit_cla)
                        var variables = self.variables
                        if variables.length != 2 then
-                               v.error(self, "Type Error: Expected two variables")
+                               v.error(self, "Type Error: 'for' expects two variables when using 'MapIterator'.")
                        else
                                variables[0].declared_type = coltype.arguments[0]
                                variables[1].declared_type = coltype.arguments[1]
@@ -851,57 +896,47 @@ redef class AForExpr
                        is_map = true
                end
 
-               if is_col or is_map then
-                       # get iterator method
-                       var coltype = self.coltype.as(not null)
-                       var itdef = v.get_method(self, coltype, "iterator", true)
-                       if itdef == null then
-                               v.error(self, "Type Error: Expected method 'iterator' in type {coltype}")
-                               return
-                       end
-                       self.method_iterator = itdef.mproperty
+               if not is_col and not is_map then
+                       v.error(self, "Type Error: 'for' expects method 'iterator' to return an 'Iterator' or 'MapIterator' type'.")
+                       return
+               end
 
-                       # get iterator type
-                       var ittype = itdef.msignature.return_mtype
-                       if ittype == null then
-                               v.error(self, "Type Error: Expected method 'iterator' to return an Iterator type")
-                               return
-                       end
+               # anchor formal and virtual types
+               if mtype.need_anchor then mtype = v.anchor_to(mtype)
 
-                       # get methods is_ok, next, item
-                       var ikdef = v.get_method(self, ittype, "is_ok", false)
-                       if ikdef == null then
-                               v.error(self, "Type Error: Expected method 'is_ok' in Iterator type {ittype}")
-                               return
-                       end
-                       self.method_is_ok = ikdef.mproperty
+               mtype = mtype.as_notnullable
+               self.coltype = mtype.as(MClassType)
 
-                       var itemdef = v.get_method(self, ittype, "item", false)
-                       if itemdef == null then
-                               v.error(self, "Type Error: Expected method 'item' in Iterator type {ittype}")
-                               return
-                       end
-                       self.method_item = itemdef.mproperty
+               # get methods is_ok, next, item
+               var ikdef = v.get_method(self, ittype, "is_ok", false)
+               if ikdef == null then
+                       v.error(self, "Type Error: 'for' expects a method 'is_ok' in 'Iterator' type {ittype}.")
+                       return
+               end
+               self.method_is_ok = ikdef
 
-                       var nextdef = v.get_method(self, ittype, "next", false)
-                       if nextdef == null then
-                               v.error(self, "Type Error: Expected method 'next' in Iterator type {ittype}")
-                               return
-                       end
-                       self.method_next = nextdef.mproperty
+               var itemdef = v.get_method(self, ittype, "item", false)
+               if itemdef == null then
+                       v.error(self, "Type Error: 'for' expects a method 'item' in 'Iterator' type {ittype}.")
+                       return
+               end
+               self.method_item = itemdef
 
-                       if is_map then
-                               var keydef = v.get_method(self, ittype, "key", false)
-                               if keydef == null then
-                                       v.error(self, "Type Error: Expected method 'key' in Iterator type {ittype}")
-                                       return
-                               end
-                               self.method_key = keydef.mproperty
-                       end
+               var nextdef = v.get_method(self, ittype, "next", false)
+               if nextdef == null then
+                       v.error(self, "Type Error: 'for' expects a method 'next' in 'Iterator' type {ittype}.")
                        return
                end
+               self.method_next = nextdef
 
-               v.modelbuilder.error(self, "NOT YET IMPLEMENTED: Do 'for' on {mtype}")
+               if is_map then
+                       var keydef = v.get_method(self, ittype, "key", false)
+                       if keydef == null then
+                               v.error(self, "Type Error: 'for' expects a method 'key' in 'Iterator' type {ittype}.")
+                               return
+                       end
+                       self.method_key = keydef
+               end
        end
 
        redef fun accept_typing(v)
@@ -935,6 +970,15 @@ redef class AOrExpr
        end
 end
 
+redef class AImpliesExpr
+       redef fun accept_typing(v)
+       do
+               v.visit_expr_bool(n_expr)
+               v.visit_expr_bool(n_expr2)
+               self.mtype = v.type_bool(self)
+       end
+end
+
 redef class AAndExpr
        redef fun accept_typing(v)
        do
@@ -963,27 +1007,20 @@ redef class AOrElseExpr
                        return # Skip error
                end
 
-               if t1 isa MNullableType then
-                       t1 = t1.mtype
-               end
+               t1 = t1.as_notnullable
 
                var t = v.merge_types(self, [t1, t2])
                if t == null then
-                       v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
+                       t = v.mmodule.object_type
+                       if t2 isa MNullableType then
+                               t = t.as_nullable
+                       end
+                       #v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
                end
                self.mtype = t
        end
 end
 
-redef class AEeExpr
-       redef fun accept_typing(v)
-       do
-               v.visit_expr(n_expr)
-               v.visit_expr(n_expr2)
-               self.mtype = v.type_bool(self)
-       end
-end
-
 redef class ATrueExpr
        redef fun accept_typing(v)
        do
@@ -1041,12 +1078,15 @@ redef class ASuperstringExpr
                if mclass == null then return # Forward error
                self.mtype = mclass.mclass_type
                for nexpr in self.n_exprs do
-                       var t = v.visit_expr(nexpr)
+                       v.visit_expr_subtype(nexpr, v.mmodule.object_type)
                end
        end
 end
 
 redef class AArrayExpr
+       var with_capacity_callsite: nullable CallSite
+       var push_callsite: nullable CallSite
+
        redef fun accept_typing(v)
        do
                var mtypes = new Array[nullable MType]
@@ -1064,11 +1104,18 @@ redef class AArrayExpr
                end
                var mclass = v.get_mclass(self, "Array")
                if mclass == null then return # Forward error
-               self.mtype = mclass.get_mtype([mtype])
+               var array_mtype = mclass.get_mtype([mtype])
+
+               with_capacity_callsite = v.get_method(self, array_mtype, "with_capacity", false)
+               push_callsite = v.get_method(self, array_mtype, "push", false)
+
+               self.mtype = array_mtype
        end
 end
 
 redef class ARangeExpr
+       var init_callsite: nullable CallSite
+
        redef fun accept_typing(v)
        do
                var discrete_class = v.get_mclass(self, "Discrete")
@@ -1079,13 +1126,28 @@ redef class ARangeExpr
                if t1 == null or t2 == null then return
                var mclass = v.get_mclass(self, "Range")
                if mclass == null then return # Forward error
+               var mtype
                if v.is_subtype(t1, t2) then
-                       self.mtype = mclass.get_mtype([t2])
+                       mtype = mclass.get_mtype([t2])
                else if v.is_subtype(t2, t1) then
-                       self.mtype = mclass.get_mtype([t1])
+                       mtype = mclass.get_mtype([t1])
                else
                        v.error(self, "Type Error: Cannot create range: {t1} vs {t2}")
+                       return
+               end
+
+               self.mtype = mtype
+
+               # get the constructor
+               var callsite
+               if self isa ACrangeExpr then
+                       callsite = v.get_method(self, mtype, "init", false)
+               else if self isa AOrangeExpr then
+                       callsite = v.get_method(self, mtype, "without_last", false)
+               else
+                       abort
                end
+               init_callsite = callsite
        end
 end
 
@@ -1098,7 +1160,7 @@ end
 
 redef class AIsaExpr
        # The static type to cast to.
-       # (different from the static type of the expression that is Bool).
+       # (different from the static type of the expression that is `Bool`).
        var cast_type: nullable MType
        redef fun accept_typing(v)
        do
@@ -1129,6 +1191,8 @@ redef class AAsNotnullExpr
        redef fun accept_typing(v)
        do
                var mtype = v.visit_expr(self.n_expr)
+               if mtype == null then return # Forward error
+
                if mtype isa MNullType then
                        v.error(self, "Type error: as(not null) on null")
                        return
@@ -1137,8 +1201,18 @@ redef class AAsNotnullExpr
                        self.mtype = mtype.mtype
                        return
                end
-               # TODO: warn on useless as not null
                self.mtype = mtype
+
+               if mtype isa MClassType then
+                       v.modelbuilder.warning(self, "Warning: expression is already not null, since it is a `{mtype}`.")
+                       return
+               end
+               assert mtype.need_anchor
+               var u = v.anchor_to(mtype)
+               if not u isa MNullableType then
+                       v.modelbuilder.warning(self, "Warning: expression is already not null, since it is a `{mtype}: {u}`.")
+                       return
+               end
        end
 end
 
@@ -1153,6 +1227,9 @@ redef class ASelfExpr
        redef var its_variable: nullable Variable
        redef fun accept_typing(v)
        do
+               if v.is_toplevel_context and not self isa AImplicitSelfExpr then
+                       v.error(self, "Error: self cannot be used in top-level method.")
+               end
                var variable = v.selfvariable
                self.its_variable = variable
                self.mtype = v.get_variable(self, variable)
@@ -1162,9 +1239,6 @@ end
 ## MESSAGE SENDING AND PROPERTY
 
 redef class ASendExpr
-       # @depreciated: use `callsite`
-       fun mproperty: nullable MMethod do return callsite.mproperty
-
        # The property invoked by the send.
        var callsite: nullable CallSite
 
@@ -1185,7 +1259,6 @@ redef class ASendExpr
                var msignature = callsite.msignature
 
                var args = compute_raw_arguments
-               self.raw_arguments = args
 
                callsite.check_signature(v, args)
 
@@ -1194,6 +1267,9 @@ redef class ASendExpr
                        if not (vmpropdef isa MMethodDef and vmpropdef.mproperty.is_init) then
                                v.error(self, "Can call a init only in another init")
                        end
+                       if vmpropdef isa MMethodDef and vmpropdef.mproperty.is_root_init and not callsite.mproperty.is_root_init then
+                               v.error(self, "Error: {vmpropdef} cannot call a factory {callsite.mproperty}")
+                       end
                end
 
                var ret = msignature.return_mtype
@@ -1202,14 +1278,6 @@ redef class ASendExpr
                else
                        self.is_typed = true
                end
-
-               if self.n_closure_defs.length == msignature.mclosures.length then
-                       for i in [0..self.n_closure_defs.length[ do
-                               self.n_closure_defs[i].accept_typing(v, msignature.mclosures[i])
-                       end
-               else
-                       debug("closure: got {self.n_closure_defs.length}, want {msignature.mclosures.length}")
-               end
        end
 
        # The name of the property
@@ -1217,7 +1285,7 @@ redef class ASendExpr
        private fun property_name: String is abstract
 
        # An array of all arguments (excluding self)
-       var raw_arguments: nullable Array[AExpr]
+       fun raw_arguments: Array[AExpr] do return compute_raw_arguments
 
        private fun compute_raw_arguments: Array[AExpr] is abstract
 end
@@ -1333,9 +1401,6 @@ redef class ABraAssignExpr
 end
 
 redef class ASendReassignFormExpr
-       # @depreciated use `write_callsite`
-       fun write_mproperty: nullable MMethod do return write_callsite.mproperty
-
        # The property invoked for the writing
        var write_callsite: nullable CallSite
 
@@ -1357,7 +1422,6 @@ redef class ASendReassignFormExpr
                self.callsite = callsite
 
                var args = compute_raw_arguments
-               self.raw_arguments = args
 
                callsite.check_signature(v, args)
 
@@ -1406,11 +1470,16 @@ end
 redef class ASuperExpr
        # The method to call if the super is in fact a 'super init call'
        # Note: if the super is a normal call-next-method, then this attribute is null
-       var mproperty: nullable MMethod
+       var callsite: nullable CallSite
+
+       # The method to call is the super is a standard `call-next-method` super-call
+       # Note: if the super is a special super-init-call, then this attribute is null
+       var mpropdef: nullable MMethodDef
 
        redef fun accept_typing(v)
        do
-               var recvtype = v.nclassdef.mclassdef.bound_mtype
+               var recvtype = v.anchor
+               assert recvtype != null
                var mproperty = v.mpropdef.mproperty
                if not mproperty isa MMethod then
                        v.error(self, "Error: super only usable in a method")
@@ -1427,22 +1496,28 @@ redef class ASuperExpr
                end
                # FIXME: covariance of return type in linear extension?
                var superprop = superprops.first
-               assert superprop isa MMethodDef
 
-               var msignature = v.resolve_signature_for(superprop, recvtype, true)
+               var msignature = superprop.msignature.as(not null)
+               msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
                var args = self.n_args.to_a
                if args.length > 0 then
                        v.check_signature(self, args, mproperty.name, msignature)
                end
                self.mtype = msignature.return_mtype
+               self.is_typed = true
+               v.mpropdef.has_supercall = true
+               mpropdef = v.mpropdef.as(MMethodDef)
        end
 
        private fun process_superinit(v: TypeVisitor)
        do
-               var recvtype = v.nclassdef.mclassdef.bound_mtype
-               var mproperty = v.mpropdef.mproperty
+               var recvtype = v.anchor
+               assert recvtype != null
+               var mpropdef = v.mpropdef
+               assert mpropdef isa MMethodDef
+               var mproperty = mpropdef.mproperty
                var superprop: nullable MMethodDef = null
-               for msupertype in v.nclassdef.mclassdef.supertypes do
+               for msupertype in mpropdef.mclassdef.supertypes do
                        msupertype = msupertype.anchor_to(v.mmodule, recvtype)
                        var errcount = v.modelbuilder.toolcontext.error_count
                        var candidate = v.try_get_mproperty_by_name2(self, msupertype, mproperty.name).as(nullable MMethod)
@@ -1450,12 +1525,15 @@ redef class ASuperExpr
                                if v.modelbuilder.toolcontext.error_count > errcount then return # Forard error
                                continue # Try next super-class
                        end
-                       if superprop != null and superprop.mproperty != candidate then
+                       if superprop != null and candidate.is_root_init then
+                               continue
+                       end
+                       if superprop != null and superprop.mproperty != candidate and not superprop.mproperty.is_root_init then
                                v.error(self, "Error: conflicting super constructor to call for {mproperty}: {candidate.full_name}, {superprop.mproperty.full_name}")
                                return
                        end
                        var candidatedefs = candidate.lookup_definitions(v.mmodule, recvtype)
-                       if superprop != null then
+                       if superprop != null and superprop.mproperty == candidate then
                                if superprop == candidatedefs.first then continue
                                candidatedefs.add(superprop)
                        end
@@ -1469,14 +1547,32 @@ redef class ASuperExpr
                        v.error(self, "Error: No super method to call for {mproperty}.")
                        return
                end
-               self.mproperty = superprop.mproperty
+
+               var msignature = superprop.new_msignature or else superprop.msignature.as(not null)
+               msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
+
+               var callsite = new CallSite(self, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
+               self.callsite = callsite
 
                var args = self.n_args.to_a
-               var msignature = v.resolve_signature_for(superprop, recvtype, true)
                if args.length > 0 then
-                       v.check_signature(self, args, mproperty.name, msignature)
+                       callsite.check_signature(v, args)
                else
-                       # TODO: Check signature
+                       # Check there is at least enough parameters
+                       if mpropdef.msignature.arity < msignature.arity then
+                               v.error(self, "Error: Not enough implicit arguments to pass. Got {mpropdef.msignature.arity}, expected at least {msignature.arity}. Signature is {msignature}")
+                               return
+                       end
+                       # Check that each needed parameter is conform
+                       var i = 0
+                       for sp in msignature.mparameters do
+                               var p = mpropdef.msignature.mparameters[i]
+                               if not v.is_subtype(p.mtype, sp.mtype) then
+                                       v.error(self, "Type error: expected argument #{i} of type {sp.mtype}, got implicit argument {p.name} of type {p.mtype}. Signature is {msignature}")
+                                       return
+                               end
+                               i += 1
+                       end
                end
 
                self.is_typed = true
@@ -1486,9 +1582,6 @@ end
 ####
 
 redef class ANewExpr
-       # @depreciated use `callsite`
-       fun mproperty: nullable MMethod do return self.callsite.mproperty
-
        # The constructor invoked by the new.
        var callsite: nullable CallSite
 
@@ -1506,6 +1599,14 @@ redef class ANewExpr
                                v.error(self, "Type error: cannot instantiate the formal type {recvtype}.")
                                return
                        end
+               else
+                       if recvtype.mclass.kind == abstract_kind then
+                               v.error(self, "Cannot instantiate abstract class {recvtype}.")
+                               return
+                       else if recvtype.mclass.kind == interface_kind then
+                               v.error(self, "Cannot instantiate interface {recvtype}.")
+                               return
+                       end
                end
 
                var name: String
@@ -1619,50 +1720,6 @@ end
 
 ###
 
-redef class AClosureCallExpr
-       redef fun accept_typing(v)
-       do
-               var variable = self.variable
-               if variable == null then return # Skip error
-
-               var recvtype = v.nclassdef.mclassdef.bound_mtype
-               var msignature = variable.declared_type.as(not null)
-               msignature = v.resolve_for(msignature, recvtype, false).as(MSignature)
-
-               var args = n_args.to_a
-               v.check_signature(self, args, variable.name, msignature)
-
-               self.is_typed = true
-               self.mtype = msignature.return_mtype
-       end
-end
-
-redef class AClosureDef
-       var mclosure: nullable MParameter
-
-       private fun accept_typing(v: TypeVisitor, mparameter: MParameter)
-       do
-               var variables = self.variables
-               if variables == null then return
-
-               self.mclosure = mparameter
-               var msignature = mparameter.mtype.as(MSignature)
-
-               if msignature.arity != variables.length then
-                       v.error(self, "Type error: closure {mparameter.name} expects {msignature.arity} parameters, {variables.length} given")
-                       return
-               end
-
-               for i in [0..variables.length[ do
-                       variables[i].declared_type = msignature.mparameters[i].mtype
-               end
-
-               v.visit_stmt(self.n_expr)
-       end
-end
-
-###
-
 redef class ADebugTypeExpr
        redef fun accept_typing(v)
        do
@@ -1675,5 +1732,6 @@ redef class ADebugTypeExpr
                        var umtype = v.anchor_to(mtype)
                        v.modelbuilder.warning(self, "Found type {expr} (-> {unsafe}), expected {mtype} (-> {umtype})")
                end
+               self.is_typed = true
        end
 end