[pypy-commit] pypy py3k: function annotations and correct implement of kwonly defaults

gutworth noreply at buildbot.pypy.org
Wed Mar 14 21:40:32 CET 2012


Author: Benjamin Peterson <benjamin at python.org>
Branch: py3k
Changeset: r53599:f688cf0d9bce
Date: 2012-03-14 15:33 -0500
http://bitbucket.org/pypy/pypy/changeset/f688cf0d9bce/

Log:	function annotations and correct implement of kwonly defaults

diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py
--- a/pypy/interpreter/argument.py
+++ b/pypy/interpreter/argument.py
@@ -262,7 +262,7 @@
     # XXX: this should be @jit.look_inside_iff, but we need key word arguments,
     # and it doesn't support them for now.
     def _match_signature(self, w_firstarg, scope_w, signature, defaults_w=None,
-                         blindargs=0):
+                         w_kw_defs=None, blindargs=0):
         """Parse args and kwargs according to the signature of a code object,
         or raise an ArgErr in case of failure.
         Return the number of arguments filled in.
@@ -270,19 +270,19 @@
         if jit.we_are_jitted() and self._dont_jit:
             return self._match_signature_jit_opaque(w_firstarg, scope_w,
                                                     signature, defaults_w,
-                                                    blindargs)
+                                                    w_kw_defs, blindargs)
         return self._really_match_signature(w_firstarg, scope_w, signature,
-                                            defaults_w, blindargs)
+                                            defaults_w, w_kw_defs, blindargs)
 
     @jit.dont_look_inside
     def _match_signature_jit_opaque(self, w_firstarg, scope_w, signature,
-                                    defaults_w, blindargs):
+                                    defaults_w, w_kw_defs, blindargs):
         return self._really_match_signature(w_firstarg, scope_w, signature,
-                                            defaults_w, blindargs)
+                                            defaults_w, w_kw_defs, blindargs)
 
     @jit.unroll_safe
     def _really_match_signature(self, w_firstarg, scope_w, signature,
-                                defaults_w=None, blindargs=0):
+                                defaults_w=None, w_kw_defs=None, blindargs=0):
         #
         #   args_w = list of the normal actual parameters, wrapped
         #   kwds_w = real dictionary {'keyword': wrapped parameter}
@@ -350,7 +350,7 @@
         elif avail > co_argcount:
             raise ArgErrCount(avail, num_kwds,
                               co_argcount, has_vararg, has_kwarg,
-                              defaults_w, 0)
+                              defaults_w, w_kw_defs, 0)
 
         # the code assumes that keywords can potentially be large, but that
         # argnames is typically not too large
@@ -384,8 +384,8 @@
                     num_remainingkwds -= 1
         missing = 0
         if input_argcount < co_argcount + co_kwonlyargcount:
-            def_first = co_argcount + co_kwonlyargcount - (0 if defaults_w is None else len(defaults_w))
-            for i in range(input_argcount, co_argcount + co_kwonlyargcount):
+            def_first = co_argcount - (0 if defaults_w is None else len(defaults_w))
+            for i in range(input_argcount, co_argcount):
                 if scope_w[i] is not None:
                     continue
                 defnum = i - def_first
@@ -396,6 +396,19 @@
                     # because it might be related to a problem with */** or
                     # keyword arguments, which will be checked for below.
                     missing += 1
+            for i in range(co_argcount, co_argcount + co_kwonlyargcount):
+                if scope_w[i] is not None:
+                    continue
+                elif w_kw_defs is None:
+                    missing += 1
+                    continue
+                name = signature.kwonlyargnames[i - co_argcount]
+                w_name = self.space.wrap(name)
+                w_def = self.space.finditem(w_kw_defs, w_name)
+                if w_def is not None:
+                    scope_w[i] = w_def
+                else:
+                    missing += 1
 
         # TODO: Put a nice error message
         #if co_kwonlyargcount:
@@ -422,21 +435,22 @@
             if co_argcount == 0:
                 raise ArgErrCount(avail, num_kwds,
                               co_argcount, has_vararg, has_kwarg,
-                              defaults_w, missing)
+                              defaults_w, w_kw_defs, missing)
             raise ArgErrUnknownKwds(self.space, num_remainingkwds, keywords,
                                     used_keywords, self.keyword_names_w)
 
         if missing:
             raise ArgErrCount(avail, num_kwds,
                               co_argcount, has_vararg, has_kwarg,
-                              defaults_w, missing)
+                              defaults_w, w_kw_defs, missing)
 
         return co_argcount + has_vararg + has_kwarg + co_kwonlyargcount
 
 
 
     def parse_into_scope(self, w_firstarg,
-                         scope_w, fnname, signature, defaults_w=None):
+                         scope_w, fnname, signature, defaults_w=None,
+                         w_kw_defs=None):
         """Parse args and kwargs to initialize a frame
         according to the signature of code object.
         Store the argumentvalues into scope_w.
