Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r45174:c19ba84541c5 Date: 2011-06-29 09:40 +0200 http://bitbucket.org/pypy/pypy/changeset/c19ba84541c5/
Log: merge heads diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py --- a/pypy/annotation/bookkeeper.py +++ b/pypy/annotation/bookkeeper.py @@ -299,12 +299,13 @@ listdef.generalize_range_step(flags['range_step']) return SomeList(listdef) - def getdictdef(self, is_r_dict=False): + def getdictdef(self, is_r_dict=False, force_non_null=False): """Get the DictDef associated with the current position.""" try: dictdef = self.dictdefs[self.position_key] except KeyError: - dictdef = DictDef(self, is_r_dict=is_r_dict) + dictdef = DictDef(self, is_r_dict=is_r_dict, + force_non_null=force_non_null) self.dictdefs[self.position_key] = dictdef return dictdef diff --git a/pypy/annotation/builtin.py b/pypy/annotation/builtin.py --- a/pypy/annotation/builtin.py +++ b/pypy/annotation/builtin.py @@ -311,8 +311,14 @@ def robjmodel_we_are_translated(): return immutablevalue(True) -def robjmodel_r_dict(s_eqfn, s_hashfn): - dictdef = getbookkeeper().getdictdef(is_r_dict=True) +def robjmodel_r_dict(s_eqfn, s_hashfn, s_force_non_null=None): + if s_force_non_null is None: + force_non_null = False + else: + assert s_force_non_null.is_constant() + force_non_null = s_force_non_null.const + dictdef = getbookkeeper().getdictdef(is_r_dict=True, + force_non_null=force_non_null) dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn) return SomeDict(dictdef) diff --git a/pypy/annotation/dictdef.py b/pypy/annotation/dictdef.py --- a/pypy/annotation/dictdef.py +++ b/pypy/annotation/dictdef.py @@ -85,12 +85,14 @@ def __init__(self, bookkeeper, s_key = s_ImpossibleValue, s_value = s_ImpossibleValue, - is_r_dict = False): + is_r_dict = False, + force_non_null = False): self.dictkey = DictKey(bookkeeper, s_key, is_r_dict) self.dictkey.itemof[self] = True self.dictvalue = DictValue(bookkeeper, s_value) self.dictvalue.itemof[self] = True self.bookkeeper = bookkeeper + self.force_non_null = force_non_null def read_key(self, position_key=None): if position_key is None: diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -562,7 +562,8 @@ elif callable.api_func.restype is not lltype.Void: retval = rffi.cast(callable.api_func.restype, result) except Exception, e: - print 'Fatal error in cpyext, calling', callable.__name__ + print 'Fatal error in cpyext, CPython compatibility layer, calling', callable.__name__ + print 'Either report a bug or consider not using this particular extension' if not we_are_translated(): import traceback traceback.print_exc() diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,13 +1,14 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.settype import set_typedef as settypedef from pypy.interpreter import gateway from pypy.interpreter.argument import Signature from pypy.interpreter.error import OperationError, operationerrfmt from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS from pypy.rlib.objectmodel import r_dict, we_are_translated -from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.rlib.debug import mark_dict_non_null def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -59,7 +60,8 @@ def initialize_as_rdict(self): assert self.r_dict_content is None - self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w) + self.r_dict_content = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) return self.r_dict_content @@ -308,6 +310,7 @@ def __init__(self, space): self.space = space self.content = {} + mark_dict_non_null(self.content) def impl_setitem(self, w_key, w_value): space = self.space @@ -317,6 +320,7 @@ self._as_rdict().impl_fallback_setitem(w_key, w_value) def impl_setitem_str(self, key, w_value): + assert key is not None self.content[key] = w_value def impl_setdefault(self, w_key, w_default): @@ -342,6 +346,7 @@ return len(self.content) def impl_getitem_str(self, key): + assert key is not None return self.content.get(key, None) def impl_getitem(self, w_key): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -112,7 +112,7 @@ # some helper functions def newset(space): - return r_dict(space.eq_w, space.hash_w) + return r_dict(space.eq_w, space.hash_w, force_non_null=True) def make_setdata_from_w_iterable(space, w_iterable=None): """Return a new r_dict with the content of w_iterable.""" diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py --- a/pypy/rlib/debug.py +++ b/pypy/rlib/debug.py @@ -262,6 +262,28 @@ return hop.inputarg(hop.args_r[0], arg=0) +def mark_dict_non_null(d): + """ Mark dictionary as having non-null keys and values. A warning would + be emitted (not an error!) in case annotation disagrees. + """ + assert isinstance(d, dict) + return d + + +class DictMarkEntry(ExtRegistryEntry): + _about_ = mark_dict_non_null + + def compute_result_annotation(self, s_dict): + from pypy.annotation.model import SomeDict, s_None + + assert isinstance(s_dict, SomeDict) + s_dict.dictdef.force_non_null = True + return s_dict + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.inputarg(hop.args_r[0], arg=0) + class IntegerCanBeNegative(Exception): pass diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py --- a/pypy/rlib/objectmodel.py +++ b/pypy/rlib/objectmodel.py @@ -448,10 +448,11 @@ The functions key_eq() and key_hash() are used by the key comparison algorithm.""" - def __init__(self, key_eq, key_hash): + def __init__(self, key_eq, key_hash, force_non_null=False): self._dict = {} self.key_eq = key_eq self.key_hash = key_hash + self.force_non_null = force_non_null def __getitem__(self, key): return self._dict[_r_dictkey(self, key)] diff --git a/pypy/rlib/test/test_debug.py b/pypy/rlib/test/test_debug.py --- a/pypy/rlib/test/test_debug.py +++ b/pypy/rlib/test/test_debug.py @@ -1,11 +1,12 @@ import py -from pypy.rlib.debug import check_annotation, make_sure_not_resized -from pypy.rlib.debug import debug_print, debug_start, debug_stop -from pypy.rlib.debug import have_debug_prints, debug_offset, debug_flush -from pypy.rlib.debug import check_nonneg, IntegerCanBeNegative +from pypy.rlib.debug import (check_annotation, make_sure_not_resized, + debug_print, debug_start, debug_stop, + have_debug_prints, debug_offset, debug_flush, + check_nonneg, IntegerCanBeNegative, + mark_dict_non_null) from pypy.rlib import debug -from pypy.rpython.test.test_llinterp import interpret +from pypy.rpython.test.test_llinterp import interpret, gengraph def test_check_annotation(): class Error(Exception): @@ -52,8 +53,17 @@ py.test.raises(ListChangeUnallowed, interpret, f, [], list_comprehension_operations=True) +def test_mark_dict_non_null(): + def f(): + d = {"ac": "bx"} + mark_dict_non_null(d) + return d -class DebugTests: + t, typer, graph = gengraph(f, []) + assert sorted(graph.returnblock.inputargs[0].concretetype.TO.entries.TO.OF._flds.keys()) == ['key', 'value'] + + +class DebugTests(object): def test_debug_print_start_stop(self): def f(x): diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py --- a/pypy/rpython/lltypesystem/rdict.py +++ b/pypy/rpython/lltypesystem/rdict.py @@ -9,6 +9,7 @@ from pypy.rpython import robject from pypy.rlib import objectmodel, jit from pypy.rpython import rmodel +from pypy.rpython.error import TyperError HIGHEST_BIT = intmask(1 << (LONG_BIT - 1)) MASK = intmask(HIGHEST_BIT - 1) @@ -42,7 +43,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() self.lowleveltype = lltype.Ptr(self.DICT) @@ -61,6 +62,7 @@ self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash + self.force_non_null = force_non_null # setup() needs to be called to finish this initialization def _externalvsinternal(self, rtyper, item_repr): @@ -97,6 +99,13 @@ s_value = self.dictvalue.s_value nullkeymarker = not self.key_repr.can_ll_be_null(s_key) nullvaluemarker = not self.value_repr.can_ll_be_null(s_value) + if self.force_non_null: + if not nullkeymarker: + rmodel.warning("%s can be null, but forcing non-null in dict key" % s_key) + nullkeymarker = True + if not nullvaluemarker: + rmodel.warning("%s can be null, but forcing non-null in dict value" % s_value) + nullvaluemarker = True dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper, s_key) dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper, @@ -640,12 +649,15 @@ pass -def rtype_r_dict(hop): +def rtype_r_dict(hop, i_force_non_null=None): r_dict = hop.r_result if not r_dict.custom_eq_hash: raise TyperError("r_dict() call does not return an r_dict instance") - v_eqfn, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn, - r_dict.r_rdict_hashfn) + v_eqfn = hop.inputarg(r_dict.r_rdict_eqfn, arg=0) + v_hashfn = hop.inputarg(r_dict.r_rdict_hashfn, arg=1) + if i_force_non_null is not None: + assert i_force_non_null == 2 + hop.inputarg(lltype.Void, arg=2) cDICT = hop.inputconst(lltype.Void, r_dict.DICT) hop.exception_cannot_occur() v_result = hop.gendirectcall(ll_newdict, cDICT) diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py --- a/pypy/rpython/ootypesystem/rdict.py +++ b/pypy/rpython/ootypesystem/rdict.py @@ -18,7 +18,7 @@ class DictRepr(AbstractDictRepr): def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, - custom_eq_hash=None): + custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.custom_eq_hash = custom_eq_hash is not None diff --git a/pypy/rpython/rdict.py b/pypy/rpython/rdict.py --- a/pypy/rpython/rdict.py +++ b/pypy/rpython/rdict.py @@ -15,6 +15,7 @@ dictvalue = self.dictdef.dictvalue s_key = dictkey .s_value s_value = dictvalue.s_value + force_non_null = self.dictdef.force_non_null if (s_key.__class__ is annmodel.SomeObject and s_key.knowntype == object and s_value.__class__ is annmodel.SomeObject and s_value.knowntype == object): return robject.pyobj_repr @@ -29,7 +30,8 @@ lambda: rtyper.getrepr(s_value), dictkey, dictvalue, - custom_eq_hash) + custom_eq_hash, + force_non_null) def rtyper_makekey(self): self.dictdef.dictkey .dont_change_any_more = True diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py --- a/pypy/rpython/test/test_rdict.py +++ b/pypy/rpython/test/test_rdict.py @@ -598,7 +598,6 @@ res = self.interpret(func, []) assert res in [5263, 6352] - class TestLLtype(BaseTestRdict, LLRtypeMixin): def test_dict_but_not_with_char_keys(self): def func(i): @@ -860,6 +859,25 @@ res = f() assert res == 1 + def test_nonnull_hint(self): + def eq(a, b): + return a == b + def rhash(a): + return 3 + + def func(i): + d = r_dict(eq, rhash, force_non_null=True) + if not i: + d[None] = i + else: + d[str(i)] = i + return "12" in d, d + + llres = self.interpret(func, [12]) + assert llres.item0 == 1 + DICT = lltype.typeOf(llres.item1) + assert sorted(DICT.TO.entries.TO.OF._flds) == ['f_hash', 'key', 'value'] + # ____________________________________________________________ _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit