Author: Armin Rigo <ar...@tunes.org> Branch: py3k-kwonly-builtin Changeset: r86336:d428c0d4802a Date: 2016-08-20 09:15 +0200 http://bitbucket.org/pypy/pypy/changeset/d428c0d4802a/
Log: A much simpler solution gets us most of the way there (thanks fijal): rely on the mapdict logic diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -38,7 +38,9 @@ 'name?', 'w_kw_defs?'] - def __init__(self, space, code, w_globals=None, defs_w=[], w_kw_defs=None, + w_kw_defs = None + + def __init__(self, space, code, w_globals=None, defs_w=[], kw_defs_w=None, closure=None, w_ann=None, forcename=None, qualname=None): self.space = space self.name = forcename or code.co_name @@ -48,10 +50,12 @@ 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 + # + if kw_defs_w is not None: + self.init_kwdefaults_dict(kw_defs_w) def __repr__(self): # return "function %s.%s" % (self.space, self.name) @@ -379,14 +383,29 @@ 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): - raise oefmt(space.w_TypeError, "__kwdefaults__ must be a dict") - self.w_kw_defs = w_new + self.w_kw_defs = None + else: + if not space.isinstance_w(w_new, space.w_dict): + raise oefmt(space.w_TypeError, "__kwdefaults__ must be a dict") + w_instance = self.init_kwdefaults_dict() + w_instance.setdict(space, w_new) + self.w_kw_defs = w_instance.getdict(space) def fdel_func_kwdefaults(self, space): self.w_kw_defs = None + def init_kwdefaults_dict(self, kw_defs_w=[]): + # use the mapdict logic to get at least not-too-bad JIT code + # from function calls with default values of kwonly arguments + space = self.space + w_class = space.fromcache(KwDefsClassCache).w_class + w_instance = space.call_function(w_class) + for w_name, w_value in kw_defs_w: + attr = space.unicode_w(w_name).encode('utf-8') + w_instance.setdictvalue(space, attr, w_value) + self.w_kw_defs = w_instance.getdict(space) + return w_instance + def fget_func_doc(self, space): if self.w_doc is None: self.w_doc = self.code.getdocstring(space) @@ -663,11 +682,12 @@ def __init__(self, func): assert isinstance(func, Function) Function.__init__(self, func.space, func.code, func.w_func_globals, - func.defs_w, func.w_kw_defs, func.closure, + 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 + self.w_kw_defs = func.w_kw_defs def descr_builtinfunction__new__(space, w_subtype): raise oefmt(space.w_TypeError, @@ -685,3 +705,12 @@ else: code = None return isinstance(code, BuiltinCode) + + +class KwDefsClassCache: + def __init__(self, space): + self.w_class = space.appexec([], """(): + class KwDefs: + pass + return KwDefs + """) diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -1235,15 +1235,15 @@ for i in range(len(names_w) - 1, -1, -1): space.setitem(w_ann, names_w[i], self.popvalue()) defaultarguments = self.popvalues(posdefaults) - w_kw_defs = None + kw_defs_w = 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) + kw_defs_w = [] + for i in range(kwdefaults): + w_defvalue = self.popvalue() + w_defname = self.popvalue() + kw_defs_w.append((w_defname, w_defvalue)) fn = function.Function(space, codeobj, self.get_w_globals(), defaultarguments, - w_kw_defs, freevars, w_ann, qualname=qualname) + kw_defs_w, freevars, w_ann, qualname=qualname) self.pushvalue(space.wrap(fn)) def MAKE_FUNCTION(self, oparg, next_instr): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit