Author: Greg Price <pr...@mit.edu> Branch: signatures Changeset: r59326:aefa224aec97 Date: 2012-12-03 22:48 -0800 http://bitbucket.org/pypy/pypy/changeset/aefa224aec97/
Log: Add types.self notation, for signatures on methods diff --git a/pypy/annotation/signature.py b/pypy/annotation/signature.py --- a/pypy/annotation/signature.py +++ b/pypy/annotation/signature.py @@ -131,15 +131,18 @@ s_input)) inputcells[:] = args_s -def apply_bookkeeper(paramtype, bookkeeper): +def finish_type(paramtype, bookkeeper, func): + from pypy.annotation.types import SelfTypeMarker if isinstance(paramtype, SomeObject): return paramtype + elif isinstance(paramtype, SelfTypeMarker): + raise Exception("%r argument declared as annotation.types.self(); class needs decorator rlib.signature.finishsigs()" % (func,)) else: return paramtype(bookkeeper) def enforce_signature_args(funcdesc, paramtypes, actualtypes): assert len(paramtypes) == len(actualtypes) - params_s = [apply_bookkeeper(paramtype, funcdesc.bookkeeper) for paramtype in paramtypes] + params_s = [finish_type(paramtype, funcdesc.bookkeeper, funcdesc.pyobj) for paramtype in paramtypes] for i, (s_param, s_actual) in enumerate(zip(params_s, actualtypes)): if not s_param.contains(s_actual): raise Exception("%r argument %d:\n" @@ -148,4 +151,4 @@ actualtypes[:] = params_s def enforce_signature_return(funcdesc, sigtype, inferredtype): - return apply_bookkeeper(sigtype, funcdesc.bookkeeper) + return finish_type(sigtype, funcdesc.bookkeeper, funcdesc.pyobj) diff --git a/pypy/annotation/types.py b/pypy/annotation/types.py --- a/pypy/annotation/types.py +++ b/pypy/annotation/types.py @@ -46,3 +46,9 @@ def instance(class_): return lambda bookkeeper: model.SomeInstance(bookkeeper.getuniqueclassdef(class_)) + +class SelfTypeMarker(object): + pass + +def self(): + return SelfTypeMarker() diff --git a/pypy/rlib/signature.py b/pypy/rlib/signature.py --- a/pypy/rlib/signature.py +++ b/pypy/rlib/signature.py @@ -1,3 +1,4 @@ +from pypy.annotation import types def signature(*paramtypes, **kwargs): """Decorate a function to specify its type signature. @@ -17,3 +18,22 @@ f._signature_ = (paramtypes, returntype) return f return decorator + + +def finishsigs(cls): + """Decorate a class to finish any method signatures involving types.self(). + + This is required if any method has a signature with types.self() in it. + """ + # A bit annoying to have to use this, but it avoids performing any + # terrible hack in the implementation. Eventually we'll offer signatures + # on classes, and then that decorator can do this on the side. + def fix(sigtype): + if isinstance(sigtype, types.SelfTypeMarker): + return types.instance(cls) + return sigtype + for attr in cls.__dict__.values(): + if hasattr(attr, '_signature_'): + paramtypes, returntype = attr._signature_ + attr._signature_ = (tuple(fix(t) for t in paramtypes), fix(returntype)) + return cls diff --git a/pypy/rlib/test/test_signature.py b/pypy/rlib/test/test_signature.py --- a/pypy/rlib/test/test_signature.py +++ b/pypy/rlib/test/test_signature.py @@ -1,5 +1,5 @@ import py -from pypy.rlib.signature import signature +from pypy.rlib.signature import signature, finishsigs from pypy.annotation import types, model from pypy.translator.translator import TranslationContext, graphof @@ -180,3 +180,32 @@ @check_annotator_fails def bad_for_body(): f(C1()) + +def test_signature_self(): + @finishsigs + class C(object): + @signature(types.self(), types.self(), returns=types.none()) + def f(self, other): + pass + class D1(C): + pass + class D2(C): + pass + + def g(): + D1().f(D2()) + a = annotate_at(g) + + argtype = sigof(a, C.__dict__['f'])[0] + assert isinstance(argtype, model.SomeInstance) + assert argtype.classdef.classdesc.pyobj == C + +def test_signature_self_error(): + class C(object): + @signature(types.self(), returns=types.none()) + def incomplete_sig_meth(self): + pass + + exc = py.test.raises(Exception, annotate_at, C.incomplete_sig_meth).value + assert 'incomplete_sig_meth' in repr(exc.args) + assert 'finishsigs' in repr(exc.args) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit