Typing of closures
authorJean Privat <jean@pryen.org>
Tue, 20 Jan 2009 23:01:42 +0000 (18:01 -0500)
committerJean Privat <jean@pryen.org>
Tue, 20 Jan 2009 23:01:42 +0000 (18:01 -0500)
src/metamodel/static_type.nit
src/parser/parser_nodes.nit
src/syntax/mmbuilder.nit
src/syntax/syntax_base.nit
src/syntax/typing.nit
tests/sav/error_init_auto.sav
tests/sav/error_init_auto_alt1.sav
tests/sav/error_init_auto_alt2.sav
tests/sav/error_init_auto_alt3.sav

index bf4616f..12d7941 100644 (file)
@@ -82,6 +82,9 @@ class MMSignature
        # The return type
        readable attr _return_type: MMType 
 
+       # The closure parameters
+       readable attr _closures: Array[MMSignature] = new Array[MMSignature]
+
        # Number of parameters
        meth arity: Int
        do
@@ -157,7 +160,11 @@ class MMSignature
                if rv != null then
                        rv = rv.for_module(mod).adapt_to(r)
                end
-               return new MMSignature(p,rv,r)
+               var res = new MMSignature(p,rv,r)
+               for clos in _closures do
+                       res.closures.add(clos.adaptation_to(r))
+               end
+               return res
        end
 
        attr _not_for_self_cache: MMSignature
@@ -188,6 +195,9 @@ class MMSignature
 
                if need_for_self then
                        res = new MMSignature(p, rv, _recv)
+                       for clos in _closures do
+                               res.closures.add(clos.not_for_self)
+                       end
                else
                        res = self
                end
index 21ecbfe..ac89b9f 100644 (file)
@@ -792,6 +792,16 @@ class AVarReassignExpr
 special AVarFormExpr
 special AReassignFormExpr 
 end
+class AClosureCallExpr
+special ACallFormExpr 
+       init(i: TId, a: List[PExpr], c: List[PClosureDef])
+       do
+               _n_id = i
+               _n_args = a
+               _n_closure_defs = c
+               _n_expr = null
+       end
+end
 class ARangeExpr
 special PExpr
     readable writable attr _n_expr: PExpr = null 
index 6f8879e..934b21e 100644 (file)
@@ -390,6 +390,9 @@ private class SignatureBuilder
        # Position of the current star parameter
        readable writable attr _vararg_rank: Int = -1
 
+       # Current closure declarations
+       readable writable attr _closure_decls: Array[AClosureDecl] = new Array[AClosureDecl]
+
        # Current signature
        readable writable attr _signature: MMSignature = null 
 end
@@ -785,6 +788,11 @@ redef class PPropdef
                                v.error(v.signature_builder.untyped_params.first, "Error: Untyped parameter.")
                        else
                                prop.signature = new MMSignature(new Array[MMType], null, v.local_class.get_type)
+                               if v.signature_builder.closure_decls != null then
+                                       for clos in v.signature_builder.closure_decls do
+                                               prop.signature.closures.add(clos.signature)
+                                       end
+                               end
                        end
                end
        end
@@ -1103,6 +1111,9 @@ redef class ASignature
                        if v.signature_builder.vararg_rank >= 0 then
                                v.signature_builder.signature.vararg_rank = v.signature_builder.vararg_rank
                        end
+                       for clos in v.signature_builder.closure_decls do
+                               v.signature_builder.signature.closures.add(clos.signature)
+                       end
                end
        end
 
@@ -1156,6 +1167,28 @@ redef class AParam
        redef meth is_vararg do return n_dotdotdot != null
 end
 
+redef class AClosureDecl
+
+       redef readable attr _signature: MMSignature
+
+       redef readable attr _variable: ClosureVariable
+
+       redef meth accept_property_verifier(v)
+       do
+               var old_signature_builder = v.signature_builder
+               v.signature_builder = new SignatureBuilder
+               super
+               var sig = v.signature_builder.signature
+               if sig == null then
+                       sig = new MMSignature(new Array[MMType], null, v.local_class.get_type)
+               end
+               _signature = sig
+               v.signature_builder = old_signature_builder
+               old_signature_builder.closure_decls.add(self)
+               _variable = new ClosureVariable(n_id.to_symbol, self, sig)
+       end
+end
+
 redef class PType
        # Check that visibilities of types in the signature are compatible with the visibility of the property.
        private meth check_visibility(v: AbsSyntaxVisitor, p: MMLocalProperty) is abstract
