Merge: Autocast and literal arrays
authorJean Privat <jean@pryen.org>
Sat, 18 Apr 2015 09:47:17 +0000 (16:47 +0700)
committerJean Privat <jean@pryen.org>
Sat, 18 Apr 2015 09:47:17 +0000 (16:47 +0700)
Small bugfixes

* forbid autocasts in combined assignments and literal arrays
* keep autocast information in transform
* rta visits implicit methods of literal arrays

Only the first one was the original bug I wanted to fix, the two others where discovered and solved while writing the PR.

Pull-Request: #1272
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Romain Chanoir <chanoir.romain@courrier.uqam.ca>

1  2 
src/semantize/typing.nit

diff --combined src/semantize/typing.nit
@@@ -105,13 -105,13 +105,13 @@@ private class TypeVisito
        # If `sub` is a safe subtype of `sup` then return `sub`.
        # If `sub` is an unsafe subtype (ie an implicit cast is required), then return `sup`.
        #
-       # The point of the return type is to determinate the usable type on an expression:
+       # The point of the return type is to determinate the usable type on an expression when `autocast` is true:
        # If the suptype is safe, then the return type is the one on the expression typed by `sub`.
        # Is the subtype is unsafe, then the return type is the one of an implicit cast on `sup`.
-       fun check_subtype(node: ANode, sub, sup: MType): nullable MType
+       fun check_subtype(node: ANode, sub, sup: MType, autocast: Bool): nullable MType
        do
                if self.is_subtype(sub, sup) then return sub
-               if self.is_subtype(sub, self.anchor_to(sup)) then
+               if autocast and self.is_subtype(sub, self.anchor_to(sup)) then
                        # FIXME workaround to the current unsafe typing policy. To remove once fixed virtual types exists.
                        #node.debug("Unsafe typing: expected {sup}, got {sub}")
                        return sup
  
                if sup == null then return null # Forward error
  
-               var res = check_subtype(nexpr, sub, sup)
+               var res = check_subtype(nexpr, sub, sup, true)
                if res != sub then
                        nexpr.implicit_cast_to = res
                end
        # Visit the expressions of args and check their conformity with the corresponding type in signature
        # The point of this method is to handle varargs correctly
        # Note: The signature must be correctly adapted
 -      fun check_signature(node: ANode, args: Array[AExpr], mproperty: MProperty, msignature: MSignature): Bool
 +      fun check_signature(node: ANode, args: Array[AExpr], mproperty: MProperty, msignature: MSignature): nullable SignatureMap
        do
                var vararg_rank = msignature.vararg_rank
                if vararg_rank >= 0 then
                        if args.length < msignature.arity then
                                modelbuilder.error(node, "Error: expected at least {msignature.arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.")
 -                              return false
 +                              return null
                        end
                else if args.length != msignature.arity then
                        modelbuilder.error(node, "Error: expected {msignature.arity} argument(s) for `{mproperty}{msignature}`; got {args.length}. See introduction at `{mproperty.full_name}`.")
 -                      return false
 +                      return null
                end
  
                #debug("CALL {unsafe_type}.{msignature}")
  
 +              # Associate each parameter to a position in the arguments
 +              var map = new SignatureMap
 +
                var vararg_decl = args.length - msignature.arity
 +              var j = 0
                for i in [0..msignature.arity[ do
 -                      var j = i
 -                      if i == vararg_rank then continue # skip the vararg
 -                      if i > vararg_rank then
 -                              j = i + vararg_decl
 +                      var param = msignature.mparameters[i]
 +                      var arg = args[j]
 +                      map.map[i] = j
 +                      j += 1
 +
 +                      if i == vararg_rank then
 +                              j += vararg_decl
 +                              continue # skip the vararg
                        end
 -                      var paramtype = msignature.mparameters[i].mtype
 -                      self.visit_expr_subtype(args[j], paramtype)
 +
 +                      var paramtype = param.mtype
 +                      self.visit_expr_subtype(arg, paramtype)
                end
                if vararg_rank >= 0 then
                        var paramtype = msignature.mparameters[vararg_rank].mtype
                        var first = args[vararg_rank]
                        if vararg_decl == 0 and first isa AVarargExpr then
                                var mclass = get_mclass(node, "Array")
 -                              if mclass == null then return false # Forward error
 +                              if mclass == null then return null # Forward error
                                var array_mtype = mclass.get_mtype([paramtype])
                                self.visit_expr_subtype(first.n_expr, array_mtype)
                                first.mtype  = first.n_expr.mtype
                        else
 -                              for j in [vararg_rank..vararg_rank+vararg_decl] do
 -                                      self.visit_expr_subtype(args[j], paramtype)
 +                              map.vararg_decl = vararg_decl + 1
 +                              for i in [vararg_rank..vararg_rank+vararg_decl] do
 +                                      self.visit_expr_subtype(args[i], paramtype)
                                end
                        end
                end
 -              return true
 +
 +              return map
        end
  
        fun error(node: ANode, message: String)
        end
  end
  
 +# Mapping between parameters and arguments in a call.
 +#
 +# Parameters and arguments are not stored in the class but referenced by their position (starting from 0)
 +#
 +# The point of this class is to help engine and other things to map arguments in the AST to parameters of the model.
 +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.
  class CallSite
        # The associated node for location
        # Is a implicit cast required on erasure typing policy?
        var erasure_cast: Bool
  
 +      # The mapping used on the call to associate arguments to parameters
 +      # If null then no specific association is required.
 +      var signaturemap: nullable SignatureMap = null
 +
        private fun check_signature(v: TypeVisitor, args: Array[AExpr]): Bool
        do
 -              return v.check_signature(self.node, args, self.mproperty, self.msignature)
 +              var map = v.check_signature(self.node, args, self.mproperty, self.msignature)
 +              signaturemap = map
 +              return map == null
        end
  end
  
@@@ -868,7 -837,7 +868,7 @@@ redef class AReassignFormExp
                var value_type = v.visit_expr_subtype(self.n_value, msignature.mparameters.first.mtype)
                if value_type == null then return null # Skip error
  
-               v.check_subtype(self, rettype, writetype)
+               v.check_subtype(self, rettype, writetype, false)
                return rettype
        end
  end
@@@ -1360,7 -1329,7 +1360,7 @@@ redef class AArrayExp
                        end
                        set_comprehension(e)
                        if mtype != null then
-                               if v.check_subtype(e, t, mtype) == null then return # Skip error
+                               if v.check_subtype(e, t, mtype, false) == null then return # Forward error
                                if t == mtype then useless = true
                        else
                                mtypes.add(t)
@@@ -1768,7 -1737,7 +1768,7 @@@ redef class ASuperExp
                msignature = v.resolve_for(msignature, recvtype, true).as(MSignature)
                var args = self.n_args.to_a
                if args.length > 0 then
 -                      v.check_signature(self, args, mproperty, msignature)
 +                      signaturemap = v.check_signature(self, args, mproperty, msignature)
                end
                self.mtype = msignature.return_mtype
                self.is_typed = true
                mpropdef = v.mpropdef.as(MMethodDef)
        end
  
 +      # The mapping used on the call to associate arguments to parameters.
 +      # If null then no specific association is required.
 +      var signaturemap: nullable SignatureMap
 +
        private fun process_superinit(v: TypeVisitor)
        do
                var anchor = v.anchor