Merge remote-tracking branch 'origin/master' into init_auto
[nit.git] / src / semantize / typing.nit
index 8a23a73..5f4c2dc 100644 (file)
@@ -117,6 +117,7 @@ private class TypeVisitor
                        #node.debug("Unsafe typing: expected {sup}, got {sub}")
                        return sup
                end
+               if sup isa MBottomType then return null # Skip error
                if sub.need_anchor then
                        var u = anchor_to(sub)
                        self.modelbuilder.error(node, "Type Error: expected `{sup}`, got `{sub}: {u}`.")
@@ -151,7 +152,11 @@ private class TypeVisitor
                        end
                        return null # forward error
                end
-               self.error(nexpr, "Error: expected an expression.")
+               var more_message = null
+               var p = nexpr.parent
+               if p != null then more_message = p.bad_expr_message(nexpr)
+               if more_message == null then more_message = "" else more_message = " " + more_message
+               self.error(nexpr, "Error: expected an expression{more_message}.")
                return null
        end
 
@@ -313,8 +318,12 @@ private class TypeVisitor
 
                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
@@ -373,7 +382,7 @@ private class TypeVisitor
                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)
 
@@ -489,8 +498,12 @@ private class TypeVisitor
                                continue # skip the vararg
                        end
 
-                       var paramtype = param.mtype
-                       self.visit_expr_subtype(arg, paramtype)
+                       if not param.is_vararg then
+                               var paramtype = param.mtype
+                               self.visit_expr_subtype(arg, paramtype)
+                       else
+                               check_one_vararg(arg, param)
+                       end
                end
 
                if min_arity > 0 then
@@ -508,27 +521,9 @@ private class TypeVisitor
                        var paramtype = msignature.mparameters[vararg_rank].mtype
                        var first = args[vararg_rank]
                        if vararg_decl == 0 then
-                               var mclass = get_mclass(node, "Array")
-                               if mclass == null then return null # Forward error
-                               var array_mtype = mclass.get_mtype([paramtype])
-                               if first isa AVarargExpr then
-                                       self.visit_expr_subtype(first.n_expr, array_mtype)
-                                       first.mtype  = first.n_expr.mtype
-                               else
-                                       # only one vararg, maybe `...` was forgot, so be gentle!
-                                       var t = visit_expr(first)
-                                       if t == null then return null # Forward error
-                                       if not is_subtype(t, paramtype) and is_subtype(t, array_mtype) then
-                                               # Not acceptable but could be a `...`
-                                               error(first, "Type Error: expected `{paramtype}`, got `{t}`. Is an ellipsis `...` missing on the argument?")
-                                               return null
-                                       end
-                                       # Standard valid vararg, finish the job
-                                       map.vararg_decl = 1
-                                       self.visit_expr_subtype(first, paramtype)
-                               end
+                               if not check_one_vararg(first, msignature.mparameters[vararg_rank]) then return null
                        else
-                               map.vararg_decl = vararg_decl + 1
+                               first.vararg_decl = vararg_decl + 1
                                for i in [vararg_rank..vararg_rank+vararg_decl] do
                                        self.visit_expr_subtype(args[i], paramtype)
                                end
@@ -538,6 +533,33 @@ private class TypeVisitor
                return map
        end
 