index b5ac33b..3da7ef7 100644 (file)
@@ -235,6 +235,22 @@ special Variable
        init(n: Symbol, d: PNode) do super
 end
 
+# False variable corresponding to closures declared in signatures
+# Lives in the same namespace than variables
+class ClosureVariable
+special Variable
+       redef meth kind do return once "closure"
+
+       # The signature of the closure
+       readable attr _signature: MMSignature
+
+       init(n: Symbol, d: PNode, s: MMSignature)
+       do
+               super(n, d)
+               _signature = s
+       end
+end
+
 ###############################################################################
 
 # Visitor used during the syntax analysis
@@ -433,6 +449,14 @@ redef class PParam
        meth variable: ParamVariable is abstract 
 end
 
+redef class PClosureDecl
+       # The signature of the declared closure
+       meth signature: MMSignature is abstract
+
+       # Associated bloc variable
+       meth variable: ClosureVariable is abstract
+end
+
 redef class PType
        # Retrieve the local class corresponding to the type.
        # Display an error and return null if there is no class
@@ -591,3 +615,15 @@ redef class AVarFormExpr
        readable writable attr _variable: Variable 
 end
 
+redef class AClosureCallExpr
+       # Associated closure variable
+       readable writable attr _variable: ClosureVariable
+end
+
+redef class PClosureDef
+       # Associated signature
+       readable writable attr _signature: MMSignature
+
+       # Automatic variables
+       readable writable attr _variables: Array[AutoVariable]
+end
index 8580534..423d970 100644 (file)
@@ -281,12 +281,20 @@ end
 redef class PParam
        redef meth after_typing(v)
        do
+               # TODO: why the test?
                if v.variable_ctx != null then
                        v.variable_ctx.add(variable)
                end
        end
 end
 
+redef class AClosureDecl
+       redef meth after_typing(v)
+       do
+               v.variable_ctx.add(variable)
+       end
+end
+
 redef class PType
        readable attr _stype: MMType
        redef meth after_typing(v)
@@ -696,7 +704,7 @@ special ASuperInitCall
                        register_super_init_call(v, p)
                        if n_args.length > 0 then
                                var signature = get_signature(v, v.self_var.stype, p, true)
-                               _arguments = process_signature(v, signature, p, n_args.to_a)
+                               _arguments = process_signature(v, signature, p.name, n_args.to_a)
                        end
                else
                        v.error(self, "Error: No super method to call for {v.local_property}.")
@@ -787,6 +795,9 @@ end
 
 class AAbsSendExpr
 special PExpr
+       # The signature of the called property
+       readable attr _prop_signature: MMSignature
+
        # Compute the called global property
        private meth do_typing(v: TypingVisitor, type_recv: MMType, is_implicit_self: Bool, recv_is_self: Bool, name: Symbol, raw_args: Array[PExpr])
        do
@@ -794,9 +805,10 @@ special PExpr
                if prop == null then return
                var sig = get_signature(v, type_recv, prop, recv_is_self)
                if sig == null then return
-               var args = process_signature(v, sig, prop, raw_args)
+               var args = process_signature(v, sig, prop.name, raw_args)
                if args == null then return
                _prop = prop
+               _prop_signature = sig
                _arguments = args
        end
 
@@ -836,14 +848,14 @@ special PExpr
        end
        
        # Check the conformity of a set of arguments `raw_args' to a signature.
