Merge: CallSite on AFor and ARange
authorJean Privat <jean@pryen.org>
Fri, 28 Mar 2014 22:13:12 +0000 (18:13 -0400)
committerJean Privat <jean@pryen.org>
Fri, 28 Mar 2014 22:13:21 +0000 (18:13 -0400)
Use CallSite to resolve and type some implicit services.
Subsequent phases will like them!

Currenlty: all the AFor and ARange services are converted and tools updated.
TODO: Array and SuperString

Pull-Request: #370
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

1  2 
src/naive_interpreter.nit
src/rapid_type_analysis.nit
src/typing.nit

@@@ -249,7 -249,7 +249,7 @@@ private class NaiveInterprete
        # Return a new native string initialized with `txt`
        fun native_string_instance(txt: String): Instance
        do
 -              var val = new Buffer.from(txt)
 +              var val = new FlatBuffer.from(txt)
                val.add('\0')
                var ic = self.mainmodule.get_primitive_class("NativeString")
                return new PrimitiveInstance[Buffer](ic.mclass_type, val)
        # Return a stack stace. One line per function
        fun stack_trace: String
        do
 -              var b = new Buffer
 +              var b = new FlatBuffer
                b.append(",---- Stack trace -- - -  -\n")
                for f in frames do
                        b.append("| {f.mpropdef} ({f.current_node.location})\n")
@@@ -771,7 -771,7 +771,7 @@@ redef class AInternMethPropde
                                return null
                        else if pname == "copy_to" then
                                # sig= copy_to(dest: NativeString, length: Int, from: Int, to: Int)
 -                              var destval = args[1].val.as(Buffer)
 +                              var destval = args[1].val.as(FlatBuffer)
                                var lenval = args[2].to_i
                                var fromval = args[3].to_i
                                var toval = args[4].to_i
                                if toval + lenval >= destval.length then
                                        debug("Illegal access on {destval} for element {toval}+{lenval}/{destval.length}")
                                end
 -                              recvval.copy(fromval, lenval, destval, toval)
 +                              recvval.as(FlatBuffer).copy(fromval, lenval, destval, toval)
                                return null
                        else if pname == "atoi" then
                                return v.int_instance(recvval.to_i)
@@@ -874,12 -874,12 +874,12 @@@ redef class AExternMethPropde
                        var recvval = args.first.val
                        if pname == "io_write" then
                                var a1 = args[1].val.as(Buffer)
 -                              recvval.as(OStream).write(a1.substring(0, args[2].to_i))
 +                              recvval.as(OStream).write(a1.substring(0, args[2].to_i).to_s)
                                return args[2]
                        else if pname == "io_read" then
                                var str = recvval.as(IStream).read(args[2].to_i)
                                var a1 = args[1].val.as(Buffer)
 -                              new Buffer.from(str).copy(0, str.length, a1, 0)
 +                              new FlatBuffer.from(str).copy(0, str.length, a1.as(FlatBuffer), 0)
                                return v.int_instance(str.length)
                        else if pname == "io_close" then
                                recvval.as(IOS).close
@@@ -1261,19 -1261,19 +1261,19 @@@ redef class AForExp
                if col.mtype isa MNullType then fatal(v, "Receiver is null")
  
                #self.debug("col {col}")
-               var iter = v.send(v.force_get_primitive_method("iterator", col.mtype), [col]).as(not null)
+               var iter = v.callsite(method_iterator, [col]).as(not null)
                #self.debug("iter {iter}")
                loop
-                       var isok = v.send(v.force_get_primitive_method("is_ok", iter.mtype), [iter]).as(not null)
+                       var isok = v.callsite(method_is_ok, [iter]).as(not null)
                        if not isok.is_true then return
                        if self.variables.length == 1 then
-                               var item = v.send(v.force_get_primitive_method("item", iter.mtype), [iter]).as(not null)
+                               var item = v.callsite(method_item, [iter]).as(not null)
                                #self.debug("item {item}")
                                v.frame.map[self.variables.first] = item
                        else if self.variables.length == 2 then