@@ -444,29 +458,32 @@
         """
         try:
             return self._match_signature(w_firstarg,
-                                         scope_w, signature, defaults_w, 0)
+                                         scope_w, signature, defaults_w,
+                                         w_kw_defs, 0)
         except ArgErr, e:
             raise operationerrfmt(self.space.w_TypeError,
                                   "%s() %s", fnname, e.getmsg())
 
-    def _parse(self, w_firstarg, signature, defaults_w, blindargs=0):
+    def _parse(self, w_firstarg, signature, defaults_w, w_kw_defs, blindargs=0):
         """Parse args and kwargs according to the signature of a code object,
         or raise an ArgErr in case of failure.
         """
         scopelen = signature.scope_length()
         scope_w = [None] * scopelen
         self._match_signature(w_firstarg, scope_w, signature, defaults_w,
-                              blindargs)
+                              w_kw_defs, blindargs)
         return scope_w
 
 
     def parse_obj(self, w_firstarg,
-                  fnname, signature, defaults_w=None, blindargs=0):
+                  fnname, signature, defaults_w=None, w_kw_defs=None,
+                  blindargs=0):
         """Parse args and kwargs to initialize a frame
         according to the signature of code object.
         """
         try:
-            return self._parse(w_firstarg, signature, defaults_w, blindargs)
+            return self._parse(w_firstarg, signature, defaults_w, w_kw_defs,
+                               blindargs)
         except ArgErr, e:
             raise operationerrfmt(self.space.w_TypeError,
                                   "%s() %s", fnname, e.getmsg())
@@ -522,22 +539,22 @@
 
 
     def _match_signature(self, w_firstarg, scope_w, signature, defaults_w=None,
-                         blindargs=0):
+                         w_kw_defs=None, blindargs=0):
         self.combine_if_necessary()
         # _match_signature is destructive
         return Arguments._match_signature(
                self, w_firstarg, scope_w, signature,
-               defaults_w, blindargs)
+               defaults_w, w_kw_defs, blindargs)
 
     def unpack(self):
         self.combine_if_necessary()
         return Arguments.unpack(self)
 
-    def match_signature(self, signature, defaults_w):
+    def match_signature(self, signature, defaults_w, w_kw_defs=None):
         """Parse args and kwargs according to the signature of a code object,
         or raise an ArgErr in case of failure.
         """
-        return self._parse(None, signature, defaults_w)
+        return self._parse(None, signature, defaults_w, w_kw_defs)
 
     def unmatch_signature(self, signature, data_w):
         """kind of inverse of match_signature"""
@@ -650,7 +667,7 @@
 class ArgErrCount(ArgErr):
 
     def __init__(self, got_nargs, nkwds, expected_nargs, has_vararg, has_kwarg,
-                 defaults_w, missing_args):
+                 defaults_w, w_kw_defs, missing_args):
         self.expected_nargs = expected_nargs
         self.has_vararg = has_vararg
         self.has_kwarg = has_kwarg
diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -611,10 +611,10 @@
     return 1 - arg
 
 def _compute_MAKE_CLOSURE(arg):
-    return -arg - 1
+    return -1 - _num_args(arg) - ((arg >> 16) & 0xFFFF)
 
 def _compute_MAKE_FUNCTION(arg):
-    return -arg
+    return -_num_args(arg) - ((arg >> 16) & 0xFFFF)
 
 def _compute_BUILD_SLICE(arg):
     if arg == 3:
diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py
--- a/pypy/interpreter/astcompiler/ast.py
+++ b/pypy/interpreter/astcompiler/ast.py
@@ -242,15 +242,16 @@
 
 class FunctionDef(stmt):
 
-    def __init__(self, name, args, body, decorator_list, lineno, col_offset):
+    def __init__(self, name, args, body, decorator_list, returns, lineno, col_offset):
         self.name = name
         self.args = args
         self.body = body
         self.w_body = None
         self.decorator_list = decorator_list
         self.w_decorator_list = None
+        self.returns = returns
         stmt.__init__(self, lineno, col_offset)
-        self.initialization_state = 63
+        self.initialization_state = 127
 
     def walkabout(self, visitor):
         visitor.visit_FunctionDef(self)
@@ -261,13 +262,16 @@
             visitor._mutate_sequence(self.body)
         if self.decorator_list:
             visitor._mutate_sequence(self.decorator_list)
+        if self.returns:
+            self.returns = self.returns.mutate_over(visitor)
         return visitor.visit_FunctionDef(self)
 
     def sync_app_attrs(self, space):
-        if (self.initialization_state & ~0) ^ 63:
-            self.missing_field(space, ['lineno', 'col_offset', 'name', 'args', 'body', 'decorator_list'], 'FunctionDef')
+        if (self.initialization_state & ~64) ^ 63:
+            self.missing_field(space, ['lineno', 'col_offset', 'name', 'args', 'body', 'decorator_list', None], 'FunctionDef')
         else:
-            pass
+            if not self.initialization_state & 64:
+                self.returns = None
         self.args.sync_app_attrs(space)
         w_list = self.w_body
         if w_list is not None:
@@ -289,6 +293,8 @@
         if self.decorator_list is not None:
             for node in self.decorator_list:
                 node.sync_app_attrs(space)
+        if self.returns:
+            self.returns.sync_app_attrs(space)
 
 
 class ClassDef(stmt):
@@ -2300,57 +2306,75 @@
 
 class arguments(AST):
 
-    def __init__(self, args, vararg, kwonlyargs, kwarg, defaults):
+    def __init__(self, args, vararg, varargannotation, kwonlyargs, kwarg, kwargannotation, defaults, kw_defaults):
         self.args = args
         self.w_args = None
         self.vararg = vararg
+        self.varargannotation = varargannotation
         self.kwonlyargs = kwonlyargs
         self.w_kwonlyargs = None
         self.kwarg = kwarg
+        self.kwargannotation = kwargannotation
         self.defaults = defaults
         self.w_defaults = None
-        self.initialization_state = 31
+        self.kw_defaults = kw_defaults
+        self.w_kw_defaults = None
+        self.initialization_state = 255
 
     def mutate_over(self, visitor):
         if self.args:
             visitor._mutate_sequence(self.args)
+        if self.varargannotation:
+            self.varargannotation = self.varargannotation.mutate_over(visitor)
         if self.kwonlyargs:
             visitor._mutate_sequence(self.kwonlyargs)
+        if self.kwargannotation:
+            self.kwargannotation = self.kwargannotation.mutate_over(visitor)
         if self.defaults:
             visitor._mutate_sequence(self.defaults)
+        if self.kw_defaults:
+            visitor._mutate_sequence(self.kw_defaults)
         return visitor.visit_arguments(self)
 
     def walkabout(self, visitor):
         visitor.visit_arguments(self)
 
     def sync_app_attrs(self, space):
-        if (self.initialization_state & ~10) ^ 21:
-            self.missing_field(space, ['args', None, 'kwonlyargs', None, 'defaults'], 'arguments')
+        if (self.initialization_state & ~54) ^ 201:
+            self.missing_field(space, ['args', None, None, 'kwonlyargs', None, None, 'defaults', 'kw_defaults'], 'arguments')
         else:
             if not self.initialization_state & 2:
                 self.vararg = None
-            if not self.initialization_state & 8:
+            if not self.initialization_state & 4:
+                self.varargannotation = None
+            if not self.initialization_state & 16:
                 self.kwarg = None
+            if not self.initialization_state & 32:
+                self.kwargannotation = None
         w_list = self.w_args
         if w_list is not None:
             list_w = space.listview(w_list)
             if list_w:
-                self.args = [space.interp_w(expr, w_obj) for w_obj in list_w]
+                self.args = [space.interp_w(arg, w_obj) for w_obj in list_w]
             else:
                 self.args = None
         if self.args is not None:
             for node in self.args:
                 node.sync_app_attrs(space)
+        if self.varargannotation:
+            self.varargannotation.sync_app_attrs(space)
         w_list = self.w_kwonlyargs
         if w_list is not None:
             list_w = space.listview(w_list)
             if list_w:
-                self.kwonlyargs = [space.interp_w(expr, w_obj) for w_obj in list_w]
+                self.kwonlyargs = [space.interp_w(arg, w_obj) for w_obj in list_w]
             else:
                 self.kwonlyargs = None
         if self.kwonlyargs is not None:
             for node in self.kwonlyargs:
                 node.sync_app_attrs(space)
+        if self.kwargannotation:
+            self.kwargannotation.sync_app_attrs(space)
         w_list = self.w_defaults
         if w_list is not None:
             list_w = space.listview(w_list)
@@ -2361,6 +2385,40 @@
         if self.defaults is not None:
             for node in self.defaults:
                 node.sync_app_attrs(space)
+        w_list = self.w_kw_defaults
+        if w_list is not None:
+            list_w = space.listview(w_list)
+            if list_w:
+                self.kw_defaults = [space.interp_w(expr, w_obj) for w_obj in list_w]
+            else:
+                self.kw_defaults = None
+        if self.kw_defaults is not None:
+            for node in self.kw_defaults:
+                node.sync_app_attrs(space)
+
+class arg(AST):
+
+    def __init__(self, arg, annotation):
+        self.arg = arg
+        self.annotation = annotation
+        self.initialization_state = 3
+
+    def mutate_over(self, visitor):
+        if self.annotation:
+            self.annotation = self.annotation.mutate_over(visitor)
+        return visitor.visit_arg(self)
+
+    def walkabout(self, visitor):
+        visitor.visit_arg(self)
+
+    def sync_app_attrs(self, space):
+        if (self.initialization_state & ~2) ^ 1:
+            self.missing_field(space, ['arg', None], 'arg')
+        else:
+            if not self.initialization_state & 2:
+                self.annotation = None
+        if self.annotation:
+            self.annotation.sync_app_attrs(space)
 
 class keyword(AST):
 
@@ -2415,7 +2473,8 @@
 
     def _mutate_sequence(self, seq):
         for i in range(len(seq)):
-            seq[i] = seq[i].mutate_over(self)
+            if seq[i] is not None:
+                seq[i] = seq[i].mutate_over(self)
 
     def visit_Module(self, node):
         return self.default_visitor(node)
@@ -2531,6 +2590,8 @@
         return self.default_visitor(node)
     def visit_arguments(self, node):
         return self.default_visitor(node)
+    def visit_arg(self, node):
+        return self.default_visitor(node)
     def visit_keyword(self, node):
         return self.default_visitor(node)
     def visit_alias(self, node):
@@ -2554,6 +2615,8 @@
         node.args.walkabout(self)
         self.visit_sequence(node.body)
         self.visit_sequence(node.decorator_list)
+        if node.returns:
+            node.returns.walkabout(self)
 
     def visit_ClassDef(self, node):
         self.visit_sequence(node.bases)
@@ -2766,8 +2829,17 @@
 
     def visit_arguments(self, node):
         self.visit_sequence(node.args)
+        if node.varargannotation:
+            node.varargannotation.walkabout(self)
         self.visit_sequence(node.kwonlyargs)
+        if node.kwargannotation:
+            node.kwargannotation.walkabout(self)
         self.visit_sequence(node.defaults)
+        self.visit_sequence(node.kw_defaults)
+
+    def visit_arg(self, node):
+        if node.annotation:
+            node.annotation.walkabout(self)
 
     def visit_keyword(self, node):
         node.value.walkabout(self)
@@ -3083,15 +3155,38 @@
     w_self.w_decorator_list = w_new_value
     w_self.initialization_state |= 32
 
-_FunctionDef_field_unroller = unrolling_iterable(['name', 'args', 'body', 'decorator_list'])
+def FunctionDef_get_returns(space, w_self):
+    if w_self.w_dict is not None:
+        w_obj = w_self.getdictvalue(space, 'returns')
+        if w_obj is not None:
+            return w_obj
+    if not w_self.initialization_state & 64:
+        typename = space.type(w_self).getname(space)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'returns')
+    return space.wrap(w_self.returns)
+
+def FunctionDef_set_returns(space, w_self, w_new_value):
+    try:
+        w_self.returns = space.interp_w(expr, w_new_value, True)
+        if type(w_self.returns) is expr:
+            raise OperationError(space.w_TypeError, space.w_None)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+        w_self.setdictvalue(space, 'returns', w_new_value)
+        return
+    w_self.deldictvalue(space, 'returns')
+    w_self.initialization_state |= 64
+
+_FunctionDef_field_unroller = unrolling_iterable(['name', 'args', 'body', 'decorator_list', 'returns'])
 def FunctionDef_init(space, w_self, __args__):
     w_self = space.descr_self_interp_w(FunctionDef, w_self)
     w_self.w_body = None
     w_self.w_decorator_list = None
     args_w, kwargs_w = __args__.unpack()
     if args_w:
-        if len(args_w) != 4:
-            w_err = space.wrap("FunctionDef constructor takes either 0 or 4 positional arguments")
+        if len(args_w) != 5:
+            w_err = space.wrap("FunctionDef constructor takes either 0 or 5 positional arguments")
             raise OperationError(space.w_TypeError, w_err)
         i = 0
         for field in _FunctionDef_field_unroller:
@@ -3103,11 +3198,12 @@
 FunctionDef.typedef = typedef.TypeDef("FunctionDef",
     stmt.typedef,
     __module__='_ast',
-    _fields=_FieldsWrapper(['name', 'args', 'body', 'decorator_list']),
+    _fields=_FieldsWrapper(['name', 'args', 'body', 'decorator_list', 'returns']),
     name=typedef.GetSetProperty(FunctionDef_get_name, FunctionDef_set_name, cls=FunctionDef),
     args=typedef.GetSetProperty(FunctionDef_get_args, FunctionDef_set_args, cls=FunctionDef),
     body=typedef.GetSetProperty(FunctionDef_get_body, FunctionDef_set_body, cls=FunctionDef),
     decorator_list=typedef.GetSetProperty(FunctionDef_get_decorator_list, FunctionDef_set_decorator_list, cls=FunctionDef),
+    returns=typedef.GetSetProperty(FunctionDef_get_returns, FunctionDef_set_returns, cls=FunctionDef),
     __new__=interp2app(get_AST_new(FunctionDef)),
     __init__=interp2app(FunctionDef_init),
 )
@@ -6993,8 +7089,31 @@
     w_self.deldictvalue(space, 'vararg')
     w_self.initialization_state |= 2
 
+def arguments_get_varargannotation(space, w_self):
+    if w_self.w_dict is not None:
+        w_obj = w_self.getdictvalue(space, 'varargannotation')
+        if w_obj is not None:
+            return w_obj
+    if not w_self.initialization_state & 4:
+        typename = space.type(w_self).getname(space)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'varargannotation')
+    return space.wrap(w_self.varargannotation)
+
+def arguments_set_varargannotation(space, w_self, w_new_value):
+    try:
+        w_self.varargannotation = space.interp_w(expr, w_new_value, True)
+        if type(w_self.varargannotation) is expr:
+            raise OperationError(space.w_TypeError, space.w_None)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+        w_self.setdictvalue(space, 'varargannotation', w_new_value)
+        return
+    w_self.deldictvalue(space, 'varargannotation')
+    w_self.initialization_state |= 4
+
 def arguments_get_kwonlyargs(space, w_self):
-    if not w_self.initialization_state & 4:
+    if not w_self.initialization_state & 8:
         typename = space.type(w_self).getname(space)
         raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwonlyargs')
     if w_self.w_kwonlyargs is None:
@@ -7008,14 +7127,14 @@
 
 def arguments_set_kwonlyargs(space, w_self, w_new_value):
     w_self.w_kwonlyargs = w_new_value
-    w_self.initialization_state |= 4
+    w_self.initialization_state |= 8
 
 def arguments_get_kwarg(space, w_self):
     if w_self.w_dict is not None:
         w_obj = w_self.getdictvalue(space, 'kwarg')
         if w_obj is not None:
             return w_obj
-    if not w_self.initialization_state & 8:
+    if not w_self.initialization_state & 16:
         typename = space.type(w_self).getname(space)
         raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwarg')
     return space.wrap(w_self.kwarg)
@@ -7032,10 +7151,33 @@
         w_self.setdictvalue(space, 'kwarg', w_new_value)
         return
     w_self.deldictvalue(space, 'kwarg')
-    w_self.initialization_state |= 8
+    w_self.initialization_state |= 16
+
+def arguments_get_kwargannotation(space, w_self):
+    if w_self.w_dict is not None:
+        w_obj = w_self.getdictvalue(space, 'kwargannotation')
+        if w_obj is not None:
+            return w_obj
+    if not w_self.initialization_state & 32:
+        typename = space.type(w_self).getname(space)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwargannotation')
+    return space.wrap(w_self.kwargannotation)
+
+def arguments_set_kwargannotation(space, w_self, w_new_value):
+    try:
+        w_self.kwargannotation = space.interp_w(expr, w_new_value, True)
+        if type(w_self.kwargannotation) is expr:
+            raise OperationError(space.w_TypeError, space.w_None)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+        w_self.setdictvalue(space, 'kwargannotation', w_new_value)
+        return
+    w_self.deldictvalue(space, 'kwargannotation')
+    w_self.initialization_state |= 32
 
 def arguments_get_defaults(space, w_self):
-    if not w_self.initialization_state & 16:
+    if not w_self.initialization_state & 64:
         typename = space.type(w_self).getname(space)
         raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'defaults')
     if w_self.w_defaults is None:
@@ -7049,18 +7191,36 @@
 
 def arguments_set_defaults(space, w_self, w_new_value):
     w_self.w_defaults = w_new_value
-    w_self.initialization_state |= 16
-
-_arguments_field_unroller = unrolling_iterable(['args', 'vararg', 'kwonlyargs', 'kwarg', 'defaults'])
+    w_self.initialization_state |= 64
+
+def arguments_get_kw_defaults(space, w_self):
+    if not w_self.initialization_state & 128:
+        typename = space.type(w_self).getname(space)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kw_defaults')
+    if w_self.w_kw_defaults is None:
+        if w_self.kw_defaults is None:
+            list_w = []
+        else:
+            list_w = [space.wrap(node) for node in w_self.kw_defaults]
+        w_list = space.newlist(list_w)
+        w_self.w_kw_defaults = w_list
+    return w_self.w_kw_defaults
+
+def arguments_set_kw_defaults(space, w_self, w_new_value):
+    w_self.w_kw_defaults = w_new_value
+    w_self.initialization_state |= 128
+
+_arguments_field_unroller = unrolling_iterable(['args', 'vararg', 'varargannotation', 'kwonlyargs', 'kwarg', 'kwargannotation', 'defaults', 'kw_defaults'])
 def arguments_init(space, w_self, __args__):
     w_self = space.descr_self_interp_w(arguments, w_self)
     w_self.w_args = None
     w_self.w_kwonlyargs = None
     w_self.w_defaults = None
+    w_self.w_kw_defaults = None
     args_w, kwargs_w = __args__.unpack()
     if args_w:
-        if len(args_w) != 5:
-            w_err = space.wrap("arguments constructor takes either 0 or 5 positional arguments")
+        if len(args_w) != 8:
+            w_err = space.wrap("arguments constructor takes either 0 or 8 positional arguments")
             raise OperationError(space.w_TypeError, w_err)
         i = 0
         for field in _arguments_field_unroller:
@@ -7072,16 +7232,88 @@
 arguments.typedef = typedef.TypeDef("arguments",
     AST.typedef,
     __module__='_ast',
-    _fields=_FieldsWrapper(['args', 'vararg', 'kwonlyargs', 'kwarg', 'defaults']),
+    _fields=_FieldsWrapper(['args', 'vararg', 'varargannotation', 'kwonlyargs', 'kwarg', 'kwargannotation', 'defaults', 'kw_defaults']),
     args=typedef.GetSetProperty(arguments_get_args, arguments_set_args, cls=arguments),
     vararg=typedef.GetSetProperty(arguments_get_vararg, arguments_set_vararg, cls=arguments),
+    varargannotation=typedef.GetSetProperty(arguments_get_varargannotation, arguments_set_varargannotation, cls=arguments),
     kwonlyargs=typedef.GetSetProperty(arguments_get_kwonlyargs, arguments_set_kwonlyargs, cls=arguments),
     kwarg=typedef.GetSetProperty(arguments_get_kwarg, arguments_set_kwarg, cls=arguments),
+    kwargannotation=typedef.GetSetProperty(arguments_get_kwargannotation, arguments_set_kwargannotation, cls=arguments),
     defaults=typedef.GetSetProperty(arguments_get_defaults, arguments_set_defaults, cls=arguments),
+    kw_defaults=typedef.GetSetProperty(arguments_get_kw_defaults, arguments_set_kw_defaults, cls=arguments),
     __new__=interp2app(get_AST_new(arguments)),
     __init__=interp2app(arguments_init),
 )
 
+def arg_get_arg(space, w_self):
+    if w_self.w_dict is not None:
+        w_obj = w_self.getdictvalue(space, 'arg')
+        if w_obj is not None:
+            return w_obj
+    if not w_self.initialization_state & 1:
+        typename = space.type(w_self).getname(space)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'arg')
+    return space.wrap(w_self.arg)
+
+def arg_set_arg(space, w_self, w_new_value):
+    try:
+        w_self.arg = space.str_w(w_new_value)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+        w_self.setdictvalue(space, 'arg', w_new_value)
+        return
+    w_self.deldictvalue(space, 'arg')
+    w_self.initialization_state |= 1
+
+def arg_get_annotation(space, w_self):
+    if w_self.w_dict is not None:
+        w_obj = w_self.getdictvalue(space, 'annotation')
+        if w_obj is not None:
+            return w_obj
+    if not w_self.initialization_state & 2:
+        typename = space.type(w_self).getname(space)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'annotation')
+    return space.wrap(w_self.annotation)
+
+def arg_set_annotation(space, w_self, w_new_value):
+    try:
+        w_self.annotation = space.interp_w(expr, w_new_value, True)
+        if type(w_self.annotation) is expr:
+            raise OperationError(space.w_TypeError, space.w_None)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+        w_self.setdictvalue(space, 'annotation', w_new_value)
+        return
+    w_self.deldictvalue(space, 'annotation')
+    w_self.initialization_state |= 2
+
+_arg_field_unroller = unrolling_iterable(['arg', 'annotation'])
+def arg_init(space, w_self, __args__):
+    w_self = space.descr_self_interp_w(arg, w_self)
+    args_w, kwargs_w = __args__.unpack()
+    if args_w:
+        if len(args_w) != 2:
+            w_err = space.wrap("arg constructor takes either 0 or 2 positional arguments")
+            raise OperationError(space.w_TypeError, w_err)
+        i = 0
+        for field in _arg_field_unroller:
+            space.setattr(w_self, space.wrap(field), args_w[i])
+            i += 1
+    for field, w_value in kwargs_w.iteritems():
+        space.setattr(w_self, space.wrap(field), w_value)
+
+arg.typedef = typedef.TypeDef("arg",
+    AST.typedef,
+    __module__='_ast',
+    _fields=_FieldsWrapper(['arg', 'annotation']),
+    arg=typedef.GetSetProperty(arg_get_arg, arg_set_arg, cls=arg),
+    annotation=typedef.GetSetProperty(arg_get_annotation, arg_set_annotation, cls=arg),
+    __new__=interp2app(get_AST_new(arg)),
+    __init__=interp2app(arg_init),
+)
+
 def keyword_get_arg(space, w_self):
     if w_self.w_dict is not None:
         w_obj = w_self.getdictvalue(space, 'arg')
diff --git a/pypy/interpreter/astcompiler/astbuilder.py b/pypy/interpreter/astcompiler/astbuilder.py
--- a/pypy/interpreter/astcompiler/astbuilder.py
+++ b/pypy/interpreter/astcompiler/astbuilder.py
@@ -462,8 +462,13 @@
         name = name_node.value
         self.check_forbidden_name(name, name_node)
         args = self.handle_arguments(funcdef_node.children[2])
-        body = self.handle_suite(funcdef_node.children[4])
-        return ast.FunctionDef(name, args, body, decorators,
+        suite = 4
+        returns = None
+        if funcdef_node.children[3].type == tokens.RARROW:
+            returns = self.handle_expr(funcdef_node.children[4])
+            suite += 2
+        body = self.handle_suite(funcdef_node.children[suite])
+        return ast.FunctionDef(name, args, body, decorators, returns,
                                funcdef_node.lineno, funcdef_node.column)
 
     def handle_decorated(self, decorated_node):
@@ -508,99 +513,132 @@
         # and varargslist (lambda definition).
         if arguments_node.type == syms.parameters:
             if len(arguments_node.children) == 2:
-                return ast.arguments(None, None, None, None, None)
+                return ast.arguments(None, None, None, None, None, None, None,
+                                     None)
             arguments_node = arguments_node.children[1]
         i = 0
         child_count = len(arguments_node.children)
-        defaults = []
-        args = []
-        variable_arg = None
-        keywordonly_args = None
-        keywords_arg = None
+        n_pos = 0
+        n_pos_def = 0
+        n_kwdonly = 0
+        # scan args
+        while i < child_count:
+            arg_type = arguments_node.children[i].type
+            if arg_type == tokens.STAR:
+                i += 1
+                if i < child_count:
+                    next_arg_type = arguments_node.children[i].type
+                    if (next_arg_type == syms.tfpdef or
+                        next_arg_type == syms.vfpdef):
+                        i += 1
+                break
+            if arg_type == tokens.DOUBLESTAR:
+                break
+            if arg_type == syms.vfpdef or arg_type == syms.tfpdef:
+                n_pos += 1
+            if arg_type == tokens.EQUAL:
+                n_pos_def += 1
+            i += 1
+        while i < child_count:
+            arg_type = arguments_node.children[i].type
+            if arg_type == tokens.DOUBLESTAR:
+                break
+            if arg_type == syms.vfpdef or arg_type == syms.tfpdef:
+                n_kwdonly += 1
+            i += 1
+        pos = []
+        posdefaults = []
+        kwonly = []
+        kwdefaults = []
+        kwarg = None
+        kwargann = None
+        vararg = None
+        varargann = None
+        if n_pos + n_kwdonly > 255:
+            self.error("more than 255 arguments", arguments_node)
+        # process args
+        i = 0
         have_default = False
         while i < child_count:
-            argument = arguments_node.children[i]
-            arg_type = argument.type
+            arg = arguments_node.children[i]
+            arg_type = arg.type
             if arg_type == syms.tfpdef or arg_type == syms.vfpdef:
-                parenthesized = False
-                complex_args = False
-                while True:
-                    if i + 1 < child_count and \
-                            arguments_node.children[i + 1].type == tokens.EQUAL:
-                        default_node = arguments_node.children[i + 2]
-                        defaults.append(self.handle_expr(default_node))
-                        i += 2
-                        have_default = True
-                    elif have_default:
-                        if parenthesized and not complex_args:
-                            msg = "parenthesized arg with default"
-                        else:
-                            msg = ("non-default argument follows default "
-                                   "argument")
-                        self.error(msg, arguments_node)
-                    if len(argument.children) == 3:
-                        sub_arg = argument.children[1]
-                        if len(sub_arg.children) != 1:
-                            complex_args = True
-                            args.append(self.handle_arg_unpacking(sub_arg))
-                        else:
-                            parenthesized = True
-                            argument = sub_arg.children[0]
-                            continue
-                    if argument.children[0].type == tokens.NAME:
-                        name_node = argument.children[0]
-                        arg_name = name_node.value
-                        self.check_forbidden_name(arg_name, name_node)
-                        name = ast.Name(arg_name, ast.Param, name_node.lineno,
-                                        name_node.column)
-                        if keywordonly_args is None:
-                            args.append(name)
-                        else:
-                            keywordonly_args.append(name)
+                if i + 1 < child_count and \
+                        arguments_node.children[i + 1].type == tokens.EQUAL:
+                    default_node = arguments_node.children[i + 2]
+                    posdefaults.append(self.handle_expr(default_node))
                     i += 2
-                    break
+                    have_default = True
+                elif have_default:
+                    msg = "non-default argument follows default argument"
+                    self.error(msg, arguments_node)
+                pos.append(self.handle_arg(arg))
+                i += 2
             elif arg_type == tokens.STAR:
+                if i + 1 > child_count:
+                    self.error("named arguments must follow bare *")
                 name_node = arguments_node.children[i + 1]
                 keywordonly_args = []
                 if name_node.type == tokens.COMMA:
                     i += 2
+                    i = self.handle_keywordonly_args(arguments_node, i, kwonly,
+                                                     kwdefaults)
                 else:
-                    variable_arg = name_node.children[0].value
-                    self.check_forbidden_name(variable_arg, name_node)
+                    vararg = name_node.children[0].value
+                    self.check_forbidden_name(vararg, name_node)
+                    if len(name_node.children) > 1:
+                        varargann = self.handle_expr(name_node.children[2])
                     i += 3
+                    if i < child_count:
+                        next_arg_type = arguments_node.children[i].type
+                        if (next_arg_type == syms.tfpdef or
+                            next_arg_type == syms.vfpdef):
+                            i = self.handle_keywordonly_args(arguments_node, i,
+                                                             kwonly, kwdefaults)
             elif arg_type == tokens.DOUBLESTAR:
                 name_node = arguments_node.children[i + 1]
-                keywords_arg = name_node.children[0].value
-                self.check_forbidden_name(keywords_arg, name_node)
+                kwarg = name_node.children[0].value
+                self.check_forbidden_name(kwarg, name_node)
+                if len(name_node.children) > 1:
+                    kwargann = self.handle_expr(name_node.children[2])
                 i += 3
             else:
                 raise AssertionError("unknown node in argument list")
-        if not defaults:
-            defaults = None
-        if not args:
-            args = None
-        return ast.arguments(args, variable_arg, keywordonly_args, keywords_arg, defaults)
+        return ast.arguments(pos, vararg, varargann, kwonly, kwarg,
+                             kwargann, posdefaults, kwdefaults)
 
-    def handle_arg_unpacking(self, fplist_node):
-        args = []
-        for i in range((len(fplist_node.children) + 1) / 2):
-            fpdef_node = fplist_node.children[i * 2]
-            while True:
-                child = fpdef_node.children[0]
-                if child.type == tokens.NAME:
-                    arg = ast.Name(child.value, ast.Store, child.lineno,
-                                   child.column)
-                    args.append(arg)
+    def handle_keywordonly_args(self, arguments_node, i, kwonly, kwdefaults):
+        child_count = len(arguments_node.children)
+        while i < child_count:
+            arg = arguments_node.children[i]
+            arg_type = arg.type
+            if arg_type == syms.vfpdef or arg_type == syms.tfpdef:
+                if (i + 1 < child_count and
+                    arguments_node.children[i + 1].type == tokens.EQUAL):
+                    expr = self.handle_expr(arguments_node.children[i + 2])
+                    kwdefaults.append(expr)
+                    i += 2
                 else:
-                    child = fpdef_node.children[1]
-                    if len(child.children) == 1:
-                        fpdef_node = child.children[0]
-                        continue
-                    args.append(self.handle_arg_unpacking(child))
-                break
-        tup = ast.Tuple(args, ast.Store, fplist_node.lineno, fplist_node.column)
-        self.set_context(tup, ast.Store)
-        return tup
+                    kwdefaults.append(None)
+                ann = None
+                if len(arg.children) == 3:
+                    ann = self.handle_expr(arg.children[2])
+                name_node = arg.children[0]
+                argname = name_node.value
+                self.check_forbidden_name(argname, name_node)
+                kwonly.append(ast.arg(argname, ann))
+                i += 2
+            elif arg_type == tokens.DOUBLESTAR:
+                return i
+        return i
+
+    def handle_arg(self, arg_node):
+        name_node = arg_node.children[0]
+        self.check_forbidden_name(name_node.value, arg_node)
+        ann = None
+        if len(arg_node.children) == 3:
+            ann = self.handle_expr(arg_node.children[2])
+        return ast.arg(name_node.value, ann)
 
     def handle_stmt(self, stmt):
         stmt_type = stmt.type
@@ -779,7 +817,7 @@
     def handle_lambdef(self, lambdef_node):
         expr = self.handle_expr(lambdef_node.children[-1])
         if len(lambdef_node.children) == 3:
-            args = ast.arguments(None, None, None, None, None)
+            args = ast.arguments(None, None, None, None, None, None, None, None)
         else:
             args = self.handle_arguments(lambdef_node.children[1])
         return ast.Lambda(args, expr, lambdef_node.lineno, lambdef_node.column)
diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -286,17 +286,64 @@
             self.emit_op_arg(ops.LOAD_CONST, code_index)
             self.emit_op_arg(ops.MAKE_FUNCTION, num_defaults)
 
+    def _visit_kwonlydefaults(self, args):
+        defaults = 0
+        for kwonly, default in zip(args.kwonlyargs, args.kw_defaults):
+            if default:
+                self.load_const(self.space.wrap(kwonly.arg))
+                default.walkabout(self)
+                defaults += 1
+        return defaults
+
+    def _visit_arg_annotation(self, name, ann, names):
+        if ann:
+            ann.walkabout(self)
+            names.append(name)
+
+    def _visit_arg_annotations(self, args, names):
+        if args:
+            for arg in args:
+                self._visit_arg_annotation(arg.arg, arg.annotation, names)
+
+    def _visit_annotations(self, func, args, returns):
+        space = self.space
+        names = []
+        self._visit_arg_annotations(args.args, names)
+        if args.varargannotation:
+            self._visit_arg_annotation(args.vararg, args.varargannotation,
+                                       names)
+        self._visit_arg_annotations(args.kwonlyargs, names)
+        if args.kwargannotation:
+            self._visit_arg_annotation(args.kwarg, args.kwargannotation,
+                                       names)
+        self._visit_arg_annotation("return", returns, names)
+        l = len(names)
+        if l:
+            if l > 65534:
+                self.error("too many annotations", func)
+            w_tup = space.newtuple([space.wrap(name) for name in names])
+            self.load_const(w_tup)
+            l += 1
+        return l
+
     def visit_FunctionDef(self, func):
         self.update_position(func.lineno, True)
         # Load decorators first, but apply them after the function is created.
         self.visit_sequence(func.decorator_list)
         args = func.args
         assert isinstance(args, ast.arguments)
+        kw_default_count = 0
+        if args.kwonlyargs:
+            kw_default_count = self._visit_kwonlydefaults(args)
         self.visit_sequence(args.defaults)
+        num_annotations = self._visit_annotations(func, args, func.returns)
         num_defaults = len(args.defaults) if args.defaults is not None else 0
+        oparg = num_defaults
+        oparg |= kw_default_count << 8
+        oparg |= num_annotations << 16
         code = self.sub_scope(FunctionCodeGenerator, func.name, func,
                               func.lineno)
-        self._make_function(code, num_defaults)
+        self._make_function(code, oparg)
         # Apply decorators.
         if func.decorator_list:
             for i in range(len(func.decorator_list)):
diff --git a/pypy/interpreter/astcompiler/symtable.py b/pypy/interpreter/astcompiler/symtable.py
--- a/pypy/interpreter/astcompiler/symtable.py
+++ b/pypy/interpreter/astcompiler/symtable.py
@@ -356,6 +356,11 @@
         args = func.args
         assert isinstance(args, ast.arguments)
         self.visit_sequence(args.defaults)
+        if args.kw_defaults:
+            for arg in args.kw_defaults:
+                if arg:
+                    arg.walkabout(self)
+        self._visit_annotations(func)
         self.visit_sequence(func.decorator_list)
         new_scope = FunctionScope(func.name, func.lineno, func.col_offset)
         self.push_scope(new_scope, func)
@@ -443,7 +448,6 @@
                 misc.syntax_warning(self.space, msg, self.compile_info.filename,
                                     nonl.lineno, nonl.col_offset)
             self.note_symbol(name, SYM_NONLOCAL)
-            
 
     def visit_Lambda(self, lamb):
         args = lamb.args
@@ -501,11 +505,26 @@
 
     def _handle_params(self, params, is_toplevel):
         for i in range(len(params)):
-            arg = params[i]
-            if isinstance(arg, ast.Name):
-                self.note_symbol(arg.id, SYM_PARAM)
-            else:
-                raise AssertionError("unknown parameter type")
+            arg = params[i].arg
+            self.note_symbol(arg, SYM_PARAM)
+
+    def _visit_annotations(self, func):
+        args = func.args
+        if args.args:
+            self._visit_arg_annotations(args.args)
+        if args.varargannotation:
+            args.varargannotation.walkabout(self)
+        if args.kwargannotation:
+            args.kwargannotation.walkabout(self)
+        if args.kwonlyargs:
+            self._visit_arg_annotations(args.kwonlyargs)
+        if func.returns:
+            func.returns.walkabout(self)
+
+    def _visit_arg_annotations(self, args):
+        for arg in args:
+            if arg.annotation:
+                arg.annotation.walkabout(self)
 
     def visit_Name(self, name):
         if name.ctx == ast.Load:
diff --git a/pypy/interpreter/astcompiler/test/test_astbuilder.py b/pypy/interpreter/astcompiler/test/test_astbuilder.py
--- a/pypy/interpreter/astcompiler/test/test_astbuilder.py
+++ b/pypy/interpreter/astcompiler/test/test_astbuilder.py
@@ -478,43 +478,40 @@
         assert args.defaults is None
         assert args.kwarg is None
         assert args.vararg is None
+        assert func.returns is None
         args = self.get_first_stmt("def f(a, b): pass").args
         assert len(args.args) == 2
         a1, a2 = args.args
-        assert isinstance(a1, ast.Name)
-        assert a1.id == "a"
-        assert a1.ctx == ast.Param
-        assert isinstance(a2, ast.Name)
-        assert a2.id == "b"
-        assert a2.ctx == ast.Param
+        assert isinstance(a1, ast.arg)
+        assert a1.arg == "a"
+        assert isinstance(a2, ast.arg)
+        assert a2.arg == "b"
         assert args.vararg is None
         assert args.kwarg is None
         args = self.get_first_stmt("def f(a=b): pass").args
         assert len(args.args) == 1
         arg = args.args[0]
-        assert isinstance(arg, ast.Name)
-        assert arg.id == "a"
-        assert arg.ctx == ast.Param
+        assert isinstance(arg, ast.arg)
+        assert arg.arg == "a"
         assert len(args.defaults) == 1
         default = args.defaults[0]
         assert isinstance(default, ast.Name)
         assert default.id == "b"
         assert default.ctx == ast.Load
         args = self.get_first_stmt("def f(*a): pass").args
-        assert args.args is None
-        assert args.defaults is None
+        assert not args.args
+        assert not args.defaults
         assert args.kwarg is None
         assert args.vararg == "a"
         args = self.get_first_stmt("def f(**a): pass").args
-        assert args.args is None
-        assert args.defaults is None
+        assert not args.args
+        assert not args.defaults
         assert args.vararg is None
         assert args.kwarg == "a"
         args = self.get_first_stmt("def f(a, b, c=d, *e, **f): pass").args
         assert len(args.args) == 3
         for arg in args.args:
-            assert isinstance(arg, ast.Name)
-            assert arg.ctx == ast.Param
+            assert isinstance(arg, ast.arg)
         assert len(args.defaults) == 1
         assert isinstance(args.defaults[0], ast.Name)
         assert args.defaults[0].ctx == ast.Load
@@ -524,6 +521,62 @@
         exc = py.test.raises(SyntaxError, self.get_ast, input).value
         assert exc.msg == "non-default argument follows default argument"
 
+    def test_kwonly_arguments(self):
+        fn = self.get_first_stmt("def f(a, b, c, *, kwarg): pass")
+        assert isinstance(fn, ast.FunctionDef)
+        assert len(fn.args.kwonlyargs) == 1
+        assert isinstance(fn.args.kwonlyargs[0], ast.arg)
+        assert fn.args.kwonlyargs[0].arg == "kwarg"
+        assert fn.args.kw_defaults == [None]
+        fn = self.get_first_stmt("def f(a, b, c, *args, kwarg): pass")
+        assert isinstance(fn, ast.FunctionDef)
+        assert len(fn.args.kwonlyargs) == 1
+        assert isinstance(fn.args.kwonlyargs[0], ast.arg)
+        assert fn.args.kwonlyargs[0].arg == "kwarg"
+        assert fn.args.kw_defaults == [None]
+        fn = self.get_first_stmt("def f(a, b, c, *, kwarg=2): pass")
+        assert isinstance(fn, ast.FunctionDef)
+        assert len(fn.args.kwonlyargs) == 1
+        assert isinstance(fn.args.kwonlyargs[0], ast.arg)
+        assert fn.args.kwonlyargs[0].arg == "kwarg"
+        assert len(fn.args.kw_defaults) == 1
+        assert isinstance(fn.args.kw_defaults[0], ast.Num)
+
+    def test_function_annotation(self):
+        func = self.get_first_stmt("def f() -> X: pass")
+        assert isinstance(func.returns, ast.Name)
+        assert func.returns.id == "X"
+        assert func.returns.ctx == ast.Load
+        for stmt in "def f(x : 42): pass", "def f(x : 42=a): pass":
+            func = self.get_first_stmt(stmt)
+            assert isinstance(func.args.args[0].annotation, ast.Num)
+        assert isinstance(func.args.defaults[0], ast.Name)
+        func = self.get_first_stmt("def f(*x : 42): pass")
+        assert isinstance(func.args.varargannotation, ast.Num)
+        func = self.get_first_stmt("def f(**kw : 42): pass")
+        assert isinstance(func.args.kwargannotation, ast.Num)
+        func = self.get_first_stmt("def f(*, kw : 42=a): pass")
+        assert isinstance(func.args.kwonlyargs[0].annotation, ast.Num)
+
+    def test_lots_of_kwonly_arguments(self):
+        fundef = "def f("
+        for i in range(255):
+            fundef += "i%d, "%i
+        fundef += "*, key=100):\n pass\n"
+        py.test.raises(SyntaxError, self.get_first_stmt, fundef)
+
+        fundef2 = "def foo(i,*,"
+        for i in range(255):
+            fundef2 += "i%d, "%i
+        fundef2 += "lastarg):\n  pass\n"
+        py.test.raises(SyntaxError, self.get_first_stmt, fundef)
+
+        fundef3 = "def f(i,*,"
+        for i in range(253):
+            fundef3 += "i%d, "%i
+        fundef3 += "lastarg):\n  pass\n"
+        self.get_first_stmt(fundef3)
+
     def test_decorators(self):
         to_examine = (("def f(): pass", ast.FunctionDef),
                       ("class x: pass", ast.ClassDef))
@@ -758,13 +811,13 @@
         assert isinstance(args, ast.arguments)
         assert args.vararg is None
         assert args.kwarg is None
-        assert args.defaults is None
+        assert not args.defaults
         assert len(args.args) == 1
-        assert isinstance(args.args[0], ast.Name)
+        assert isinstance(args.args[0], ast.arg)
         assert isinstance(lam.body, ast.Name)
         lam = self.get_first_expr("lambda: True")
         args = lam.args
-        assert args.args is None
+        assert not args.args
         lam = self.get_first_expr("lambda x=x: y")
         assert len(lam.args.args) == 1
         assert len(lam.args.defaults) == 1
@@ -1199,17 +1252,3 @@
         if1, if2 = comps[0].ifs
         assert isinstance(if1, ast.Name)
         assert isinstance(if2, ast.Name)
-
-    def test_kwonly_arguments(self):
-        fn = self.get_first_stmt("def f(a, b, c, *, kwarg): pass")
-        assert isinstance(fn, ast.FunctionDef)
-        assert len(fn.args.kwonlyargs) == 1
-        assert isinstance(fn.args.kwonlyargs[0], ast.expr)
-        assert fn.args.kwonlyargs[0].id == "kwarg"
-
-    def test_kwonly_arguments_2(self):
-        fn = self.get_first_stmt("def f(a, b, c, *args, kwarg): pass")
-        assert isinstance(fn, ast.FunctionDef)
-        assert len(fn.args.kwonlyargs) == 1
-        assert isinstance(fn.args.kwonlyargs[0], ast.expr)
-        assert fn.args.kwonlyargs[0].id == "kwarg"
diff --git a/pypy/interpreter/astcompiler/test/test_symtable.py b/pypy/interpreter/astcompiler/test/test_symtable.py
--- a/pypy/interpreter/astcompiler/test/test_symtable.py
+++ b/pypy/interpreter/astcompiler/test/test_symtable.py
@@ -68,12 +68,24 @@
         assert exc.msg == "duplicate argument 'x' in function definition"
 
     def test_function_defaults(self):
-        scp = self.mod_scope("y = 4\ndef f(x=y): return x")
+        scp = self.mod_scope("y = w = 4\ndef f(x=y, *, z=w): return x")
         self.check_unknown(scp, "x")
+        self.check_unknown(scp, "z")
         assert scp.lookup("y") == symtable.SCOPE_LOCAL
+        assert scp.lookup("w") == symtable.SCOPE_LOCAL
         scp = scp.children[0]
         assert scp.lookup("x") == symtable.SCOPE_LOCAL
+        assert scp.lookup("z") == symtable.SCOPE_LOCAL
         self.check_unknown(scp, "y")
+        self.check_unknown(scp, "w")
+
+    def test_function_annotations(self):
+        scp = self.mod_scope("def f(x : X) -> Y: pass")
+        assert scp.lookup("X") == symtable.SCOPE_GLOBAL_IMPLICIT
+        assert scp.lookup("Y") == symtable.SCOPE_GLOBAL_IMPLICIT
+        scp = scp.children[0]
+        self.check_unknown(scp, "X")
+        self.check_unknown(scp, "Y")
 
     def check_comprehension(self, template):
         def brack(s):
diff --git a/pypy/interpreter/astcompiler/tools/Python.asdl b/pypy/interpreter/astcompiler/tools/Python.asdl
--- a/pypy/interpreter/astcompiler/tools/Python.asdl
+++ b/pypy/interpreter/astcompiler/tools/Python.asdl
@@ -9,8 +9,8 @@
 	    -- not really an actual node but useful in Jython's typesystem.
 	    | Suite(stmt* body)
 
-	stmt = FunctionDef(identifier name, arguments args, 
-                            stmt* body, expr* decorator_list)
+	stmt = FunctionDef(identifier name, arguments args,
+                            stmt* body, expr* decorator_list, expr? returns)
 	      | ClassDef(identifier name, 
 			 expr* bases,
 			 keyword* keywords,
@@ -106,8 +106,11 @@
 	excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)
 	                attributes (int lineno, int col_offset)
 
-	arguments = (expr* args, identifier? vararg, expr* kwonlyargs, 
-		     identifier? kwarg, expr* defaults)
+        arguments = (arg* args, identifier? vararg, expr? varargannotation,
+                     arg* kwonlyargs, identifier? kwarg,
+                     expr? kwargannotation, expr* defaults,
+                     expr* kw_defaults)
+        arg = (identifier arg, expr? annotation)
 
         -- keyword arguments supplied to call
         keyword = (identifier arg, expr value)
diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py
--- a/pypy/interpreter/astcompiler/tools/asdl_py.py
+++ b/pypy/interpreter/astcompiler/tools/asdl_py.py
@@ -227,7 +227,8 @@
         self.emit("")
         self.emit("def _mutate_sequence(self, seq):", 1)
         self.emit("for i in range(len(seq)):", 2)
-        self.emit("seq[i] = seq[i].mutate_over(self)", 3)
+        self.emit("if seq[i] is not None:", 3)
+        self.emit("seq[i] = seq[i].mutate_over(self)", 4)
         self.emit("")
         super(ASTVisitorVisitor, self).visitModule(mod)
         self.emit("")
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -34,8 +34,8 @@
                           'defs_w?[*]',
                           'name?']
 
-    def __init__(self, space, code, w_globals=None, defs_w=[], closure=None,
-                 forcename=None):
+    def __init__(self, space, code, w_globals=None, defs_w=[], w_kw_defs=None,
+                 closure=None, w_ann=None, forcename=None):
         self.space = space
         self.name = forcename or code.co_name
         self.w_doc = None   # lazily read from code.getdocstring()
@@ -43,8 +43,10 @@
         self.w_func_globals = w_globals  # the globals dictionary
         self.closure   = closure    # normally, list of Cell instances or None
         self.defs_w = defs_w
+        self.w_kw_defs = w_kw_defs
         self.w_func_dict = None # filled out below if needed
         self.w_module = None
+        self.w_ann = w_ann
 
     def __repr__(self):
         # return "function %s.%s" % (self.space, self.name)
@@ -223,7 +225,8 @@
                 raise OperationError(space.w_ValueError, space.wrap("closure is wrong size"))
             closure = [space.interp_w(Cell, w_cell) for w_cell in closure_w]
         func = space.allocate_instance(Function, w_subtype)
-        Function.__init__(func, space, code, w_globals, defs_w, closure, name)
+        Function.__init__(func, space, code, w_globals, defs_w, None, closure,
+                          None,name)
         return space.wrap(func)
 
     def descr_function_call(self, __args__):
@@ -352,6 +355,22 @@
     def fdel_func_defaults(self, space):
         self.defs_w = []
 
+    def fget_func_kwdefaults(self, space):
+        if self.w_kw_defs is None:
+            return space.w_None
+        return self.w_kw_defs
+
+    def fset_func_kwdefaults(self, space, w_new):
+        if space.is_w(w_new, space.w_None):
+            w_new = None
+        elif not space.isinstance_w(w_new, space.w_dict):
+            msg = "__kwdefaults__ must be a dict"
+            raise OperationError(space.w_TypeError, space.wrap(msg))
+        self.w_kw_defs = w_new
+
+    def fdel_func_kwdefaults(self, space):
+        self.w_kw_defs = None
+
     def fget_func_doc(self, space):
         if self.w_doc is None:
             self.w_doc = self.code.getdocstring(space)
@@ -416,6 +435,22 @@
             w_res = space.w_None
         return w_res
 
+    def fget_func_annotations(self, space):
+        if self.w_ann is None:
+            self.w_ann = space.newdict()
+        return self.w_ann
+
+    def fset_func_annotations(self, space, w_new):
+        if space.is_w(w_new, space.w_None):
+            w_new = None
+        elif not space.isinstance_w(w_new, space.w_dict):
+            msg = "__annotations__ must be a dict"
+            raise OperationError(space.w_TypeError, space.wrap(msg))
+        self.w_ann = w_new
+
+    def fdel_func_annotations(self, space):
+        self.w_ann = None
+
 def descr_function_get(space, w_function, w_obj, w_cls=None):
     """functionobject.__get__(obj[, type]) -> method"""
     # this is not defined as a method on Function because it's generally
@@ -552,7 +587,7 @@
     def __init__(self, func):
         assert isinstance(func, Function)
         Function.__init__(self, func.space, func.code, func.w_func_globals,
-                          func.defs_w, func.closure, func.name)
+                          func.defs_w, None, func.closure, None, func.name)
         self.w_doc = func.w_doc
         self.w_func_dict = func.w_func_dict
         self.w_module = func.w_module
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -617,7 +617,7 @@
         space = func.space
         activation = self.activation
         scope_w = args.parse_obj(w_obj, func.name, self.sig,
-                                 func.defs_w, self.minargs)
+                                 func.defs_w, func.w_kw_defs, self.minargs)
         try:
             w_result = activation._run(space, scope_w)
         except DescrMismatch:
diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py
--- a/pypy/interpreter/nestedscope.py
+++ b/pypy/interpreter/nestedscope.py
@@ -224,13 +224,8 @@
         raise NotImplementedError
 
     @jit.unroll_safe
-    def MAKE_CLOSURE(self, numdefaults, next_instr):
-        w_codeobj = self.popvalue()
-        codeobj = self.space.interp_w(pycode.PyCode, w_codeobj)
-        w_freevarstuple = self.popvalue()
+    def MAKE_CLOSURE(self, oparg, next_instr):
+        w_freevarstuple = self.peekvalue(1)
         freevars = [self.space.interp_w(Cell, cell)
                     for cell in self.space.fixedview(w_freevarstuple)]
-        defaultarguments = self.popvalues(numdefaults)
-        fn = function.Function(self.space, codeobj, self.w_globals,
-                               defaultarguments, freevars)
-        self.pushvalue(self.space.wrap(fn))
+        self._make_function(oparg, freevars)
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -225,7 +225,7 @@
                                       fresh_virtualizable=True)
         args_matched = args.parse_into_scope(None, fresh_frame.locals_stack_w,
                                              func.name,
-                                             sig, func.defs_w)
+                                             sig, func.defs_w, func.w_kw_defs)
         fresh_frame.init_cells()
         return frame.run()
 
@@ -238,7 +238,7 @@
                                       fresh_virtualizable=True)
         args_matched = args.parse_into_scope(w_obj, fresh_frame.locals_stack_w,
                                              func.name,
-                                             sig, func.defs_w)
+                                             sig, func.defs_w, func.w_kw_defs)
         fresh_frame.init_cells()
         return frame.run()
 
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -990,13 +990,36 @@
         w_varargs = self.popvalue()
         self.call_function(oparg, w_varargs, w_varkw)
 
-    def MAKE_FUNCTION(self, numdefaults, next_instr):
+    def _make_function(self, oparg, freevars=None):
+        space = self.space
         w_codeobj = self.popvalue()
         codeobj = self.space.interp_w(PyCode, w_codeobj)
-        defaultarguments = self.popvalues(numdefaults)
-        fn = function.Function(self.space, codeobj, self.w_globals,
-                               defaultarguments)
-        self.pushvalue(self.space.wrap(fn))
+        if freevars is not None:
+            # Pop freevars
+            self.popvalue()
+        posdefaults = oparg & 0xFF
+        kwdefaults = (oparg >> 8) & 0xFF
+        num_annotations = (oparg >> 16) & 0xFF
+        defaultarguments = self.popvalues(posdefaults)
+        w_ann = None
+        if num_annotations:
+            names_w = space.fixedview(self.popvalue())
+            w_ann = space.newdict(strdict=True)
+            for i in range(len(names_w) - 1, -1, -1):
+                space.setitem(w_ann, names_w[i], self.popvalue())
+        w_kw_defs = None
+        if kwdefaults:
+            w_kw_defs = space.newdict(strdict=True)
+            for i in range(kwdefaults - 1, -1, -1):
+                w_name = self.popvalue()
+                w_def = self.popvalue()
+                space.setitem(w_kw_defs, w_def, w_name)
+        fn = function.Function(space, codeobj, self.w_globals, defaultarguments,
+                               w_kw_defs, freevars, w_ann)
+        self.pushvalue(space.wrap(fn))
+
+    def MAKE_FUNCTION(self, oparg, next_instr):
+        return self._make_function(oparg)
 
     def BUILD_SLICE(self, numargs, next_instr):
         if numargs == 3:
diff --git a/pypy/interpreter/pyparser/data/Grammar3.2 b/pypy/interpreter/pyparser/data/Grammar3.2
--- a/pypy/interpreter/pyparser/data/Grammar3.2
+++ b/pypy/interpreter/pyparser/data/Grammar3.2
@@ -22,7 +22,7 @@
 decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
 decorators: decorator+
 decorated: decorators (classdef | funcdef)
-funcdef: 'def' NAME parameters ':' suite
+funcdef: 'def' NAME parameters ['->' test] ':' suite
 parameters: '(' [typedargslist] ')'
 typedargslist: (tfpdef ['=' test] (',' tfpdef ['=' test])* [','
        ['*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef]]
diff --git a/pypy/interpreter/pyparser/dfa_generated.py b/pypy/interpreter/pyparser/dfa_generated.py
--- a/pypy/interpreter/pyparser/dfa_generated.py
+++ b/pypy/interpreter/pyparser/dfa_generated.py
@@ -5,38 +5,39 @@
 
 from pypy.interpreter.pyparser import automata
 accepts = [True, True, True, True, True, True, True, True,
-           True, True, False, True, True, True, True, False,
-           False, False, True, False, False, False, True,
-           False, True, False, True, False, True, False,
-           False, True, False, False, True, True, True,
-           False, False, True, False, False, False, True]
+           True, True, False, True, True, True, True, True,
+           False, False, False, True, False, False, False,
+           True, False, True, False, True, False, True,
+           False, False, True, False, False, True, True,
+           True, False, False, True, False, False, False,
+           True]
 states = [
     # 0
-    {'\t': 0, '\n': 13, '\x0c': 0,
-     '\r': 14, ' ': 0, '!': 10, '"': 16,
-     '#': 18, '%': 12, '&': 12, "'": 15,
-     '(': 13, ')': 13, '*': 7, '+': 12,
-     ',': 13, '-': 12, '.': 6, '/': 11,
+    {'\t': 0, '\n': 14, '\x0c': 0,
+     '\r': 15, ' ': 0, '!': 10, '"': 17,
+     '#': 19, '%': 13, '&': 13, "'": 16,
+     '(': 14, ')': 14, '*': 7, '+': 13,
+     ',': 14, '-': 11, '.': 6, '/': 12,
      '0': 4, '1': 5, '2': 5, '3': 5,
      '4': 5, '5': 5, '6': 5, '7': 5,
-     '8': 5, '9': 5, ':': 13, ';': 13,
-     '<': 9, '=': 12, '>': 8, '@': 13,
+     '8': 5, '9': 5, ':': 14, ';': 14,
+     '<': 9, '=': 13, '>': 8, '@': 14,
      'A': 1, 'B': 2, 'C': 1, 'D': 1,
      'E': 1, 'F': 1, 'G': 1, 'H': 1,
      'I': 1, 'J': 1, 'K': 1, 'L': 1,
      'M': 1, 'N': 1, 'O': 1, 'P': 1,
      'Q': 1, 'R': 3, 'S': 1, 'T': 1,
      'U': 1, 'V': 1, 'W': 1, 'X': 1,
-     'Y': 1, 'Z': 1, '[': 13, '\\': 17,
-     ']': 13, '^': 12, '_': 1, '`': 13,
+     'Y': 1, 'Z': 1, '[': 14, '\\': 18,
+     ']': 14, '^': 13, '_': 1, '`': 14,
      'a': 1, 'b': 2, 'c': 1, 'd': 1,
      'e': 1, 'f': 1, 'g': 1, 'h': 1,
      'i': 1, 'j': 1, 'k': 1, 'l': 1,
      'm': 1, 'n': 1, 'o': 1, 'p': 1,
      'q': 1, 'r': 3, 's': 1, 't': 1,
      'u': 1, 'v': 1, 'w': 1, 'x': 1,
-     'y': 1, 'z': 1, '{': 13, '|': 12,
-     '}': 13, '~': 13},
+     'y': 1, 'z': 1, '{': 14, '|': 13,
+     '}': 14, '~': 14},
     # 1
     {'0': 1, '1': 1, '2': 1, '3': 1,
      '4': 1, '5': 1, '6': 1, '7': 1,
@@ -55,7 +56,7 @@
      't': 1, 'u': 1, 'v': 1, 'w': 1,
      'x': 1, 'y': 1, 'z': 1},
     # 2
-    {'"': 16, "'": 15, '0': 1, '1': 1,
+    {'"': 17, "'": 16, '0': 1, '1': 1,
      '2': 1, '3': 1, '4': 1, '5': 1,
      '6': 1, '7': 1, '8': 1, '9': 1,
      'A': 1, 'B': 1, 'C': 1, 'D': 1,
@@ -73,7 +74,7 @@
      'v': 1, 'w': 1, 'x': 1, 'y': 1,
      'z': 1},
     # 3
-    {'"': 16, "'": 15, '0': 1, '1': 1,
+    {'"': 17, "'": 16, '0': 1, '1': 1,
      '2': 1, '3': 1, '4': 1, '5': 1,
      '6': 1, '7': 1, '8': 1, '9': 1,
      'A': 1, 'B': 1, 'C': 1, 'D': 1,
@@ -91,137 +92,139 @@
      'v': 1, 'w': 1, 'x': 1, 'y': 1,
      'z': 1},
     # 4
-    {'.': 24, '0': 22, '1': 23, '2': 23,
-     '3': 23, '4': 23, '5': 23, '6': 23,
-     '7': 23, '8': 23, '9': 23, 'B': 21,
-     'E': 25, 'J': 13, 'O': 20, 'X': 19,
-     'b': 21, 'e': 25, 'j': 13, 'o': 20,
-     'x': 19},
+    {'.': 25, '0': 23, '1': 24, '2': 24,
+     '3': 24, '4': 24, '5': 24, '6': 24,
+     '7': 24, '8': 24, '9': 24, 'B': 22,
+     'E': 26, 'J': 14, 'O': 21, 'X': 20,
+     'b': 22, 'e': 26, 'j': 14, 'o': 21,
+     'x': 20},
     # 5
-    {'.': 24, '0': 5, '1': 5, '2': 5,
+    {'.': 25, '0': 5, '1': 5, '2': 5,
      '3': 5, '4': 5, '5': 5, '6': 5,
-     '7': 5, '8': 5, '9': 5, 'E': 25,
-     'J': 13, 'e': 25, 'j': 13},
+     '7': 5, '8': 5, '9': 5, 'E': 26,
+     'J': 14, 'e': 26, 'j': 14},
     # 6
-    {'0': 26, '1': 26, '2': 26, '3': 26,
-     '4': 26, '5': 26, '6': 26, '7': 26,
-     '8': 26, '9': 26},
+    {'0': 27, '1': 27, '2': 27, '3': 27,
+     '4': 27, '5': 27, '6': 27, '7': 27,
+     '8': 27, '9': 27},
     # 7
-    {'*': 12, '=': 13},
+    {'*': 13, '=': 14},
     # 8
-    {'=': 13, '>': 12},
+    {'=': 14, '>': 13},
     # 9
-    {'<': 12, '=': 13, '>': 13},
+    {'<': 13, '=': 14, '>': 14},
     # 10
-    {'=': 13},
+    {'=': 14},
     # 11
-    {'/': 12, '=': 13},
+    {'=': 14, '>': 14},
     # 12
-    {'=': 13},
+    {'/': 13, '=': 14},
     # 13
+    {'=': 14},
+    # 14
     {},
-    # 14
-    {'\n': 13},
     # 15
-    {automata.DEFAULT: 30, '\n': 27,
-     '\r': 27, "'": 28, '\\': 29},
+    {'\n': 14},
     # 16
-    {automata.DEFAULT: 33, '\n': 27,
-     '\r': 27, '"': 31, '\\': 32},
+    {automata.DEFAULT: 31, '\n': 28,
+     '\r': 28, "'": 29, '\\': 30},
     # 17
-    {'\n': 13, '\r': 14},
+    {automata.DEFAULT: 34, '\n': 28,
+     '\r': 28, '"': 32, '\\': 33},
     # 18
-    {automata.DEFAULT: 18, '\n': 27, '\r': 27},
+    {'\n': 14, '\r': 15},
     # 19
-    {'0': 34, '1': 34, '2': 34, '3': 34,
-     '4': 34, '5': 34, '6': 34, '7': 34,
-     '8': 34, '9': 34, 'A': 34, 'B': 34,
-     'C': 34, 'D': 34, 'E': 34, 'F': 34,
-     'a': 34, 'b': 34, 'c': 34, 'd': 34,
-     'e': 34, 'f': 34},
+    {automata.DEFAULT: 19, '\n': 28, '\r': 28},
     # 20
     {'0': 35, '1': 35, '2': 35, '3': 35,
-     '4': 35, '5': 35, '6': 35, '7': 35},
+     '4': 35, '5': 35, '6': 35, '7': 35,
+     '8': 35, '9': 35, 'A': 35, 'B': 35,
+     'C': 35, 'D': 35, 'E': 35, 'F': 35,
+     'a': 35, 'b': 35, 'c': 35, 'd': 35,
+     'e': 35, 'f': 35},
     # 21
-    {'0': 36, '1': 36},
+    {'0': 36, '1': 36, '2': 36, '3': 36,
+     '4': 36, '5': 36, '6': 36, '7': 36},
     # 22
-    {'.': 24, '0': 22, '1': 23, '2': 23,
-     '3': 23, '4': 23, '5': 23, '6': 23,
-     '7': 23, '8': 23, '9': 23, 'E': 25,
-     'J': 13, 'e': 25, 'j': 13},
+    {'0': 37, '1': 37},
     # 23
-    {'.': 24, '0': 23, '1': 23, '2': 23,
-     '3': 23, '4': 23, '5': 23, '6': 23,
-     '7': 23, '8': 23, '9': 23, 'E': 25,
-     'J': 13, 'e': 25, 'j': 13},
+    {'.': 25, '0': 23, '1': 24, '2': 24,
+     '3': 24, '4': 24, '5': 24, '6': 24,
+     '7': 24, '8': 24, '9': 24, 'E': 26,
+     'J': 14, 'e': 26, 'j': 14},
     # 24
-    {'0': 24, '1': 24, '2': 24, '3': 24,
-     '4': 24, '5': 24, '6': 24, '7': 24,
-     '8': 24, '9': 24, 'E': 37, 'J': 13,
-     'e': 37, 'j': 13},
+    {'.': 25, '0': 24, '1': 24, '2': 24,
+     '3': 24, '4': 24, '5': 24, '6': 24,
+     '7': 24, '8': 24, '9': 24, 'E': 26,
+     'J': 14, 'e': 26, 'j': 14},
     # 25
-    {'+': 38, '-': 38, '0': 39, '1': 39,
-     '2': 39, '3': 39, '4': 39, '5': 39,
-     '6': 39, '7': 39, '8': 39, '9': 39},
+    {'0': 25, '1': 25, '2': 25, '3': 25,
+     '4': 25, '5': 25, '6': 25, '7': 25,
+     '8': 25, '9': 25, 'E': 38, 'J': 14,
+     'e': 38, 'j': 14},
     # 26
-    {'0': 26, '1': 26, '2': 26, '3': 26,
-     '4': 26, '5': 26, '6': 26, '7': 26,
-     '8': 26, '9': 26, 'E': 37, 'J': 13,
-     'e': 37, 'j': 13},
+    {'+': 39, '-': 39, '0': 40, '1': 40,
+     '2': 40, '3': 40, '4': 40, '5': 40,
+     '6': 40, '7': 40, '8': 40, '9': 40},
     # 27
+    {'0': 27, '1': 27, '2': 27, '3': 27,
+     '4': 27, '5': 27, '6': 27, '7': 27,
+     '8': 27, '9': 27, 'E': 38, 'J': 14,
+     'e': 38, 'j': 14},
+    # 28
     {},
-    # 28
-    {"'": 13},
     # 29
-    {automata.DEFAULT: 40, '\n': 13, '\r': 14},
+    {"'": 14},
     # 30
-    {automata.DEFAULT: 30, '\n': 27,
-     '\r': 27, "'": 13, '\\': 29},
+    {automata.DEFAULT: 41, '\n': 14, '\r': 15},
     # 31
-    {'"': 13},
+    {automata.DEFAULT: 31, '\n': 28,
+     '\r': 28, "'": 14, '\\': 30},
     # 32
-    {automata.DEFAULT: 41, '\n': 13, '\r': 14},
+    {'"': 14},
     # 33
-    {automata.DEFAULT: 33, '\n': 27,
-     '\r': 27, '"': 13, '\\': 32},
+    {automata.DEFAULT: 42, '\n': 14, '\r': 15},
     # 34
-    {'0': 34, '1': 34, '2': 34, '3': 34,
-     '4': 34, '5': 34, '6': 34, '7': 34,
-     '8': 34, '9': 34, 'A': 34, 'B': 34,
-     'C': 34, 'D': 34, 'E': 34, 'F': 34,
-     'a': 34, 'b': 34, 'c': 34, 'd': 34,
-     'e': 34, 'f': 34},
+    {automata.DEFAULT: 34, '\n': 28,
+     '\r': 28, '"': 14, '\\': 33},
     # 35
     {'0': 35, '1': 35, '2': 35, '3': 35,
-     '4': 35, '5': 35, '6': 35, '7': 35},
+     '4': 35, '5': 35, '6': 35, '7': 35,
+     '8': 35, '9': 35, 'A': 35, 'B': 35,
+     'C': 35, 'D': 35, 'E': 35, 'F': 35,
+     'a': 35, 'b': 35, 'c': 35, 'd': 35,
+     'e': 35, 'f': 35},
     # 36
-    {'0': 36, '1': 36},
+    {'0': 36, '1': 36, '2': 36, '3': 36,
+     '4': 36, '5': 36, '6': 36, '7': 36},
     # 37
-    {'+': 42, '-': 42, '0': 43, '1': 43,
-     '2': 43, '3': 43, '4': 43, '5': 43,
-     '6': 43, '7': 43, '8': 43, '9': 43},
+    {'0': 37, '1': 37},
     # 38
-    {'0': 39, '1': 39, '2': 39, '3': 39,
-     '4': 39, '5': 39, '6': 39, '7': 39,
-     '8': 39, '9': 39},
+    {'+': 43, '-': 43, '0': 44, '1': 44,
+     '2': 44, '3': 44, '4': 44, '5': 44,
+     '6': 44, '7': 44, '8': 44, '9': 44},
     # 39
-    {'0': 39, '1': 39, '2': 39, '3': 39,
-     '4': 39, '5': 39, '6': 39, '7': 39,
-     '8': 39, '9': 39, 'J': 13, 'j': 13},
+    {'0': 40, '1': 40, '2': 40, '3': 40,
+     '4': 40, '5': 40, '6': 40, '7': 40,
+     '8': 40, '9': 40},
     # 40
-    {automata.DEFAULT: 40, '\n': 27,
-     '\r': 27, "'": 13, '\\': 29},
+    {'0': 40, '1': 40, '2': 40, '3': 40,
+     '4': 40, '5': 40, '6': 40, '7': 40,
+     '8': 40, '9': 40, 'J': 14, 'j': 14},
     # 41
-    {automata.DEFAULT: 41, '\n': 27,
-     '\r': 27, '"': 13, '\\': 32},
+    {automata.DEFAULT: 41, '\n': 28,
+     '\r': 28, "'": 14, '\\': 30},
     # 42
-    {'0': 43, '1': 43, '2': 43, '3': 43,
-     '4': 43, '5': 43, '6': 43, '7': 43,
-     '8': 43, '9': 43},
+    {automata.DEFAULT: 42, '\n': 28,
+     '\r': 28, '"': 14, '\\': 33},
     # 43
-    {'0': 43, '1': 43, '2': 43, '3': 43,
-     '4': 43, '5': 43, '6': 43, '7': 43,
-     '8': 43, '9': 43, 'J': 13, 'j': 13},
+    {'0': 44, '1': 44, '2': 44, '3': 44,
+     '4': 44, '5': 44, '6': 44, '7': 44,
+     '8': 44, '9': 44},
+    # 44
+    {'0': 44, '1': 44, '2': 44, '3': 44,
+     '4': 44, '5': 44, '6': 44, '7': 44,
+     '8': 44, '9': 44, 'J': 14, 'j': 14},
     ]
 pseudoDFA = automata.DFA(states, accepts)
 
diff --git a/pypy/interpreter/pyparser/gendfa.py b/pypy/interpreter/pyparser/gendfa.py
--- a/pypy/interpreter/pyparser/gendfa.py
+++ b/pypy/interpreter/pyparser/gendfa.py
@@ -131,6 +131,7 @@
                            maybe(states, newArcPair(states, "="))),
                      chainStr(states, "<>"),
                      chainStr(states, "!="),
+                     chainStr(states, "->"),
                      chain(states,
                            chainStr(states, "//"),
                            maybe(states, newArcPair(states, "="))),
diff --git a/pypy/interpreter/pyparser/pytoken.py b/pypy/interpreter/pyparser/pytoken.py
--- a/pypy/interpreter/pyparser/pytoken.py
+++ b/pypy/interpreter/pyparser/pytoken.py
@@ -61,6 +61,7 @@
 _add_tok('DOUBLESLASH', "//" )
 _add_tok('DOUBLESLASHEQUAL',"//=" )
 _add_tok('AT', "@" )
+_add_tok('RARROW', "->")
 _add_tok('OP')
 _add_tok('ERRORTOKEN')
 
diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py
--- a/pypy/interpreter/test/test_argument.py
+++ b/pypy/interpreter/test/test_argument.py
@@ -357,16 +357,16 @@
         calls = []
 
         def _match_signature(w_firstarg, scope_w, signature,
-                             defaults_w=None, blindargs=0):
+                             defaults_w=None, w_kw_defs=None, blindargs=0):
             defaults_w = [] if defaults_w is None else defaults_w
             calls.append((w_firstarg, scope_w, signature.argnames, signature.has_vararg(),
-                          signature.has_kwarg(), defaults_w, blindargs))
+                          signature.has_kwarg(), defaults_w, w_kw_defs, blindargs))
         args._match_signature = _match_signature
 
         scope_w = args.parse_obj(None, "foo", Signature(["a", "b"], None, None))
         assert len(calls) == 1
         assert calls[0] == (None, [None, None], ["a", "b"], False, False,
-                            [], 0)
+                            [], None, 0)
         assert calls[0][1] is scope_w
         calls = []
 
@@ -374,7 +374,7 @@
                                  blindargs=1)
         assert len(calls) == 1
         assert calls[0] == (None, [None, None, None], ["a", "b"], True, False,
-                            [], 1)
+                            [], None, 1)
         calls = []
 
         scope_w = args.parse_obj(None, "foo", Signature(["a", "b"], "args", "kw"),
@@ -382,7 +382,7 @@
         assert len(calls) == 1
         assert calls[0] == (None, [None, None, None, None], ["a", "b"],
                             True, True,
-                            ["x", "y"], 0)
+                            ["x", "y"], None, 0)
         calls = []
 
         scope_w = args.parse_obj("obj", "foo", Signature(["a", "b"], "args", "kw"),
@@ -390,7 +390,7 @@
         assert len(calls) == 1
         assert calls[0] == ("obj", [None, None, None, None], ["a", "b"],
                             True, True,
-                            ["x", "y"], 1)
+                            ["x", "y"], None, 1)
 
         class FakeArgErr(ArgErr):
 
@@ -415,17 +415,17 @@
         calls = []
 
         def _match_signature(w_firstarg, scope_w, signature,
-                             defaults_w=None, blindargs=0):
+                             defaults_w=None, w_kw_defs=None, blindargs=0):
             defaults_w = [] if defaults_w is None else defaults_w
             calls.append((w_firstarg, scope_w, signature.argnames, signature.has_vararg(),
-                          signature.has_kwarg(), defaults_w, blindargs))
+                          signature.has_kwarg(), defaults_w, w_kw_defs, blindargs))
         args._match_signature = _match_signature
 
         scope_w = [None, None]
         args.parse_into_scope(None, scope_w, "foo", Signature(["a", "b"], None, None))
         assert len(calls) == 1
         assert calls[0] == (None, scope_w, ["a", "b"], False, False,
-                            [], 0)
+                            [], None, 0)
         assert calls[0][1] is scope_w
         calls = []
 
@@ -435,7 +435,7 @@
         assert len(calls) == 1
         assert calls[0] == (None, scope_w, ["a", "b"],
                             True, True,
-                            ["x", "y"], 0)
+                            ["x", "y"], None, 0)
         calls = []
 
         scope_w = [None, None, None, None]
@@ -445,7 +445,7 @@
         assert len(calls) == 1
         assert calls[0] == ("obj", scope_w, ["a", "b"],
                             True, True,
-                            ["x", "y"], 0)
+                            ["x", "y"], None, 0)
 
         class FakeArgErr(ArgErr):
 
@@ -493,34 +493,34 @@
     def test_missing_args(self):
         # got_nargs, nkwds, expected_nargs, has_vararg, has_kwarg,
         # defaults_w, missing_args
-        err = ArgErrCount(1, 0, 0, False, False, None, 0)
+        err = ArgErrCount(1, 0, 0, False, False, None, None, 0)
         s = err.getmsg()
         assert s == "takes no arguments (1 given)"
-        err = ArgErrCount(0, 0, 1, False, False, [], 1)
+        err = ArgErrCount(0, 0, 1, False, False, [], None, 1)
         s = err.getmsg()
         assert s == "takes exactly 1 argument (0 given)"
-        err = ArgErrCount(3, 0, 2, False, False, [], 0)
+        err = ArgErrCount(3, 0, 2, False, False, [], None, 0)
         s = err.getmsg()
         assert s == "takes exactly 2 arguments (3 given)"
-        err = ArgErrCount(3, 0, 2, False, False, ['a'], 0)
+        err = ArgErrCount(3, 0, 2, False, False, ['a'], None, 0)
         s = err.getmsg()
         assert s == "takes at most 2 arguments (3 given)"
-        err = ArgErrCount(1, 0, 2, True, False, [], 1)
+        err = ArgErrCount(1, 0, 2, True, False, [], None, 1)
         s = err.getmsg()
         assert s == "takes at least 2 arguments (1 given)"
-        err = ArgErrCount(0, 1, 2, True, False, ['a'], 1)
+        err = ArgErrCount(0, 1, 2, True, False, ['a'], None, 1)
         s = err.getmsg()
         assert s == "takes at least 1 non-keyword argument (0 given)"
-        err = ArgErrCount(2, 1, 1, False, True, [], 0)
+        err = ArgErrCount(2, 1, 1, False, True, [], None, 0)
         s = err.getmsg()
         assert s == "takes exactly 1 non-keyword argument (2 given)"
-        err = ArgErrCount(0, 1, 1, False, True, [], 1)
+        err = ArgErrCount(0, 1, 1, False, True, [], None, 1)
         s = err.getmsg()
         assert s == "takes exactly 1 non-keyword argument (0 given)"
-        err = ArgErrCount(0, 1, 1, True, True, [], 1)
+        err = ArgErrCount(0, 1, 1, True, True, [], None, 1)
         s = err.getmsg()
         assert s == "takes at least 1 non-keyword argument (0 given)"
-        err = ArgErrCount(2, 1, 1, False, True, ['a'], 0)
+        err = ArgErrCount(2, 1, 1, False, True, ['a'], None, 0)
         s = err.getmsg()
         assert s == "takes at most 1 non-keyword argument (2 given)"
 
diff --git a/pypy/interpreter/test/test_function.py b/pypy/interpreter/test/test_function.py
--- a/pypy/interpreter/test/test_function.py
+++ b/pypy/interpreter/test/test_function.py
@@ -20,6 +20,31 @@
         assert f.__name__ == 'f'
         assert f.__module__ == 'mymodulename'
 
+    def test_annotations(self):
+        def f(): pass
+        ann = f.__annotations__
+        assert ann == {}
+        assert f.__annotations__ is ann
+        raises(TypeError, setattr, f, "__annotations__", 42)
+        del f.__annotations__
+        assert f.__annotations__ is not ann
+        f.__annotations__ = ann
+        assert f.__annotations__ is ann
+
+    def test_kwdefaults(self):
+        """
+        def f(*, kw=3): return kw
+        assert f.__kwdefaults__ == {"kw" : 3}
+        f.__kwdefaults__["kw"] = 4
+        assert f() == 4
+        f.__kwdefaults__ = {"kw" : 5}
+        assert f() == 5
+        del f.__kwdefaults__
+        assert f.__kwdefaults__ is None
+        raises(TypeError, f)
+        assert f(kw=42) == 42
+        """
+
     def test_code_is_ok(self):
         def f(): pass
         assert not hasattr(f.__code__, '__dict__')
diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py
--- a/pypy/interpreter/test/test_gateway.py
+++ b/pypy/interpreter/test/test_gateway.py
@@ -12,6 +12,7 @@
         self.space = space
         self.name = name
         self.defs_w = []
+        self.w_kw_defs = None
 
 class TestBuiltinCode:
     def test_signature(self):
diff --git a/pypy/interpreter/test/test_syntax.py b/pypy/interpreter/test/test_syntax.py
--- a/pypy/interpreter/test/test_syntax.py
+++ b/pypy/interpreter/test/test_syntax.py
@@ -612,6 +612,15 @@
         """
         exec(s)
 