-       private meth process_signature(v: TypingVisitor, psig: MMSignature, prop: MMMethod, raw_args: Array[PExpr]): Array[PExpr]
+       private meth process_signature(v: TypingVisitor, psig: MMSignature, name: Symbol, raw_args: Array[PExpr]): Array[PExpr]
        do
                var par_vararg = psig.vararg_rank
                var par_arity = psig.arity
                var raw_arity: Int
                if raw_args == null then raw_arity = 0 else raw_arity = raw_args.length
                if par_arity > raw_arity or (par_arity != raw_arity and par_vararg == -1) then
-                       v.error(self, "Error: Method '{prop}' arity missmatch.")
+                       v.error(self, "Error: '{name}' arity missmatch.")
                        return null
                end
                var arg_idx = 0
@@ -954,6 +966,9 @@ special ASuperInitCall
        # Raw arguments used (withour star transformation)
        meth raw_arguments: Array[PExpr] is abstract
 
+       # Closure definitions
+       meth closure_defs: Array[PClosureDef] do return null
+
        redef meth after_typing(v)
        do
                do_all_typing(v)
@@ -964,6 +979,23 @@ special ASuperInitCall
                if not v.check_expr(n_expr) then return
                do_typing(v, n_expr.stype, n_expr.is_implicit_self, n_expr.is_self, name, raw_arguments)
                if prop == null then return