-                               var key = v.send(v.force_get_primitive_method("key", iter.mtype), [iter]).as(not null)
+                               var key = v.callsite(method_key, [iter]).as(not null)
                                v.frame.map[self.variables[0]] = key
-                               var item = v.send(v.force_get_primitive_method("item", iter.mtype), [iter]).as(not null)
+                               var item = v.callsite(method_item, [iter]).as(not null)
                                v.frame.map[self.variables[1]] = item
                        else
                                abort
                        if v.is_break(self.escapemark) then return
                        v.is_continue(self.escapemark) # Clear the break
                        if v.is_escaping then return
-                       v.send(v.force_get_primitive_method("next", iter.mtype), [iter])
+                       v.callsite(method_next, [iter])
                end
        end
  end
@@@ -1427,7 -1427,7 +1427,7 @@@ redef class ACrangeExp
                var mtype = v.unanchor_type(self.mtype.as(not null))
                var res = new MutableInstance(mtype)
                v.init_instance(res)
-               v.send(v.force_get_primitive_method("init", mtype), [res, e1, e2])
+               v.callsite(init_callsite, [res, e1, e2])
                return res
        end
  end
@@@ -1442,7 -1442,7 +1442,7 @@@ redef class AOrangeExp
                var mtype = v.unanchor_type(self.mtype.as(not null))
                var res = new MutableInstance(mtype)
                v.init_instance(res)
-               v.send(v.force_get_primitive_method("without_last", mtype), [res, e1, e2])
+               v.callsite(init_callsite, [res, e1, e2])
                return res
        end
  end
@@@ -31,8 -31,6 +31,8 @@@ import auto_super_ini
  import csv # for live_types_to_csv
  import ordered_tree # for live_methods_to_tree
  
 +private import more_collections
 +
  redef class ModelBuilder
        fun do_rapid_type_analysis(mainmodule: MModule): RapidTypeAnalysis
        do
@@@ -77,36 -75,6 +77,36 @@@ class RapidTypeAnalysi
        # Live methods.
        var live_methods = new HashSet[MMethod]
  
 +      # Live callsites.
 +      var live_callsites = new HashSet[CallSite]
 +
 +      private var live_targets_cache = new HashMap2[MType, MProperty, Set[MMethodDef]]
 +
 +      # The live targets of a specific callsite.
 +      fun live_targets(callsite: CallSite): Set[MMethodDef]
 +      do
 +              var mtype = callsite.recv
 +              var anchor = callsite.anchor
 +              if anchor != null then mtype = mtype.anchor_to(callsite.mmodule, anchor)
 +              if mtype isa MNullableType then mtype = mtype.mtype
 +              assert mtype isa MClassType
 +              mtype = mtype.mclass.intro.bound_mtype
 +              var mproperty = callsite.mproperty
 +              var res = live_targets_cache[mtype, mproperty]
 +              if res != null then return res
 +              res = new ArraySet[MMethodDef]
 +              live_targets_cache[mtype, mproperty] = res
 +
 +              for c in live_classes do
 +                      var tc = c.intro.bound_mtype
 +                      if not tc.is_subtype(mainmodule, null, mtype) then continue
 +                      var d = mproperty.lookup_first_definition(mainmodule, tc)
 +                      res.add d
 +              end
 +
 +              return res
 +      end
 +
        # Live call-to-super.
        var live_super_sends = new HashSet[MMethodDef]
  
@@@ -474,10 -442,7 +474,10 @@@ class RapidTypeVisito
  
        fun add_cast_type(mtype: MType) do analysis.add_cast(mtype)
  
 -      fun add_callsite(callsite: nullable CallSite) do if callsite != null then analysis.add_send(callsite.recv, callsite.mproperty)
 +      fun add_callsite(callsite: nullable CallSite) do if callsite != null then
 +              analysis.add_send(callsite.recv, callsite.mproperty)
 +              analysis.live_callsites.add(callsite)
 +      end
  end
  
  ###
