nitg: Added typing test on new for non-concrete classes + unit tests for new abstract...
[nit.git] / src / typing.nit
index 836a82b..527f694 100644 (file)
 module typing
 
 import flow
-import modelbuilder
+import modelize_property
+import phase
+import local_var_init
+
+redef class ToolContext
+       var typing_phase: Phase = new TypingPhase(self, [flow_phase, modelize_property_phase, local_var_init_phase])
+end
+
+redef class MPropDef
+       # Does the MPropDef contains a call to super or a call of a super-constructor?
+       var has_supercall: Bool = false
+end
+
+private class TypingPhase
+       super Phase
+       redef fun process_npropdef(npropdef) do npropdef.do_typing(toolcontext.modelbuilder)
+end
 
 private class TypeVisitor
        var modelbuilder:  ModelBuilder
@@ -68,21 +84,34 @@ private class TypeVisitor
                return res
        end
 
-       fun resolve_signature_for(msignature: MSignature, recv: MType, for_self: Bool): MSignature
+       # 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(msignature, recv, for_self).as(MSignature)
+               return self.resolve_for(mmethoddef.msignature.as(not null), recv, for_self).as(MSignature)
        end
 
-       fun check_subtype(node: ANode, sub, sup: MType): Bool
+       # 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 `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`.
+       # Is the subtype is unsafe, then the return type is the one of an implicit cast on `sup`.
+       fun check_subtype(node: ANode, sub, sup: MType): nullable MType
        do
-               if self.is_subtype(sub, sup) then return true
+               if self.is_subtype(sub, sup) then return sub
                if self.is_subtype(sub, self.anchor_to(sup)) then
                        # FIXME workarround to the current unsafe typing policy. To remove once fixed virtual types exists.
                        #node.debug("Unsafe typing: expected {sup}, got {sub}")
-                       return true
+                       return sup
                end
                self.modelbuilder.error(node, "Type error: expected {sup}, got {sub}")
-               return false
+               return null
        end
 
        # Visit an expression and do not care about the return value
@@ -96,7 +125,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)
@@ -114,11 +143,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)
@@ -126,17 +155,18 @@ private class TypeVisitor
 
                if sup == null then return null # Forward error
 
-               if not check_subtype(nexpr, sub, sup) then
-                       return null
+               var res = check_subtype(nexpr, sub, sup)
+               if res != sub then
+                       nexpr.implicit_cast_to = res
                end
-               return sub
+               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))
@@ -171,6 +201,13 @@ private class TypeVisitor
                return self.modelbuilder.resolve_mtype(self.nclassdef, 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
@@ -188,11 +225,15 @@ private class TypeVisitor
                return mclass.mclass_type
        end
 
-       fun get_method(node: ANode, recvtype: MType, name: String, recv_is_self: Bool): nullable MMethodDef
+       fun get_method(node: ANode, recvtype: MType, name: String, recv_is_self: Bool): nullable CallSite
        do
                var unsafe_type = self.anchor_to(recvtype)
 
                #debug("recv: {recvtype} (aka {unsafe_type})")
+               if recvtype isa MNullType then
+                       self.error(node, "Error: Method '{name}' call on 'null'.")
+                       return null
+               end
 
                var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
                if mproperty == null then
@@ -205,18 +246,41 @@ private class TypeVisitor
                        return null
                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)}")
+                       return null
+               end
+
                var propdefs = mproperty.lookup_definitions(self.mmodule, unsafe_type)
+               var mpropdef
                if propdefs.length == 0 then
                        self.modelbuilder.error(node, "Type error: no definition found for property {name} in {unsafe_type}")
                        return null
-               else if propdefs.length > 1 then
-                       self.modelbuilder.error(node, "Error: confliting property definitions for property {name} in {unsafe_type}: {propdefs.join(" ")}")
-                       return null
+               else if propdefs.length == 1 then
+                       mpropdef = propdefs.first
+               else
+                       self.modelbuilder.warning(node, "Warning: confliting property definitions for property {name} in {unsafe_type}: {propdefs.join(" ")}")
+                       mpropdef = mproperty.intro
+               end
+
+
+               var msignature = self.resolve_signature_for(mpropdef, recvtype, recv_is_self)
+
+               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
+                       if rettype isa MParameterType then
+                               var erased_rettype = msignature.return_mtype
+                               assert erased_rettype != null
+                               #node.debug("Erasure cast: Really a {rettype} but unsafely a {erased_rettype}")
+                               erasure_cast = true
+                       end
                end
 