+class AppTestFunctionAnnotations:
+
+    def test_simple(self):
+        """
+        def f(a : 1, b : 2, *var : 3, hi : 4, bye : 5=0, **kw : 6) -> 42: pass
+        assert f.__annotations__ == {"a" : 1, "b" : 2, "var" : 3, "hi" : 4,
+                                    "bye" : 5, "kw" : 6, "return" : 42}
+        """
+
 class AppTestSyntaxError:
 
     def test_tokenizer_error_location(self):
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -788,10 +788,16 @@
 getset_func_defaults = GetSetProperty(Function.fget_func_defaults,
                                       Function.fset_func_defaults,
                                       Function.fdel_func_defaults)
+getset_func_kwdefaults = GetSetProperty(Function.fget_func_kwdefaults,
+                                        Function.fset_func_kwdefaults,
+                                        Function.fdel_func_kwdefaults)
 getset_func_code = GetSetProperty(Function.fget_func_code,
                                   Function.fset_func_code)
 getset_func_name = GetSetProperty(Function.fget_func_name,
                                   Function.fset_func_name)
+getset_func_annotations = GetSetProperty(Function.fget_func_annotations,
+                                        Function.fset_func_annotations,
+                                        Function.fdel_func_annotations)
 
 getset_func_dict = GetSetProperty(descr_get_dict, descr_set_dict, cls=Function)
 
@@ -808,6 +814,8 @@
     __name__ = getset_func_name,
     __dict__ = getset_func_dict,
     __defaults__ = getset_func_defaults,
+    __kwdefaults__ = getset_func_kwdefaults,
+    __annotations__ = getset_func_annotations,
     __globals__ = interp_attrproperty_w('w_func_globals', cls=Function),
     __closure__ = GetSetProperty( Function.fget_func_closure ),
     __module__ = getset___module__,


More information about the pypy-commit mailing list