@@@ -550,8 -515,7 +550,7 @@@ redef class ACrangeExp
        do
                var mtype = self.mtype.as(MClassType)
                v.add_type(mtype)
-               var prop = v.get_method(mtype, "init")
-               v.add_monomorphic_send(mtype, prop)
+               v.add_callsite(init_callsite)
        end
  end
  
@@@ -560,8 -524,7 +559,7 @@@ redef class AOrangeExp
        do
                var mtype = self.mtype.as(MClassType)
                v.add_type(mtype)
-               var prop = v.get_method(mtype, "without_last")
-               v.add_monomorphic_send(mtype, prop)
+               v.add_callsite(init_callsite)
        end
  end
  
@@@ -640,22 -603,17 +638,17 @@@ en
  redef class AForExpr
        redef fun accept_rapid_type_visitor(v)
        do
-               var recvtype = self.n_expr.mtype.as(not null)
-               var colltype = self.coltype.as(not null)
-               var itmeth = v.get_method(colltype, "iterator")
-               v.add_send(recvtype, itmeth)
-               var iteratortype = itmeth.intro.msignature.return_mtype.as(MClassType).mclass.intro.bound_mtype
-               var objtype = v.get_class("Object").mclass_type
-               v.add_send(objtype, v.get_method(iteratortype, "is_ok"))
+               v.add_callsite(self.method_iterator)
+               v.add_callsite(self.method_is_ok)
                if self.variables.length == 1 then
-                       v.add_send(objtype, v.get_method(iteratortype, "item"))
+                       v.add_callsite(self.method_item)
                else if self.variables.length == 2 then
-                       v.add_send(objtype, v.get_method(iteratortype, "key"))
-                       v.add_send(objtype, v.get_method(iteratortype, "item"))
+                       v.add_callsite(self.method_key)
+                       v.add_callsite(self.method_item)
                else
                        abort
                end
-               v.add_send(objtype, v.get_method(iteratortype, "next"))
+               v.add_callsite(self.method_next)
        end
  end
  
diff --combined src/typing.nit
@@@ -242,8 -242,8 +242,8 @@@ private class TypeVisito
                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 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
  
                        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,15 -386,9 +386,15 @@@ class CallSit
        # 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
@@@ -816,11 -810,11 +816,11 @@@ en
  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 objcla == null then return
  
                # 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: 'for' expects a type providing 'iterator' method, got '{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: 'for' expects a type providing 'iterator' method, got '{mtype}'.")
                        return
                end
-               self.method_iterator = itdef.mproperty
+               self.method_iterator = itdef
  
                # check that iterator return something
                var ittype = itdef.msignature.return_mtype
                        v.error(self, "Type Error: 'for' expects a method 'is_ok' in 'Iterator' type {ittype}.")
                        return
                end
-               self.method_is_ok = ikdef.mproperty
+               self.method_is_ok = ikdef
  
                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.mproperty
+               self.method_item = itemdef
  
                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.mproperty
+               self.method_next = nextdef
  
                if is_map then
                        var keydef = v.get_method(self, ittype, "key", false)
                                v.error(self, "Type Error: 'for' expects a method 'key' in 'Iterator' type {ittype}.")
                                return
                        end
-                       self.method_key = keydef.mproperty
+                       self.method_key = keydef
                end
        end
  
@@@ -1101,6 -1085,8 +1091,8 @@@ redef class AArrayExp
  end
  
  redef class ARangeExpr
+       var init_callsite: nullable CallSite
        redef fun accept_typing(v)
        do
                var discrete_class = v.get_mclass(self, "Discrete")
                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
  
@@@ -1497,7 -1498,7 +1504,7 @@@ redef class ASuperExp
                end
  
                var msignature = v.resolve_signature_for(superprop, recvtype, true)
 -              var callsite = new CallSite(self, recvtype, true, superprop.mproperty, superprop, msignature, false)
 +              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