typing: warn `useless-type` for useless type in a local variable
[nit.git] / src / semantize / typing.nit
index 3aa87a8..cdb8ae8 100644 (file)
@@ -39,10 +39,10 @@ private class TypeVisitor
 
        # The static type of the receiver
        # Mainly used for type tests and type resolutions
-       var anchor: nullable MClassType
+       var anchor: nullable MClassType = null
 
        # The analyzed mclassdef
-       var mclassdef: nullable MClassDef
+       var mclassdef: nullable MClassDef = null
 
        # The analyzed property
        var mpropdef: nullable MPropDef
@@ -54,10 +54,9 @@ private class TypeVisitor
        # * method called on the implicit self must be top-level
        var is_toplevel_context = false
 
-       init(modelbuilder: ModelBuilder, mmodule: MModule, mpropdef: nullable MPropDef)
+       init
        do
-               self.modelbuilder = modelbuilder
-               self.mmodule = mmodule
+               var mpropdef = self.mpropdef
 
                if mpropdef != null then
                        self.mpropdef = mpropdef
@@ -72,7 +71,7 @@ private class TypeVisitor
                        selfvariable.declared_type = mclass.mclass_type
 
                        var mprop = mpropdef.mproperty
-                       if mprop isa MMethod and mprop.is_toplevel then
+                       if mprop isa MMethod and (mprop.is_toplevel or mprop.is_new) then
                                is_toplevel_context = true
                        end
                end
@@ -602,6 +601,10 @@ redef class AAttrPropdef
                        var mtype = self.mpropdef.static_mtype
                        v.visit_expr_subtype(nexpr, mtype)
                end
+               var nblock = self.n_block
+               if nblock != null then
+                       v.visit_stmt(nblock)
+               end
        end
 end
 
@@ -665,7 +668,11 @@ redef class AVardeclExpr
                var nexpr = self.n_expr
                if nexpr != null then
                        if mtype != null then
-                               v.visit_expr_subtype(nexpr, mtype)
+                               var etype = v.visit_expr_subtype(nexpr, mtype)
+                               if etype == mtype then
+                                       assert ntype != null
+                                       v.modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition for variable `{variable.name}`")
+                               end
                        else
                                mtype = v.visit_expr(nexpr)
                                if mtype == null then return # Skip error
@@ -813,7 +820,15 @@ redef class AReturnExpr
        redef fun accept_typing(v)
        do
                var nexpr = self.n_expr
-               var ret_type = v.mpropdef.as(MMethodDef).msignature.return_mtype
+               var ret_type
+               var mpropdef = v.mpropdef
+               if mpropdef isa MMethodDef then
+                       ret_type = mpropdef.msignature.return_mtype
+               else if mpropdef isa MAttributeDef then
+                       ret_type = mpropdef.static_mtype
+               else
+                       abort
+               end
                if nexpr != null then
                        if ret_type != null then
                                v.visit_expr_subtype(nexpr, ret_type)
@@ -1680,11 +1695,13 @@ redef class ANewExpr
        # The constructor invoked by the new.
        var callsite: nullable CallSite
 
+       # The designated type
+       var recvtype: nullable MClassType
+
        redef fun accept_typing(v)
        do
                var recvtype = v.resolve_mtype(self.n_type)
                if recvtype == null then return
-               self.mtype = recvtype
 
                if not recvtype isa MClassType then
                        if recvtype isa MNullableType then
@@ -1694,16 +1711,10 @@ 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
 
+               self.recvtype = recvtype
+
                var name: String
                var nid = self.n_id
                if nid != null then
@@ -1714,6 +1725,18 @@ redef class ANewExpr
                var callsite = v.get_method(self, recvtype, name, false)
                if callsite == null then return
 
+               if not callsite.mproperty.is_new then
+                       var kind = recvtype.mclass.kind
+                       if kind != concrete_kind then
+                               v.error(self, "Type Error: Cannot instantiate {kind} {recvtype}.")
+                               return
+                       end
+                       self.mtype = recvtype
+               else
+                       self.mtype = callsite.msignature.return_mtype
+                       assert self.mtype != null
+               end
+
                self.callsite = callsite
 
                if not callsite.mproperty.is_init_for(recvtype.mclass) then