Repository navigation
Conversation
|
it looks like with incremental compilation adding a decorator does not change the interface of the class and thus doesn't force recompilation of dependent modules. codex came up with this test case: we might need to also return which classes are decorated from https://github.com/python/mypy/blob/master/mypyc/codegen/emitmodule.py#L157 so that removing/adding a non-class decorator changes the interface. |
|
@p-sawicki I think codex is correct on this one; I wasn't too familiar with the incremental compilation feature. I've gone ahead and added your test with your suggested fix. Thanks! Also worth noting: adding |
Fixes mypyc/mypyc#1229.
A class decorator can replace a class with an object that isn't a class.
functools.cacheis the common case, as is a singleton decorator that returns a function. Such a class compiles as a non-native class, which can use arbitrary class decorators, but every method call and every function returning the class failed withX object expected; got X. Compiled code stored the decorated object, such as afunctools._lru_cache_wrapper, in the static that type checks,isinstance()andsuper()use as the class.Changes:
six.add_metaclass) works as before. Otherwise it gets the undecorated class, which is what instances still are. The module attribute is still the decorated object.Group(3)still goes through the cache, as in Python. A newClassIR.is_decoratedflag tracks this, since a class's decorators aren't available when its module comes from the incremental cache. Classes whose decorators are all ones native classes support (like@dataclassand@final) are unchanged, since those return a class.One difference from Python:
isinstance(x, Group)keeps the fast check against the undecorated class, where Python raisesTypeErrorbecauseGroupisn't a class. mypy treatsGroupas a class anyway, so this seemed better than a slower genericisinstance()for every decorated class, but I can switch it to the generic call if we'd rather match the error.