Merge: Intern new
authorJean Privat <jean@pryen.org>
Tue, 14 Apr 2015 09:33:32 +0000 (16:33 +0700)
committerJean Privat <jean@pryen.org>
Tue, 14 Apr 2015 09:33:32 +0000 (16:33 +0700)
A small short PR that enables a `new`-factory to instantiate itself.

previously there was no way to do that. The following code will stack-overflow:

~~~nit
class A
   new do
      var res = new A
      res.do_thigns
      return res
   end
end
var a = new A # infinite recursion of `new A`
~~~

Note: this is a very bad example as what is done in the previous `new` should be done in an `init` instead since it is related to the initialization of the object. A `new` factory should be exclusively used for some factory-concern like returning a more specialized object or returning an already existing object.

With this PR, the primitive constructor is available and is called `intern`, as the annotation that indicates things that cannot be programmed in Nit but are provided by the execution engine.

So in the previous example, just use this primitive constructor instead of doing a recursive call:

~~~
      var res = new A.intern
~~~

This intern constructor just do the allocation and the initialization of attributes with default values.
`init` is not called.

Maybe it should not do the initialization of attributes neither but if I skip them, there is no way for the programmer to ask for them manually. whereas `init` in not automatically called but can be called manually.

note: this PR is a small step toward the conclusion of the constructor saga, more will come soon (I hope)

Pull-Request: #1252
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>

1  2 
src/compiler/abstract_compiler.nit
src/interpreter/naive_interpreter.nit
src/semantize/typing.nit

@@@ -2521,13 -2521,6 +2521,13 @@@ redef class ASelfExp
        redef fun expr(v) do return v.frame.arguments.first
  end
  
 +redef class AImplicitSelfExpr
 +      redef fun expr(v) do
 +              if not is_sys then return super
 +              return v.new_expr("glob_sys", mtype.as(not null))
 +      end
 +end
 +
  redef class AEscapeExpr
        redef fun stmt(v) do v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
  end
@@@ -3026,7 -3019,9 +3026,9 @@@ redef class ANewExp
  
                var recv = v.init_instance_or_extern(mtype)
  
-               var callsite = self.callsite.as(not null)
+               var callsite = self.callsite
+               if callsite == null then return recv
                var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
                var res2 = v.compile_callsite(callsite, args)
                if res2 != null then
@@@ -1001,11 -1001,11 +1001,11 @@@ redef class AMethPropde
                        else if pname == "file_exists" then
                                return v.bool_instance(recvval.to_s.file_exists)
                        else if pname == "file_mkdir" then
 -                              recvval.to_s.mkdir
 -                              return null
 +                              var res = recvval.to_s.mkdir
 +                              return v.bool_instance(res == null)
                        else if pname == "file_chdir" then
 -                              recvval.to_s.chdir
 -                              return null
 +                              var res = recvval.to_s.chdir
 +                              return v.bool_instance(res == null)
                        else if pname == "file_realpath" then
                                return v.native_string_instance(recvval.to_s.realpath)
                        else if pname == "get_environ" then
@@@ -1323,14 -1323,6 +1323,14 @@@ redef class ASelfExp
        end
  end
  
 +redef class AImplicitSelfExpr
 +      redef fun expr(v)
 +      do
 +              if not is_sys then return super
 +              return v.mainobj
 +      end
 +end
 +
  redef class AEscapeExpr
        redef fun stmt(v)
        do
@@@ -1807,6 -1799,9 +1807,9 @@@ redef class ANewExp
                var mtype = v.unanchor_type(self.recvtype.as(not null))
                var recv: Instance = new MutableInstance(mtype)
                v.init_instance(recv)
+               var callsite = self.callsite
+               if callsite == null then return recv
                var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
                if args == null then return null
                var res2 = v.callsite(callsite, args)
diff --combined src/semantize/typing.nit
@@@ -52,7 -52,6 +52,7 @@@ private class TypeVisito
        # Is `self` use restricted?
        # * no explicit `self`
        # * method called on the implicit self must be top-level
 +      # Currently only used for `new` factory since there is no valid receiver inside
        var is_toplevel_context = false
  
        init
@@@ -72,7 -71,7 +72,7 @@@
                        selfvariable.declared_type = mclass.mclass_type
  
                        var mprop = mpropdef.mproperty
 -                      if mprop isa MMethod and (mprop.is_toplevel or mprop.is_new) then
 +                      if mprop isa MMethod and mprop.is_new then
                                is_toplevel_context = true
                        end
                end
@@@ -1461,15 -1460,6 +1461,15 @@@ redef class ASelfExp
        end
  end
  
 +redef class AImplicitSelfExpr
 +      # Is the implicit receiver `sys`?
 +      #
 +      # By default, the implicit receiver is `self`.
 +      # But when there is not method for `self`, `sys` is used as a fall-back.
 +      # Is this case this flag is set to `true`.
 +      var is_sys = false
 +end
 +
  ## MESSAGE SENDING AND PROPERTY
  
  redef class ASendExpr
  
        redef fun accept_typing(v)
        do
 -              var recvtype = v.visit_expr(self.n_expr)
 +              var nrecv = self.n_expr
 +              var recvtype = v.visit_expr(nrecv)
                var name = self.property_name
  
                if recvtype == null then return # Forward error
  
 -              var callsite = v.get_method(self, recvtype, name, self.n_expr isa ASelfExpr)
 -              if callsite == null then return
 +              var callsite = null
 +              var unsafe_type = v.anchor_to(recvtype)
 +              var mproperty = v.try_get_mproperty_by_name2(self, unsafe_type, name)
 +              if mproperty == null and nrecv isa AImplicitSelfExpr then
 +                      # Special fall-back search in `sys` when noting found in the implicit receiver.
 +                      var sysclass = v.try_get_mclass(self, "Sys")
 +                      if sysclass != null then
 +                              var systype = sysclass.mclass_type
 +                              mproperty = v.try_get_mproperty_by_name2(self, systype, name)
 +                              if mproperty != null then
 +                                      callsite = v.get_method(self, systype, name, false)
 +                                      if callsite == null then return # Forward error
 +                                      # Update information, we are looking at `sys` now, not `self`
 +                                      nrecv.is_sys = true
 +                                      nrecv.its_variable = null
 +                                      nrecv.mtype = systype
 +                                      recvtype = systype
 +                              end
 +                      end
 +              end
 +              if callsite == null then
 +                      # If still nothing, just exit
 +                      callsite = v.get_method(self, recvtype, name, nrecv isa ASelfExpr)
 +                      if callsite == null then return
 +              end
 +
                self.callsite = callsite
                var msignature = callsite.msignature
  
@@@ -1844,6 -1809,7 +1844,7 @@@ redef class ANewExp
                end
  
                self.recvtype = recvtype
+               var kind = recvtype.mclass.kind
  
                var name: String
                var nid = self.n_id
                else
                        name = "new"
                end
+               if name == "intern" then
+                       if kind != concrete_kind then
+                               v.error(self, "Type Error: Cannot instantiate {kind} {recvtype}.")
+                               return
+                       end
+                       if n_args.n_exprs.not_empty then
+                               v.error(n_args, "Type Error: the intern constructor expects no arguments.")
+                               return
+                       end
+                       # Our job is done
+                       self.mtype = recvtype
+                       return
+               end
                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