Merge consecutive function overloads into OverloadedFuncDef nodes. Also handles conditional overloads (overloads inside if statements).
(state: State, stmts: list[Statement])
| 1803 | |
| 1804 | |
| 1805 | def fix_function_overloads(state: State, stmts: list[Statement]) -> list[Statement]: |
| 1806 | """Merge consecutive function overloads into OverloadedFuncDef nodes. |
| 1807 | |
| 1808 | Also handles conditional overloads (overloads inside if statements). |
| 1809 | """ |
| 1810 | ret: list[Statement] = [] |
| 1811 | current_overload: list[OverloadPart] = [] |
| 1812 | current_overload_name: str | None = None |
| 1813 | last_unconditional_func_def: str | None = None |
| 1814 | last_if_stmt: IfStmt | None = None |
| 1815 | last_if_overload: Decorator | FuncDef | OverloadedFuncDef | None = None |
| 1816 | last_if_stmt_overload_name: str | None = None |
| 1817 | last_if_unknown_truth_value: IfStmt | None = None |
| 1818 | skipped_if_stmts: list[IfStmt] = [] |
| 1819 | for stmt in stmts: |
| 1820 | if_overload_name: str | None = None |
| 1821 | if_block_with_overload: Block | None = None |
| 1822 | if_unknown_truth_value: IfStmt | None = None |
| 1823 | if isinstance(stmt, IfStmt): |
| 1824 | # Check IfStmt block to determine if function overloads can be merged |
| 1825 | if_overload_name = check_ifstmt_for_overloads(stmt, current_overload_name) |
| 1826 | if if_overload_name is not None: |
| 1827 | if_block_with_overload, if_unknown_truth_value = ( |
| 1828 | get_executable_if_block_with_overloads(stmt, state.options) |
| 1829 | ) |
| 1830 | |
| 1831 | if ( |
| 1832 | current_overload_name is not None |
| 1833 | and isinstance(stmt, (Decorator, FuncDef)) |
| 1834 | and stmt.name == current_overload_name |
| 1835 | ): |
| 1836 | if last_if_stmt is not None: |
| 1837 | skipped_if_stmts.append(last_if_stmt) |
| 1838 | if last_if_overload is not None: |
| 1839 | # Last stmt was an IfStmt with same overload name |
| 1840 | # Add overloads to current_overload |
| 1841 | if isinstance(last_if_overload, OverloadedFuncDef): |
| 1842 | current_overload.extend(last_if_overload.items) |
| 1843 | else: |
| 1844 | current_overload.append(last_if_overload) |
| 1845 | last_if_stmt, last_if_overload = None, None |
| 1846 | if last_if_unknown_truth_value: |
| 1847 | fail_merge_overload(state, last_if_unknown_truth_value) |
| 1848 | last_if_unknown_truth_value = None |
| 1849 | current_overload.append(stmt) |
| 1850 | if isinstance(stmt, FuncDef): |
| 1851 | # This is, strictly speaking, wrong: there might be a decorated |
| 1852 | # implementation. However, it only affects the error message we show: |
| 1853 | # ideally it's "already defined", but "implementation must come last" |
| 1854 | # is also reasonable. |
| 1855 | # TODO: can we get rid of this completely and just always emit |
| 1856 | # "implementation must come last" instead? |
| 1857 | last_unconditional_func_def = stmt.name |
| 1858 | elif ( |
| 1859 | current_overload_name is not None |
| 1860 | and isinstance(stmt, IfStmt) |
| 1861 | and if_overload_name == current_overload_name |
| 1862 | and last_unconditional_func_def != current_overload_name |
no test coverage detected
searching dependent graphs…