Merge remote-tracking branch 'origin/master' into init_auto
authorJean Privat <jean@pryen.org>
Sat, 23 Apr 2016 01:48:13 +0000 (21:48 -0400)
committerJean Privat <jean@pryen.org>
Sat, 23 Apr 2016 01:48:13 +0000 (21:48 -0400)
1  2 
src/compiler/abstract_compiler.nit
src/interpreter/naive_interpreter.nit
src/modelize/modelize_property.nit
src/rapid_type_analysis.nit
src/semantize/typing.nit

@@@ -651,6 -651,8 +651,8 @@@ abstract class AbstractCompile
                self.header.add_decl("#include <stdlib.h>")
                self.header.add_decl("#include <stdio.h>")
                self.header.add_decl("#include <string.h>")
+               # longjmp !
+               self.header.add_decl("#include <setjmp.h>\n")
                self.header.add_decl("#include <sys/types.h>\n")
                self.header.add_decl("#include <unistd.h>\n")
                self.header.add_decl("#include <stdint.h>\n")
  
                compile_header_structs
                compile_nitni_structs
+               compile_catch_stack
  
                var gccd_disable = modelbuilder.toolcontext.opt_no_gcc_directive.value
                if gccd_disable.has("noreturn") or gccd_disable.has("all") then
                self.header.add_decl("extern val *glob_sys;")
        end
  
+       # Stack stocking environment for longjumps
+       protected fun compile_catch_stack do
+               self.header.add_decl """
+ struct catch_stack_t {
+       int cursor;
+       jmp_buf envs[100];
+ };
+ extern struct catch_stack_t catchStack;
+ """
+       end
        # Declaration of structures for live Nit types
        protected fun compile_header_structs is abstract
  