+       # Check an expression as a single vararg.
+       # The main point of the method if to handle the case of reversed vararg (see `AVarargExpr`)
+       fun check_one_vararg(arg: AExpr, param: MParameter): Bool
+       do
+               var paramtype = param.mtype
+               var mclass = get_mclass(arg, "Array")
+               if mclass == null then return false # Forward error
+               var array_mtype = mclass.get_mtype([paramtype])
+               if arg isa AVarargExpr then
+                       self.visit_expr_subtype(arg.n_expr, array_mtype)
+                       arg.mtype  = arg.n_expr.mtype
+               else
+                       # only one vararg, maybe `...` was forgot, so be gentle!
+                       var t = visit_expr(arg)
+                       if t == null then return false # Forward error
+                       if not is_subtype(t, paramtype) and is_subtype(t, array_mtype) then
+                               # Not acceptable but could be a `...`
+                               error(arg, "Type Error: expected `{paramtype}`, got `{t}`. Is an ellipsis `...` missing on the argument?")
+                               return false
+                       end
+                       # Standard valid vararg, finish the job
+                       arg.vararg_decl = 1
+                       self.visit_expr_subtype(arg, paramtype)
+               end
+               return true
+       end
+
        fun error(node: ANode, message: String)
        do
                self.modelbuilder.error(node, message)
@@ -613,10 +635,6 @@ end
 class SignatureMap
        # Associate a parameter to an argument
        var map = new ArrayMap[Int, Int]
-
-       # The length of the vararg sequence
-       # 0 if no vararg or if reverse vararg (cf `AVarargExpr`)
-       var vararg_decl: Int = 0
 end
 
 # A specific method call site with its associated informations.
@@ -792,6 +810,12 @@ end
 
 redef class ANode
        private fun accept_post_typing(v: TypeVisitor) do end
+
+       # An additional information message to explain the role of a child expression.
+       #
+       # The point of the method is to allow some kind of double dispatch so the parent
+       # choose how to describe its children.
+       private fun bad_expr_message(child: AExpr): nullable String do return null
 end
 
 redef class AAttrPropdef
@@ -852,6 +876,15 @@ redef class AExpr
        # The result of the evaluation of `self` must be
        # stored inside the designated array (there is an implicit `push`)
        var comprehension: nullable AArrayExpr = null
+
+       # It indicates the number of arguments collected as a vararg.
+       #
+       # When 0, the argument is used as is, without transformation.
+       # When 1, the argument is transformed into an singleton array.
+       # Above 1, the arguments and the next ones are transformed into a common array.
+       #
+       # This attribute is meaning less on expressions not used as attributes.
+       var vararg_decl: Int = 0
 end
 
 redef class ABlockExpr
@@ -1102,6 +1135,7 @@ redef class ADoExpr
        redef fun accept_typing(v)
        do
                v.visit_stmt(n_block)
+               v.visit_stmt(n_catch)
                self.is_typed = true
        end
 end
@@ -1134,6 +1168,7 @@ redef class AForExpr
                        var mtype = v.visit_expr(g.n_expr)
                        if mtype == null then return
                        g.do_type_iterator(v, mtype)
+                       if g.is_broken then is_broken = true
                end
 
                v.visit_stmt(n_block)
@@ -1425,29 +1460,73 @@ redef class AFloatExpr
 end
 
 redef class ACharExpr
-       redef fun accept_typing(v)
-       do
-               var mclass = v.get_mclass(self, "Char")
+       redef fun accept_typing(v) do
+               var mclass: nullable MClass = null
+               if is_ascii then
+                       mclass = v.get_mclass(self, "Byte")
+               else if is_code_point then
+                       mclass = v.get_mclass(self, "Int")
+               else
+                       mclass = v.get_mclass(self, "Char")
+               end
                if mclass == null then return # Forward error
                self.mtype = mclass.mclass_type
        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
@@ -1561,7 +1640,7 @@ redef class ARangeExpr
                # 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
@@ -1690,6 +1769,14 @@ redef class ASendExpr
        # The property invoked by the send.
        var callsite: nullable CallSite
 
+       redef fun bad_expr_message(child)
+       do
+               if child == self.n_expr then
+                       return "to be the receiver of `{self.property_name}`"
+               end
+               return null
+       end
+
        redef fun accept_typing(v)
        do
                var nrecv = self.n_expr
@@ -1884,7 +1971,7 @@ redef class ABraReassignExpr
 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
@@ -1984,7 +2071,7 @@ redef class ASuperExpr
                        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)