def visit_decorator(self, dec: Decorator) -> None: if dec.decorators: decorators_to_store = dec.decorators.copy() decorators_to_remove: List[int] = [] # the index of the last non-register decorator before finding a register decorator # when going through decorators from top to bottom last_non_register: Optional[int] = None for i, d in enumerate(decorators_to_store): impl = get_singledispatch_register_call_info(d, dec.func) if impl is not None: self.singledispatch_impls[impl.singledispatch_func].append( (impl.dispatch_type, dec.func)) decorators_to_remove.append(i) if last_non_register is not None: # found a register decorator after a non-register decorator, which we # don't support because we'd have to make a copy of the function before # calling the decorator so that we can call it later, which complicates # the implementation for something that is probably not commonly used self.errors.error( "Calling decorator after registering function not supported", self.current_path, decorators_to_store[last_non_register].line, ) else: if refers_to_fullname(d, 'functools.singledispatch'): decorators_to_remove.append(i) # make sure that we still treat the function as a singledispatch function # even if we don't find any registered implementations (which might happen # if all registered implementations are registered dynamically) self.singledispatch_impls.setdefault(dec.func, []) last_non_register = i if decorators_to_remove: # calling register on a function that tries to dispatch based on type annotations # raises a TypeError because compiled functions don't have an __annotations__ # attribute self.decorators_to_remove[dec.func] = decorators_to_remove super().visit_decorator(dec)