@@@ -790,6 -804,7 +804,7 @@@ extern void nitni_global_ref_decr( stru
                v.add_decl("int glob_argc;")
                v.add_decl("char **glob_argv;")
                v.add_decl("val *glob_sys;")
+               v.add_decl("struct catch_stack_t catchStack;")
  
                if self.modelbuilder.toolcontext.opt_typing_test_metrics.value then
                        for tag in count_type_test_tags do
                v.add("signal(SIGPIPE, SIG_IGN);")
  
                v.add("glob_argc = argc; glob_argv = argv;")
+               v.add("catchStack.cursor = -1;")
                v.add("initialize_gc_option();")
  
                v.add "initialize_nitni_global_refs();"
@@@ -1164,6 -1180,29 +1180,6 @@@ abstract class AbstractCompilerVisito
        fun compile_callsite(callsite: CallSite, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
        do
                if callsite.is_broken then return null
 -              var initializers = callsite.mpropdef.initializers
 -              if not initializers.is_empty then
 -                      var recv = arguments.first
 -
 -                      var i = 1
 -                      for p in initializers do
 -                              if p isa MMethod then
 -                                      var args = [recv]
 -                                      for x in p.intro.msignature.mparameters do
 -                                              args.add arguments[i]
 -                                              i += 1
 -                                      end
 -                                      self.send(p, args)
 -                              else if p isa MAttribute then
 -                                      self.write_attribute(p, recv, arguments[i])
 -                                      i += 1
 -                              else abort
 -                      end
 -                      assert i == arguments.length
 -
 -                      return self.send(callsite.mproperty, [recv])
 -              end
 -
                return self.send(callsite.mproperty, arguments)
        end
  
        # of runtime variables to use in the call.
        fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable]
        do
 -              var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
 +              var msignature = mpropdef.msignature.as(not null)
                var res = new Array[RuntimeVariable]
                res.add(recv)
  
                return res
        end
  
+       # Generates a NativeString instance fully escaped in C-style \xHH fashion
+       fun native_string_instance(ns: NativeString, len: Int): RuntimeVariable do
+               var mtype = mmodule.native_string_type
+               var nat = new_var(mtype)
+               var byte_esc = new Buffer.with_cap(len * 4)
+               for i in [0 .. len[ do
+                       byte_esc.append("\\x{ns[i].to_s.substring_from(2)}")
+               end
+               self.add("{nat} = \"{byte_esc}\";")
+               return nat
+       end
        # Generate a string value
        fun string_instance(string: String): RuntimeVariable
        do
        # used by aborts, asserts, casts, etc.
        fun add_abort(message: String)
        do
+               self.add("if(catchStack.cursor >= 0)\{")
+               self.add("longjmp(catchStack.envs[catchStack.cursor], 1);")
+               self.add("\}")
                self.add("PRINT_ERROR(\"Runtime error: %s\", \"{message.escape_to_c}\");")
                add_raw_abort
        end
@@@ -3174,32 -3228,6 +3205,32 @@@ redef class AClassde
                                v.supercall(mpropdef, arguments.first.mtype.as(MClassType), arguments)
                        end
                        return
 +              else if mclassdef.auto_init == mpropdef then
 +                      var recv = arguments.first
 +                      var initializers = mpropdef.initializers
 +                      var no_init = false
 +                      if not initializers.is_empty then
 +
 +                              var i = 1
 +                              for p in initializers do
 +                                      if p isa MMethod then
 +                                              var args = [recv]
 +                                              for x in p.intro.msignature.mparameters do
 +                                                      args.add arguments[i]
 +                                                      i += 1
 +                                              end
 +                                              v.send(p, args)
 +                                              if p.intro.is_calling_init then no_init = true
 +                                      else if p isa MAttribute then
 +                                              v.write_attribute(p, recv, arguments[i])
 +                                              i += 1
 +                                      else abort
 +                              end
 +                              assert i == arguments.length
 +
 +                      end
 +                      if not no_init then v.send(mclass.the_root_init_mmethod.as(not null), [recv])
 +                      return
                else
                        abort
                end
  redef class ADoExpr
        redef fun stmt(v)
        do
-               v.stmt(self.n_block)
-               v.add_escape_label(break_mark)
+               if self.n_catch != null then
+                       v.add("catchStack.cursor += 1;")
+                       v.add("if(!setjmp(catchStack.envs[catchStack.cursor]))\{")
+                       v.stmt(self.n_block)
+                       v.add("catchStack.cursor -= 1;")
+                       v.add("\}else \{")
+                       v.add("catchStack.cursor -= 1;")
+                       v.stmt(self.n_catch)
+                       v.add("\}")
+               else
+                       v.stmt(self.n_block)
+               end
+                       v.add_escape_label(break_mark)
        end
  end
  
@@@ -3589,14 -3628,75 +3631,75 @@@ redef class AArrayExp
        end
  end
  
+ redef class AugmentedStringFormExpr
+       # Factorize the making of a `Regex` object from a literal prefixed string
+       protected fun make_re(v: AbstractCompilerVisitor, rs: RuntimeVariable): nullable RuntimeVariable do
+               var re = to_re
+               assert re != null
+               var res = v.compile_callsite(re, [rs])
+               if res == null then
+                       print "Cannot call property `to_re` on {self}"
+                       abort
+               end
+               for i in suffix.chars do
+                       if i == 'i' then
+                               var ign = ignore_case
+                               assert ign != null
+                               v.compile_callsite(ign, [res, v.bool_instance(true)])
+                               continue
+                       end
+                       if i == 'm' then
+                               var nl = newline
+                               assert nl != null
+                               v.compile_callsite(nl, [res, v.bool_instance(true)])
+                               continue
+                       end
+                       if i == 'b' then
+                               var ext = extended
+                               assert ext != null
+                               v.compile_callsite(ext, [res, v.bool_instance(false)])
+                               continue
+                       end
+                       # Should not happen, this needs to be updated
+                       # along with the addition of new suffixes
+                       abort
+               end
+               return res
+       end
+ end
  redef class AStringFormExpr
-       redef fun expr(v) do return v.string_instance(self.value.as(not null))
+       redef fun expr(v) do return v.string_instance(value)
+ end
+ redef class AStringExpr
+       redef fun expr(v) do
+               var s = v.string_instance(value)
+               if is_string then return s
+               if is_bytestring then
+                       var ns = v.native_string_instance(bytes.items, bytes.length)
+                       var ln = v.int_instance(bytes.length)
+                       var cs = to_bytes_with_copy
+                       assert cs != null
+                       var res = v.compile_callsite(cs, [ns, ln])
+                       assert res != null
+                       s = res
+               else if is_re then
+                       var res = make_re(v, s)
+                       assert res != null
+                       s = res
+               else
+                       print "Unimplemented prefix or suffix for {self}"
+                       abort
+               end
+               return s
+       end
  end
  
  redef class ASuperstringExpr
        redef fun expr(v)
        do
-               var type_string = mtype.as(not null)
+               var type_string = v.mmodule.string_type
  
                # Collect elements of the superstring
                var array = new Array[AExpr]
  
                # Fast join the native string to get the result
                var res = v.send(v.get_property("native_to_s", a.mtype), [a])
+               assert res != null
+               if is_re then res = make_re(v, res)
  
                # We finish to work with the native array,
                # so store it so that it can be reused
                v.add("{varonce} = {a};")
                return res
        end
  end
@@@ -113,17 -113,20 +113,20 @@@ class NaiveInterprete
                return self.modelbuilder.force_get_primitive_method(current_node, name, recv.mclass, self.mainmodule)
        end
  
-       # Is a return executed?
-       # Set this mark to skip the evaluation until the end of the specified method frame
-       var returnmark: nullable FRAME = null
-       # Is a break or a continue executed?
+       # Is a return, a break or a continue executed?
        # Set this mark to skip the evaluation until a labeled statement catch it with `is_escape`
        var escapemark: nullable EscapeMark = null
  
+       # Is an abort being executed ?
+       # Set this mark to return to the last `catch` bloc or effectively aborting if there isn't any
+       var catch_mark = new EscapeMark
+       # The count of `catch` blocs that have been encountered and can catch an abort
+       var catch_count = 0
        # Is a return or a break or a continue executed?
        # Use this function to know if you must skip the evaluation of statements
-       fun is_escaping: Bool do return returnmark != null or escapemark != null
+       fun is_escaping: Bool do return escapemark != null
  
        # The value associated with the current return/break/continue, if any.
        # Set the value when you set a escapemark.
                return instance
        end
  
+       # Return a new native string initialized with `txt`
+       fun native_string_instance_from_ns(txt: NativeString, len: Int): Instance
+       do
+               var instance = native_string_instance_len(len)
+               var val = instance.val
+               txt.copy_to(val, len, 0, 0)
+               return instance
+       end
        # Return a new native string initialized of `length`
        fun native_string_instance_len(length: Int): PrimitiveInstance[NativeString]
        do
        # Return `null` if one of the evaluation of the arguments return null.
        fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: Instance, args: SequenceRead[AExpr]): nullable Array[Instance]
        do
 -              var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
 +              var msignature = mpropdef.msignature.as(not null)
                var res = new Array[Instance]
                res.add(recv)
  
        fun callsite(callsite: nullable CallSite, arguments: Array[Instance]): nullable Instance
        do
                if callsite == null then return null
 -              var initializers = callsite.mpropdef.initializers
 -              if not initializers.is_empty then
 -                      var recv = arguments.first
 -                      var i = 1
 -                      for p in initializers do
 -                              if p isa MMethod then
 -                                      var args = [recv]
 -                                      for x in p.intro.msignature.mparameters do
 -                                              args.add arguments[i]
 -                                              i += 1
 -                                      end
 -                                      self.send(p, args)
 -                              else if p isa MAttribute then
 -                                      assert recv isa MutableInstance
 -                                      write_attribute(p, recv, arguments[i])
 -                                      i += 1
 -                              else abort
 -                      end
 -                      assert i == arguments.length
 -
 -                      return send(callsite.mproperty, [recv])
 -              end
                return send(callsite.mproperty, arguments)
        end
  
@@@ -816,10 -851,8 +829,8 @@@ redef class AMethPropde
                var f = v.new_frame(self, mpropdef, args)
                var res = call_commons(v, mpropdef, args, f)
                v.frames.shift
-               if v.returnmark == f then
-                       v.returnmark = null
+               if v.is_escape(self.return_mark) then
                        res = v.escapevalue
-                       v.escapevalue = null
                        return res
                end
                return res
                                return v.int32_instance(recvval.to_i32)
                        else if pname == "to_u32" then
                                return v.uint32_instance(recvval.to_u32)
-                       else if pname == "rand" then
-                               var res = recvval.rand
-                               return v.int_instance(res)
                        end
                else if cname == "Byte" then
                        var recvval = args[0].to_b
                                return v.float_instance(args[0].to_f.log)
                        else if pname == "pow" then
                                return v.float_instance(args[0].to_f.pow(args[1].to_f))
-                       else if pname == "rand" then
-                               return v.float_instance(args[0].to_f.rand)
                        else if pname == "abs" then
                                return v.float_instance(args[0].to_f.abs)
                        else if pname == "hypot_with" then
@@@ -1518,10 -1546,9 +1524,9 @@@ redef class AAttrPropde
                        val = v.expr(nexpr)
                else if nblock != null then
                        v.stmt(nblock)
-                       assert v.returnmark == f
+                       assert v.escapemark == return_mark
                        val = v.escapevalue
-                       v.returnmark = null
-                       v.escapevalue = null
+                       v.escapemark = null
                else
                        abort
                end
@@@ -1546,31 -1573,6 +1551,31 @@@ redef class AClassde
                                v.call(superpd, arguments)
                        end
                        return null
 +              else if mclassdef.auto_init == mpropdef then
 +                      var recv = arguments.first
 +                      var initializers = mpropdef.initializers
 +                      var no_init = false
 +                      if not initializers.is_empty then
 +                              var i = 1
 +                              for p in initializers do
 +                                      if p isa MMethod then
 +                                              var args = [recv]
 +                                              for x in p.intro.msignature.mparameters do
 +                                                      args.add arguments[i]
 +                                                      i += 1
 +                                              end
 +                                              v.send(p, args)
 +                                              if p.intro.is_calling_init then no_init = true
 +                                      else if p isa MAttribute then
 +                                              assert recv isa MutableInstance
 +                                              v.write_attribute(p, recv, arguments[i])
 +                                              i += 1
 +                                      else abort
 +                              end
 +                              assert i == arguments.length
 +                      end
 +                      if not no_init then v.send(mclass.the_root_init_mmethod.as(not null), [recv])
 +                      return null
                else
                        abort
                end
@@@ -1691,24 -1693,17 +1696,17 @@@ redef class AEscapeExp
        end
  end
  
  redef class AAbortExpr
        redef fun stmt(v)
        do
-               fatal(v, "Aborted")
-               exit(1)
+               # Abort as asked if there is no `catch` bloc
+               if v.catch_count <= 0 then
+                       fatal(v, "Aborted")
+                       exit(1)
+               else
+                       # Abort mode, skipping everything until a `catch` bloc is reached
+                       v.escapemark = v.catch_mark
+               end
        end
  end
  
  redef class ADoExpr
        redef fun stmt(v)
        do
+               # If this bloc has a catch, register it in the counter
+               if self.n_catch != null then v.catch_count += 1
                v.stmt(self.n_block)
                v.is_escape(self.break_mark) # Clear the break (if any)
+               if self.n_catch != null then
+                       v.catch_count -= 1
+                       # Are we in abort mode? then this catch is executing
+                       if v.is_escape(v.catch_mark) then v.stmt(self.n_catch)
+               end
        end
  end
  
@@@ -1971,11 -1973,71 +1976,71 @@@ redef class AArrayExp
        end
  end
  
+ redef class AugmentedStringFormExpr
+       # Factorize the making of a `Regex` object from a literal prefixed string
+       fun make_re(v: NaiveInterpreter, rs: Instance): nullable Instance do
+               var tore = to_re
+               assert tore != null
+               var res = v.callsite(tore, [rs])
+               if res == null then
+                       print "Cannot call property `to_re` on {self}"
+                       abort
+               end
+               for j in suffix.chars do
+                       if j == 'i' then
+                               var prop = ignore_case
+                               assert prop != null
+                               v.callsite(prop, [res, v.bool_instance(true)])
+                               continue
+                       end
+                       if j == 'm' then
+                               var prop = newline
+                               assert prop != null
+                               v.callsite(prop, [res, v.bool_instance(true)])
+                               continue
+                       end
+                       if j == 'b' then
+                               var prop = extended
+                               assert prop != null
+                               v.callsite(prop, [res, v.bool_instance(false)])
+                               continue
+                       end
+                       # Should not happen, this needs to be updated
+                       # along with the addition of new suffixes
+                       abort
+               end
+               return res
+       end
+ end
  redef class AStringFormExpr
-       redef fun expr(v)
-       do
-               var txt = self.value.as(not null)
-               return v.string_instance(txt)
+       redef fun expr(v) do return v.string_instance(value)
+ end
+ redef class AStringExpr
+       redef fun expr(v) do
+               var s = v.string_instance(value)
+               if is_string then return s
+               if is_bytestring then
+                       var ns = v.native_string_instance_from_ns(bytes.items, bytes.length)
+                       var ln = v.int_instance(bytes.length)
+                       var prop = to_bytes_with_copy
+                       assert prop != null
+                       var res = v.callsite(prop, [ns, ln])
+                       if res == null then
+                               print "Cannot call property `to_bytes` on {self}"
+                               abort
+                       end
+                       s = res
+               else if is_re then
+                       var res = make_re(v, s)
+                       assert res != null
+                       s = res
+               else
+                       print "Unimplemented prefix or suffix for {self}"
+                       abort
+               end
+               return s
        end
  end
  
@@@ -1991,6 -2053,7 +2056,7 @@@ redef class ASuperstringExp
                var i = v.array_instance(array, v.mainmodule.object_type)
                var res = v.send(v.force_get_primitive_method("plain_to_s", i.mtype), [i])
                assert res != null
+               if is_re then res = make_re(v, res)
                return res
        end
  end
@@@ -55,9 -55,10 +55,9 @@@ redef class ModelBuilde
                        toolcontext.run_phases_on_npropdef(res)
                        return res
                end
 -              if mpropdef isa MMethodDef and mpropdef.mproperty.is_root_init then
 -                      res = mclassdef2nclassdef.get_or_null(mpropdef.mclassdef)
 -                      if res != null then return res
 -              end
 +              # Fall back to the class node if any.
 +              res = mclassdef2nclassdef.get_or_null(mpropdef.mclassdef)
 +              if res != null then return res
                return null
        end
  
                        var mparameters = new Array[MParameter]
                        var msignature = new MSignature(mparameters, null)
                        mpropdef.msignature = msignature
                        mprop.is_init = true
                        self.toolcontext.info("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
                        the_root_init_mmethod = mprop
 -                      return
                end
  
                # Is there already a constructor defined?
                        if mpropdef.mproperty.is_root_init then
                                assert defined_init == null
                                defined_init = mpropdef
 -                      else if mpropdef.mproperty.name == "init" then
 +                      else if mpropdef.mproperty.name == "autoinit" then
                                # An explicit old-style init named "init", so return
                                return
                        end
                end
  
 +              if mclassdef.auto_init != null then
 +                      return
 +              end
 +
                if not nclassdef isa AStdClassdef then return
  
                # Collect undefined attributes
                if the_root_init_mmethod == null then return
  
                # Look for most-specific new-stype init definitions
 -              var spropdefs = the_root_init_mmethod.lookup_super_definitions(mclassdef.mmodule, mclassdef.bound_mtype)
 -              if spropdefs.is_empty then
 -                      toolcontext.error(nclassdef.location, "Error: `{mclassdef}` does not specialize `{the_root_init_mmethod.intro_mclassdef}`. Possible duplication of the root class `Object`?")
 -                      return
 +              var spropdefs = new ArraySet[MMethodDef]
 +              for x in mclassdef.in_hierarchy.direct_greaters do
 +                      var y = x.mclass.intro.auto_init
 +                      if y == null then continue
 +                      if y.is_broken or y.msignature == null then return
 +                      spropdefs.add y
                end
  
                # Look at the autoinit class-annotation
                                        abort
                                end
                        end
 -              else
 +              else if spropdefs.not_empty then
 +                      # Search for inherited manual autoinit
 +                      var manual = null
 +                      for s in spropdefs do
 +                              if mpropdef2npropdef.has_key(s) then
 +                                      self.toolcontext.info("{mclassdef} inherits a manual autoinit {s}", 3)
 +                                      #mclassdef.autoinit = s
 +                                      #return
 +                                      manual = s
 +                              end
 +                      end
 +
                        # Search the longest-one and checks for conflict
                        var longest = spropdefs.first
                        if spropdefs.length > 1 then
                                # part 1. find the longest list
                                for spd in spropdefs do
                                        if spd.initializers.length > longest.initializers.length then longest = spd
 +                                      if spd != manual and manual != null then
 +                                              self.toolcontext.info("{mclassdef} conflict between manual autoinit {manual} and automatic autoinit {spd}.", 3)
 +                                      end
 +                              end
 +                              # conflict with manual autoinit?
 +                              if longest != manual and manual != null then
 +                                      self.error(nclassdef, "Error: conflict between manual autoinit {manual} and automatic autoinit {longest}.")
                                end
                                # part 2. compare
                                # Check for conflict in the order of initializers
                                mparameters.clear
                                initializers.clear
                        else
 -                              # Can we just inherit?
 -                              if spropdefs.length == 1 and mparameters.is_empty and defined_init == null then
 -                                      self.toolcontext.info("{mclassdef} inherits the basic constructor {longest}", 3)
 -                                      mclassdef.mclass.root_init = longest
 -                                      return
 -                              end
 -
                                # Combine the inherited list to what is collected
                                if longest.initializers.length > 0 then
 -                                      mparameters.prepend longest.new_msignature.mparameters
 +                                      mparameters.prepend longest.msignature.mparameters
                                        initializers.prepend longest.initializers
                                end
                        end
                end
  
 -              # If we already have a basic init definition, then setup its initializers
 -              if defined_init != null then
 -                      defined_init.initializers.add_all(initializers)
 +              # Create a specific new autoinit constructor
 +              do
 +                      var mprop = new MMethod(mclassdef, "autoinit", public_visibility)
 +                      mprop.is_init = true
 +                      var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
 +                      mpropdef.initializers.add_all(initializers)
                        var msignature = new MSignature(mparameters, null)
 -                      defined_init.new_msignature = msignature
 -                      self.toolcontext.info("{mclassdef} extends its basic constructor signature to {defined_init}{msignature}", 3)
 -                      mclassdef.mclass.root_init = defined_init
 -                      return
 +                      mpropdef.msignature = msignature
 +                      mclassdef.auto_init = mpropdef
 +                      self.toolcontext.info("{mclassdef} gets a free auto constructor `{mpropdef}{msignature}`. {spropdefs}", 3)
 +                      #mclassdef.mclass.root_init = mpropdef
 +                      mclassdef.mclass.the_root_init_mmethod = the_root_init_mmethod
                end
 -
 -              # Else create the local implicit basic init definition
 -              var mprop = the_root_init_mmethod
 -              var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
 -              mpropdef.has_supercall = true
 -              mpropdef.initializers.add_all(initializers)
 -              var msignature = new MSignature(mparameters, null)
 -              mpropdef.new_msignature = msignature
 -              mpropdef.msignature = new MSignature(new Array[MParameter], null) # always an empty real signature
 -              self.toolcontext.info("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
 -              mclassdef.mclass.root_init = mpropdef
        end
  
        # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
@@@ -499,15 -492,11 +499,15 @@@ en
  
  redef class MClass
        # The base init of the class.
 -      # Used to get the common new_msignature and initializers
        #
        # TODO: Where to put this information is not clear because unlike other
        # informations, the initialisers are stable in a same class.
        var root_init: nullable MMethodDef = null
 +
 +      # The base init of the class.
 +      #
 +      # TODO: merge with `root_init` and `ModelBuilder::the_root_init_mmethod` if possible
 +      var the_root_init_mmethod: nullable MMethod = null
  end
  
  redef class MClassDef
@@@ -791,9 -780,6 +791,9 @@@ redef class AMethPropde
                        else if n_kwinit != null then
                                name = "init"
                                name_node = n_kwinit
 +                              if self.n_signature.n_params.not_empty or get_single_annotation("old_style_init", modelbuilder) != null then
 +                                      name = "autoinit"
 +                              end
                        else if n_kwnew != null then
                                name = "new"
                                name_node = n_kwnew
  
                var look_like_a_root_init = look_like_a_root_init(modelbuilder, mclassdef)
                var mprop: nullable MMethod = null
 -              if not is_init or n_kwredef != null then mprop = modelbuilder.try_get_mproperty_by_name(name_node, mclassdef, name).as(nullable MMethod)
 +              if not is_init or n_kwredef != null or look_like_a_root_init then mprop = modelbuilder.try_get_mproperty_by_name(name_node, mclassdef, name).as(nullable MMethod)
                if mprop == null and look_like_a_root_init then
                        mprop = modelbuilder.the_root_init_mmethod
                        var nb = n_block
                mclassdef.mprop2npropdef[mprop] = self
  
                var mpropdef = new MMethodDef(mclassdef, mprop, self.location)
 +              if mprop.name == "autoinit" and mclassdef.is_intro then
 +                      assert mclassdef.auto_init == null
 +                      mclassdef.auto_init = mpropdef
 +                      if mpropdef.is_intro then
 +                              mpropdef.initializers.add mprop
 +                              mpropdef.is_calling_init = true
 +                      end
 +              end
  
                set_doc(mpropdef, modelbuilder)
  
                        var root_init = mclassdef.mclass.root_init
                        if root_init != null then
                                # Inherit the initializers by refinement
 -                              mpropdef.new_msignature = root_init.new_msignature
                                assert mpropdef.initializers.is_empty
                                mpropdef.initializers.add_all root_init.initializers
                        end
@@@ -1427,7 -1406,16 +1427,16 @@@ redef class AAttrPropde
                                        var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
                                        if cla != null then mtype = cla.mclass_type
                                else if nexpr isa AStringFormExpr then
-                                       var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
+                                       var cla: nullable MClass
+                                       if nexpr.is_bytestring then
+                                               cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Bytes")
+                                       else if nexpr.is_re then
+                                               cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Regex")
+                                       else if nexpr.is_string then
+                                               cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
+                                       else
+                                               abort
+                                       end
                                        if cla != null then mtype = cla.mclass_type
                                else
                                        modelbuilder.error(self, "Error: untyped attribute `{mreadpropdef}`. Implicit typing allowed only for literals and new.")
@@@ -245,6 -245,7 +245,6 @@@ class RapidTypeAnalysi
                                v.add_monomorphic_send(vararg, self.modelbuilder.force_get_primitive_method(node, "with_native", vararg.mclass, self.mainmodule))
                        end
  
 -                      # TODO? new_msignature
                        var sig = msignature
                        var osig = mmeth.intro.msignature.as(not null)
                        for i in [0..sig.arity[ do
  
                        if npropdef isa AClassdef then
                                if mmethoddef.mproperty.is_root_init then
 +                                      # Final init call
                                        if not mmethoddef.is_intro then
                                                self.add_super_send(v.receiver, mmethoddef)
                                        end
 +                              else if mmethoddef.mclassdef.auto_init == mmethoddef then
 +                                      # autoinit call
 +                                      for i in mmethoddef.initializers do
 +                                              if i isa MMethod then self.add_send(v.receiver, i)
 +                                      end
                                else
                                        npropdef.debug "cannot RTA {mmethoddef}"
                                        abort
@@@ -590,6 -585,11 +590,11 @@@ redef class AStringFormExp
                v.add_type(native)
                var prop = v.get_method(native, "to_s_full")
                v.add_monomorphic_send(native, prop)
+               v.add_callsite(to_re)
+               v.add_callsite(ignore_case)
+               v.add_callsite(newline)
+               v.add_callsite(extended)
+               v.add_callsite(to_bytes_with_copy)
        end
  end
  
diff --combined src/semantize/typing.nit
@@@ -318,12 -318,8 +318,12 @@@ private class TypeVisito
  
                var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
                if name == "new" and mproperty == null then
 -                      name = "init"
 +                      name = "autoinit"
                        mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
 +                      if mproperty == null then
 +                              name = "init"
 +                              mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
 +                      end
                end
  
                if mproperty == null then
                end
  
  
 -              var msignature = mpropdef.new_msignature or else mpropdef.msignature
 +              var msignature = mpropdef.msignature
                if msignature == null then return null # skip error
                msignature = resolve_for(msignature, recvtype, recv_is_self).as(MSignature)
  
@@@ -1135,6 -1131,7 +1135,7 @@@ redef class ADoExp
        redef fun accept_typing(v)
        do
                v.visit_stmt(n_block)
+               v.visit_stmt(n_catch)
                self.is_typed = true
        end
  end
@@@ -1473,21 -1470,59 +1474,59 @@@ redef class ACharExp
        end
  end
  
- redef class AStringFormExpr
-       redef fun accept_typing(v)
-       do
+ redef class AugmentedStringFormExpr
+       super AExpr
+       # Text::to_re, used for prefix `re`
+       var to_re: nullable CallSite = null
+       # Regex::ignore_case, used for suffix `i` on `re`
+       var ignore_case: nullable CallSite = null
+       # Regex::newline, used for suffix `m` on `re`
+       var newline: nullable CallSite = null
+       # Regex::extended, used for suffix `b` on `re`
+       var extended: nullable CallSite = null
+       # NativeString::to_bytes_with_copy, used for prefix `b`
+       var to_bytes_with_copy: nullable CallSite = null
+       redef fun accept_typing(v) do
                var mclass = v.get_mclass(self, "String")
                if mclass == null then return # Forward error
-               self.mtype = mclass.mclass_type
+               if is_bytestring then
+                       to_bytes_with_copy = v.get_method(self, v.mmodule.native_string_type, "to_bytes_with_copy", false)
+                       mclass = v.get_mclass(self, "Bytes")
+               else if is_re then
+                       to_re = v.get_method(self, mclass.mclass_type, "to_re", false)
+                       for i in suffix.chars do
+                               mclass = v.get_mclass(self, "Regex")
+                               if mclass == null then
+                                       v.error(self, "Error: `Regex` class unknown")
+                                       return
+                               end
+                               var service = ""
+                               if i == 'i' then
+                                       service = "ignore_case="
+                                       ignore_case = v.get_method(self, mclass.mclass_type, service, false)
+                               else if i == 'm' then
+                                       service = "newline="
+                                       newline = v.get_method(self, mclass.mclass_type, service, false)
+                               else if i == 'b' then
+                                       service = "extended="
+                                       extended = v.get_method(self, mclass.mclass_type, service, false)
+                               else
+                                       v.error(self, "Type Error: Unrecognized suffix {i} in prefixed Regex")
+                                       abort
+                               end
+                       end
+               end
+               if mclass == null then return # Forward error
+               mtype = mclass.mclass_type
        end
  end
  
  redef class ASuperstringExpr
        redef fun accept_typing(v)
        do
-               var mclass = v.get_mclass(self, "String")
-               if mclass == null then return # Forward error
-               self.mtype = mclass.mclass_type
+               super
                var objclass = v.get_mclass(self, "Object")
                if objclass == null then return # Forward error
                var objtype = objclass.mclass_type
@@@ -1601,7 -1636,7 +1640,7 @@@ redef class ARangeExp
                # get the constructor
                var callsite
                if self isa ACrangeExpr then
 -                      callsite = v.get_method(self, mtype, "init", false)
 +                      callsite = v.get_method(self, mtype, "autoinit", false)
                else if self isa AOrangeExpr then
                        callsite = v.get_method(self, mtype, "without_last", false)
                else
@@@ -1932,7 -1967,7 +1971,7 @@@ redef class ABraReassignExp
  end
  
  redef class AInitExpr
 -      redef fun property_name do return "init"
 +      redef fun property_name do if n_args.n_exprs.is_empty then return "init" else return "autoinit"
        redef fun property_node do return n_kwinit
        redef fun compute_raw_arguments do return n_args.to_a
  end
@@@ -2032,7 -2067,7 +2071,7 @@@ redef class ASuperExp
                        return
                end
  
 -              var msignature = superprop.new_msignature or else superprop.msignature.as(not null)
 +              var msignature = superprop.msignature.as(not null)
                msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
  
                var callsite = new CallSite(hot_location, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)