+
+               var cd = closure_defs
+               var cs = _prop_signature.closures # Closure signatures
+               if cd != null then
+                       if cs.length == 0 then
+                               v.error(self, "Error: property {prop} does not require blocs.")
+                       else if cs.length != cd.length then
+                               v.error(self, "Error: property {prop} requires {cs.length} blocs, {cd.length} found.")
+                       else
+                               for i in [0..cs.length[ do
+                                       cd[i].accept_typing2(v, cs[i])
+                               end
+                       end
+               else if cs.length != 0 then
+                       v.error(self, "Error: property {prop} requires {cs.length} blocs.")
+               end
+
                if prop.global.is_init then
                        if not v.local_property.global.is_init then
                                v.error(self, "Error: try to invoke constructor {prop} in a method.")
@@ -1067,22 +1099,39 @@ end
 redef class ACallFormExpr
        redef meth after_typing(v)
        do
-               if n_expr.is_implicit_self then
+               if n_expr != null and n_expr.is_implicit_self then
                        var name = n_id.to_symbol
                        var variable = v.variable_ctx[name]
                        if variable != null then
-                               if not n_args.is_empty then
-                                       v.error(self, "Error: {name} is variable, not a function.")
+                               if variable isa ClosureVariable then
+                                       var n = new AClosureCallExpr(n_id, n_args, n_closure_defs)
+                                       replace_with(n)
+                                       n.variable = variable
+                                       n.after_typing(v)
+                                       return
+                               else
+                                       if not n_args.is_empty then
+                                               v.error(self, "Error: {name} is variable, not a function.")
+                                       end
+                                       var vform = variable_create(variable)
+                                       vform.variable = variable
+                                       replace_with(vform)
+                                       vform.after_typing(v)
+                                       return
                                end
-                               var vform = variable_create(variable)
-                               vform.variable = variable
-                               replace_with(vform)
-                               vform.after_typing(v)
-                               return
                        end
                end
                super
        end
+       
+       redef meth closure_defs
+       do
+               if n_closure_defs == null or n_closure_defs.is_empty then
+                       return null
+               else
+                       return n_closure_defs.to_a
+               end
+       end
 
        # Create a variable acces corresponding to the call form
        meth variable_create(variable: Variable): AVarFormExpr is abstract
@@ -1148,6 +1197,55 @@ redef class AInitExpr
        redef meth raw_arguments do return n_args.to_a
 end
 
+redef class AClosureCallExpr
+       redef meth after_typing(v)
+       do
+               var va = variable
+               var sig = va.signature 
+               var args = process_signature(v, sig, n_id.to_symbol, n_args.to_a)
+               if args == null then return
+               _prop = null
+               _prop_signature = sig
+               _arguments = args
+               _stype = sig.return_type
+       end
+end
+
+redef class PClosureDef
+       attr _accept_typing2: Bool
+       redef meth accept_typing(v)
+       do
+               # Typing is deferred, wait accept_typing2(v)
+               if _accept_typing2 then super
+       end
+
+       private meth accept_typing2(v: TypingVisitor, sig: MMSignature) is abstract
+end
+
+redef class AClosureDef
+       redef meth accept_typing2(v, sig)
+       do      
+               if sig.arity != n_id.length then
+                       v.error(self, "Error: {sig.arity} automatic variable names expected, {n_id.length} found.")
+                       return
+               end
+
+               signature = sig
+
+               v.variable_ctx = v.variable_ctx.sub
+               variables = new Array[AutoVariable]
+               for i in [0..n_id.length[ do
+                       var va = new AutoVariable(n_id[i].to_symbol, self)
+                       variables.add(va)
+                       va.stype = sig[i]
+                       v.variable_ctx.add(va)
+               end
+
+               _accept_typing2 = true
+               accept_typing(v)
+       end
+end
+
 redef class AIsaExpr
        redef meth after_typing(v)
        do
index e12821e..39a09a4 100644 (file)
@@ -1,4 +1,4 @@
-./error_init_auto.nit:34,5--9: Error: Method 'init' arity missmatch.
-./error_init_auto.nit:36,5--14: Error: Method 'init' arity missmatch.
-./error_init_auto.nit:37,5--17: Error: Method 'init' arity missmatch.
+./error_init_auto.nit:34,5--9: Error: 'init' arity missmatch.
+./error_init_auto.nit:36,5--14: Error: 'init' arity missmatch.
+./error_init_auto.nit:37,5--17: Error: 'init' arity missmatch.
 ./error_init_auto.nit:38,5--15: Error: Method 'foo' doesn't exists in A.
index 09505e7..9e5a36d 100644 (file)
@@ -1,4 +1,4 @@
-alt/error_init_auto_alt1.nit:34,5--11: Error: Method 'init' arity missmatch.
-alt/error_init_auto_alt1.nit:35,5--14: Error: Method 'init' arity missmatch.
-alt/error_init_auto_alt1.nit:36,5--17: Error: Method 'init' arity missmatch.
+alt/error_init_auto_alt1.nit:34,5--11: Error: 'init' arity missmatch.
+alt/error_init_auto_alt1.nit:35,5--14: Error: 'init' arity missmatch.
+alt/error_init_auto_alt1.nit:36,5--17: Error: 'init' arity missmatch.
 alt/error_init_auto_alt1.nit:37,5--15: Error: Method 'foo' doesn't exists in A.
index 2cf402b..839cda3 100644 (file)
@@ -1,4 +1,4 @@
-alt/error_init_auto_alt2.nit:33,5--9: Error: Method 'init' arity missmatch.
-alt/error_init_auto_alt2.nit:34,5--11: Error: Method 'init' arity missmatch.
-alt/error_init_auto_alt2.nit:36,5--17: Error: Method 'init' arity missmatch.
+alt/error_init_auto_alt2.nit:33,5--9: Error: 'init' arity missmatch.
+alt/error_init_auto_alt2.nit:34,5--11: Error: 'init' arity missmatch.
+alt/error_init_auto_alt2.nit:36,5--17: Error: 'init' arity missmatch.
 alt/error_init_auto_alt2.nit:37,5--15: Error: Method 'foo' doesn't exists in A.
index 5ec28c2..bd9cc2d 100644 (file)
@@ -1,4 +1,4 @@
-alt/error_init_auto_alt3.nit:34,5--9: Error: Method 'init' arity missmatch.
-alt/error_init_auto_alt3.nit:36,5--14: Error: Method 'init' arity missmatch.
-alt/error_init_auto_alt3.nit:37,5--17: Error: Method 'init' arity missmatch.
+alt/error_init_auto_alt3.nit:34,5--9: Error: 'init' arity missmatch.
+alt/error_init_auto_alt3.nit:36,5--14: Error: 'init' arity missmatch.
+alt/error_init_auto_alt3.nit:37,5--17: Error: 'init' arity missmatch.
 alt/error_init_auto_alt3.nit:38,5--15: Error: Method 'foo' doesn't exists in A.