-               var propdef = propdefs.first
-               assert propdef isa MMethodDef
-               return propdef
+               var callsite = new CallSite(node, recvtype, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
+               return callsite
        end
 
        # Visit the expressions of args and cheik their conformity with the corresponding typi in signature
@@ -245,12 +309,12 @@ private class TypeVisitor
                        if i > vararg_rank then
                                j = i + vararg_decl
                        end
-                       var paramtype = msignature.parameter_mtypes[i]
+                       var paramtype = msignature.mparameters[i].mtype
                        self.visit_expr_subtype(args[j], paramtype)
                end
                if vararg_rank >= 0 then
                        var varargs = new Array[AExpr]
-                       var paramtype = msignature.parameter_mtypes[vararg_rank]
+                       var paramtype = msignature.mparameters[vararg_rank].mtype
                        for j in [vararg_rank..vararg_rank+vararg_decl] do
                                varargs.add(args[j])
                                self.visit_expr_subtype(args[j], paramtype)
@@ -322,6 +386,38 @@ private class TypeVisitor
        end
 end
 
+# A specific method call site with its associated informations.
+class CallSite
+       # The assiciated node for location
+       var node: ANode
+
+       # The statis type of the receiver
+       var recv: MType
+
+       # Is the receiver self?
+       # If "for_self", virtual types of the signature are keeped
+       # If "not_for_self", virtual type are erased
+       var recv_is_self: Bool
+
+       # The designated method
+       var mproperty: MMethod
+
+       # The statically designated method definition
+       # The most specif one, it is.
+       var mpropdef: MMethodDef
+
+       # The resolved signature for the receiver
+       var msignature: MSignature
+
+       # Is a implicit cast required on erasure typing policy?
+       var erasure_cast: Bool
+
+       private fun check_signature(v: TypeVisitor, args: Array[AExpr]): Bool
+       do
+               return v.check_signature(self.node, args, self.mproperty.name, self.msignature)
+       end
+end
+
 redef class Variable
        # The declared type of the variable
        var declared_type: nullable MType
@@ -377,6 +473,9 @@ redef class APropdef
        fun do_typing(modelbuilder: ModelBuilder)
        do
        end
+
+       # The variable associated to the reciever (if any)
+       var selfvariable: nullable Variable
 end
 
 redef class AConcreteMethPropdef
@@ -385,13 +484,14 @@ redef class AConcreteMethPropdef
                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 mmethoddef = self.mpropdef.as(not null)
                for i in [0..mmethoddef.msignature.arity[ do
-                       var mtype = mmethoddef.msignature.parameter_mtypes[i]
+                       var mtype = mmethoddef.msignature.mparameters[i].mtype
                        if mmethoddef.msignature.vararg_rank == i then
                                var arrayclass = v.get_mclass(self.n_signature.n_params[i], "Array")
                                if arrayclass == null then return # Skip error
@@ -415,6 +515,7 @@ redef class AAttrPropdef
        do
                var nclassdef = self.parent.as(AClassdef)
                var v = new TypeVisitor(modelbuilder, nclassdef, self.mpropdef.as(not null))
+               self.selfvariable = v.selfvariable
 
                var nexpr = self.n_expr
                if nexpr != null then
@@ -431,10 +532,16 @@ redef class AExpr
        # null if self is a statement of in case of error
        var mtype: nullable MType = null
 
-       # Is the statement correctly typed.
-       # Used to distinguish errors and statements when `mtype' == null
+       # Is the statement correctly typed?
+       # Used to distinguish errors and statements when `mtype == null`
        var is_typed: Bool = false
 
+       # 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`
+       var implicit_cast_to: nullable MType = null
+
        # Return the variable read (if any)
        # Used to perform adaptive typing
        fun its_variable: nullable Variable do return null
@@ -451,6 +558,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
@@ -478,11 +592,13 @@ redef class AVardeclExpr
                        end
                end
 
-               if mtype == null then
-                       mtype = v.get_mclass(self, "Object").mclass_type
+               var decltype = mtype
+               if mtype == null or mtype isa MNullType then
+                       decltype = v.get_mclass(self, "Object").mclass_type.as_nullable
+                       if mtype == null then mtype = decltype
                end
 
-               variable.declared_type = mtype
+               variable.declared_type = decltype
                v.set_variable(self, variable, mtype)
 
                #debug("var {variable}: {mtype}")
@@ -524,15 +640,18 @@ 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_property: nullable MMethodDef = null
+       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
@@ -552,19 +671,15 @@ redef class AReassignFormExpr
                        return null
                end
 
-               var mpropdef = v.get_method(self, readtype, reassign_name, false)
-               if mpropdef == null then return null # Skip error
-
-               self.reassign_property = mpropdef
-
-               var msignature = mpropdef.msignature
-               assert msignature!= null
-               msignature = v.resolve_signature_for(msignature, readtype, false)
+               var callsite = v.get_method(self, readtype, reassign_name, false)
+               if callsite == null then return null # Skip error
+               self.reassign_callsite = callsite
 
+               var msignature = callsite.msignature
                var rettype = msignature.return_mtype
                assert msignature.arity == 1 and rettype != null
 
-               var value_type = v.visit_expr_subtype(self.n_value, msignature.parameter_mtypes.first)
+               var value_type = v.visit_expr_subtype(self.n_value, msignature.mparameters.first.mtype)
                if value_type == null then return null # Skip error
 
                v.check_subtype(self, rettype, writetype)
@@ -699,28 +814,125 @@ redef class ALoopExpr
 end
 
 redef class AForExpr
-       redef fun accept_typing(v)
-       do
-               var mtype = v.visit_expr(n_expr)
-               if mtype == null then return
+       var coltype: nullable MClassType
 
-               var colcla = v.get_mclass(self, "Collection")
-               if colcla == null then return
+       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
+
+       private fun do_type_iterator(v: TypeVisitor, mtype: MType)
+       do
+               # get obj class
                var objcla = v.get_mclass(self, "Object")
                if objcla == null then return
-               if v.is_subtype(mtype, colcla.get_mtype([objcla.mclass_type.as_nullable])) then
-                       var coltype = mtype.supertype_to(v.mmodule, v.anchor, colcla)
-                       assert coltype isa MGenericType
+
+               # check iterator method
+               var unsafe_type = v.anchor_to(mtype)
+               if v.try_get_mproperty_by_name2(self, unsafe_type, "iterator") == null then
+                       if v.try_get_mproperty_by_name2(self, unsafe_type, "iterate") == null then
+                               v.error(self, "Type Error: Expected method 'iterator' in type {mtype}")
+                       else
+                               v.modelbuilder.error(self, "NOT YET IMPLEMENTED: Do 'for' on {mtype}")
+                       end
+                       return
+               end
+
+               var itdef = v.get_method(self, mtype, "iterator", true)
+               if itdef == null then
+                       v.error(self, "Type Error: Expected method 'iterator' in type {mtype}")
+                       return
+               end
+               self.method_iterator = itdef.mproperty
+
+               # check that iterator return something
+               var ittype = itdef.msignature.return_mtype
+               if ittype == null then
+                       v.error(self, "Type Error: Expected 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
+
+               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")
                        else
                                variables.first.declared_type = coltype.arguments.first
                        end
-               else
-                       v.modelbuilder.error(self, "TODO: Do 'for' on {mtype}")
+                       is_col = true
                end
 
+               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")
+                       else
+                               variables[0].declared_type = coltype.arguments[0]
+                               variables[1].declared_type = coltype.arguments[1]
+                       end
+                       is_map = true
+               end
+
+               if not is_col and not is_map then
+                       v.error(self, "Type Error: Expected method 'iterator' to return an Iterator of MapIterator type")
+                       return
+               end
+
+               # anchor formal and virtual types
+               if mtype.need_anchor then mtype = v.anchor_to(mtype)
+
+               self.coltype = mtype.as(MClassType)
+
+               # 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
+
+               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
+
+               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
+
+               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
+       end
+
+       redef fun accept_typing(v)
+       do
+               var mtype = v.visit_expr(n_expr)
+               if mtype == null then return
+
+               self.do_type_iterator(v, mtype)
+
                v.visit_stmt(n_block)
                self.is_typed = true
        end
@@ -745,6 +957,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
@@ -779,21 +1000,16 @@ redef class AOrElseExpr
 
                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
@@ -881,8 +1097,11 @@ end
 redef class ARangeExpr
        redef fun accept_typing(v)
        do
-               var t1 = v.visit_expr(self.n_expr)
-               var t2 = v.visit_expr(self.n_expr2)
+               var discrete_class = v.get_mclass(self, "Discrete")
+               if discrete_class == null then return # Forward error
+               var discrete_type = discrete_class.intro.bound_mtype
+               var t1 = v.visit_expr_subtype(self.n_expr, discrete_type)
+               var t2 = v.visit_expr_subtype(self.n_expr2, discrete_type)
                if t1 == null or t2 == null then return
                var mclass = v.get_mclass(self, "Range")
                if mclass == null then return # Forward error
@@ -905,7 +1124,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
@@ -969,8 +1188,11 @@ 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 mproperty: nullable MMethod
+       var callsite: nullable CallSite
 
        redef fun accept_typing(v)
        do
@@ -983,21 +1205,17 @@ redef class ASendExpr
                        return
                end
 
-               var propdef = v.get_method(self, recvtype, name, self.n_expr isa ASelfExpr)
-               if propdef == null then return
-               var mproperty = propdef.mproperty
-               self.mproperty = mproperty
-               var msignature = propdef.msignature
-               if msignature == null then abort # Forward error
-
-               var for_self = self.n_expr isa ASelfExpr
-               msignature = v.resolve_signature_for(msignature, recvtype, for_self)
+               var callsite = v.get_method(self, recvtype, name, self.n_expr isa ASelfExpr)
+               if callsite == null then return
+               self.callsite = callsite
+               var msignature = callsite.msignature
 
                var args = compute_raw_arguments
+               self.raw_arguments = args
 
-               v.check_signature(self, args, name, msignature)
+               callsite.check_signature(v, args)
 
-               if mproperty.is_init then
+               if callsite.mproperty.is_init then
                        var vmpropdef = v.mpropdef
                        if not (vmpropdef isa MMethodDef and vmpropdef.mproperty.is_init) then
                                v.error(self, "Can call a init only in another init")
@@ -1017,7 +1235,9 @@ redef class ASendExpr
        private fun property_name: String is abstract
 
        # An array of all arguments (excluding self)
-       fun compute_raw_arguments: Array[AExpr] is abstract
+       var raw_arguments: nullable Array[AExpr]
+
+       private fun compute_raw_arguments: Array[AExpr] is abstract
 end
 
 redef class ABinopExpr
@@ -1131,8 +1351,11 @@ 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_mproperty: nullable MMethod = null
+       var write_callsite: nullable CallSite
 
        redef fun accept_typing(v)
        do
@@ -1145,38 +1368,33 @@ redef class ASendReassignFormExpr
                        return
                end
 
-               var propdef = v.get_method(self, recvtype, name, self.n_expr isa ASelfExpr)
-               if propdef == null then return
-               var mproperty = propdef.mproperty
-               self.mproperty = mproperty
-               var msignature = propdef.msignature
-               if msignature == null then abort # Forward error
                var for_self = self.n_expr isa ASelfExpr
-               msignature = v.resolve_signature_for(msignature, recvtype, for_self)
+               var callsite = v.get_method(self, recvtype, name, for_self)
+
+               if callsite == null then return
+               self.callsite = callsite
 
                var args = compute_raw_arguments
+               self.raw_arguments = args
 
-               v.check_signature(self, args, name, msignature)
+               callsite.check_signature(v, args)
 
-               var readtype = msignature.return_mtype
+               var readtype = callsite.msignature.return_mtype
                if readtype == null then
                        v.error(self, "Error: {name} is not a function")
                        return
                end
 
-               var wpropdef = v.get_method(self, recvtype, name + "=", self.n_expr isa ASelfExpr)
-               if wpropdef == null then return
-               var wmproperty = wpropdef.mproperty
-               self.write_mproperty = wmproperty
-               var wmsignature = wpropdef.msignature
-               if wmsignature == null then abort # Forward error
-               wmsignature = v.resolve_signature_for(wmsignature, recvtype, for_self)
+               var wcallsite = v.get_method(self, recvtype, name + "=", self.n_expr isa ASelfExpr)
+               if wcallsite == null then return
+               self.write_callsite = wcallsite
 
-               var wtype = self.resolve_reassignment(v, readtype, wmsignature.parameter_mtypes.last)
+               var wtype = self.resolve_reassignment(v, readtype, wcallsite.msignature.mparameters.last.mtype)
                if wtype == null then return
 
+               args = args.to_a # duplicate so raw_arguments keeps only the getter args
                args.add(self.n_value)
-               v.check_signature(self, args, name + "=", wmsignature)
+               wcallsite.check_signature(v, args)
 
                self.is_typed = true
        end
@@ -1224,20 +1442,19 @@ redef class ASuperExpr
                        end
                        v.error(self, "Error: No super method to call for {mproperty}.")
                        return
-               else if superprops.length > 1 then
-                       v.modelbuilder.warning(self, "Error: Conflicting super method to call for {mproperty}: {superprops.join(", ")}.")
-                       return
                end
+               # FIXME: covariance of return type in linear extension?
                var superprop = superprops.first
                assert superprop isa MMethodDef
 
-               var msignature = superprop.msignature.as(not null)
-               msignature = v.resolve_signature_for(msignature, recvtype, true)
+               var msignature = v.resolve_signature_for(superprop, recvtype, true)
                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
        end
 
        private fun process_superinit(v: TypeVisitor)
@@ -1275,8 +1492,7 @@ redef class ASuperExpr
                self.mproperty = superprop.mproperty
 
                var args = self.n_args.to_a
-               var msignature = superprop.msignature.as(not null)
-               msignature = v.resolve_signature_for(msignature, recvtype, true)
+               var msignature = v.resolve_signature_for(superprop, recvtype, true)
                if args.length > 0 then
                        v.check_signature(self, args, mproperty.name, msignature)
                else
@@ -1290,8 +1506,11 @@ end
 ####
 
 redef class ANewExpr
+       # @depreciated use `callsite`
+       fun mproperty: nullable MMethod do return self.callsite.mproperty
+
        # The constructor invoked by the new.
-       var mproperty: nullable MMethod
+       var callsite: nullable CallSite
 
        redef fun accept_typing(v)
        do
@@ -1307,6 +1526,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
@@ -1316,21 +1543,18 @@ redef class ANewExpr
                else
                        name = "init"
                end
-               var propdef = v.get_method(self, recvtype, name, false)
-               if propdef == null then return
+               var callsite = v.get_method(self, recvtype, name, false)
+               if callsite == null then return
 
-               self.mproperty = propdef.mproperty
+               self.callsite = callsite
 
-               if not propdef.mproperty.is_init_for(recvtype.mclass) then
+               if not callsite.mproperty.is_init_for(recvtype.mclass) then
                        v.error(self, "Error: {name} is not a constructor.")
                        return
                end
 
-               var msignature = propdef.msignature.as(not null)
-               msignature = v.resolve_signature_for(msignature, recvtype, false)
-
                var args = n_args.to_a
-               v.check_signature(self, args, name, msignature)
+               callsite.check_signature(v, args)
        end
 end
 
@@ -1423,15 +1647,6 @@ end
 
 ###
 
-redef class AClosureCallExpr
-       redef fun accept_typing(v)
-       do
-               #TODO
-       end
-end
-
-###
-
 redef class ADebugTypeExpr
        redef fun accept_typing(v)
        do
@@ -1444,5 +1659,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