src: use `as_notnullable` in code
[nit.git] / src / typing.nit
index fd0197d..d2cc5fa 100644 (file)
@@ -34,46 +34,69 @@ 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
@@ -166,8 +189,6 @@ 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
@@ -178,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}'.")
@@ -232,6 +251,15 @@ private class TypeVisitor
                end
 
                assert mproperty isa MMethod
+
+               if is_toplevel_context and recv_is_self and not mproperty.is_toplevel and name != "sys" and name != "exit" then
+                       # FIXME named methods are here as a workaround
+                       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
@@ -256,7 +284,7 @@ private class TypeVisitor
                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
@@ -476,9 +504,8 @@ redef class AMethPropdef
                var nblock = self.n_block
                if nblock == null then return
 
-               var nclassdef = self.parent.as(AClassdef)
                var mpropdef = self.mpropdef.as(not null)
-               var v = new TypeVisitor(modelbuilder, nclassdef, mpropdef)
+               var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
                self.selfvariable = v.selfvariable
 
                var mmethoddef = self.mpropdef.as(not null)
@@ -505,8 +532,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
@@ -825,7 +852,7 @@ redef class AForExpr
                if objcla == null then return
 
                # check iterator method
-               var itdef = v.get_method(self, mtype, "iterator", true)
+               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
@@ -878,7 +905,7 @@ redef class AForExpr
                # anchor formal and virtual types
                if mtype.need_anchor then mtype = v.anchor_to(mtype)
 
-               if mtype isa MNullableType then mtype = mtype.mtype
+               mtype = mtype.as_notnullable
                self.coltype = mtype.as(MClassType)
 
                # get methods is_ok, next, item
@@ -981,9 +1008,7 @@ 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
@@ -1054,7 +1079,7 @@ 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
@@ -1167,6 +1192,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
@@ -1175,8 +1202,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
 
@@ -1191,6 +1228,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)
@@ -1436,7 +1476,8 @@ redef class ASuperExpr
 
        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")
@@ -1468,12 +1509,13 @@ redef class ASuperExpr
 
        private fun process_superinit(v: TypeVisitor)
        do
-               var recvtype = v.nclassdef.mclassdef.bound_mtype
+               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)