Skip to content

Make expression cache robust for nested generic calls - #22059

Open
ilevkivskyi wants to merge 1 commit into
python:masterfrom
ilevkivskyi:fix-expr-cache-gen
Open

ilevkivskyi wants to merge 1 commit into
python:masterfrom
ilevkivskyi:fix-expr-cache-gen

Conversation

@ilevkivskyi

Copy link
Copy Markdown
Member

Example in the added test takes almost a minute to check on current master, while with this PR it only takes milliseconds. This is unlikely to affect any real code (but should reduce the number of rare extreme cases of poor performance).

The problem is that we call freshen_function_type_vars() each time we type-check a generic function call. This means that arguments will get new type context each time, and our expression cache (which is our main guard against poor performance for deeply nested expressions) stops working, because type context is a part of the cache key.

The fix seems simple, only call freshen_function_type_vars() once per call expression (I also include original callable type as part of the new cache key for overloads). An alternative would be to erase type context before caching, but TypeVarEraser visitor takes some time, while expression cache is an ultra-hot code path.

Note the test I added relies on the fact that we call freshen_function_type_vars() in checkmember.py, without this PR it fails with:

Expected:
   main:16: note: Revealed type is "builtins.int"
-  main:22: note: Revealed type is "def [S] (x: S`46) -> S`46" (diff)
Actual:
   main:16: note: Revealed type is "builtins.int"
+  main:22: note: Revealed type is "def [S] (x: S`491326) -> S`491326" (diff)

Btw, I didn't find this while profiling slow libraries, I actually need this for something radical. I think I know how to fix mypy overusing outer context during inference once and for all (and likely remove all existing ad-hoc heuristics that compensate for this).

@github-actions

Copy link
Copy Markdown
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

core (https://github.com/home-assistant/core)
- Warning: disabling incremental mode may severely reduce performance
- If this is intentional, delete '.mypy_cache' to suppress this warning

rotki (https://github.com/rotki/rotki)
+ rotkehlchen/api/server.py:487: error: Value of type variable "ErrorHandlerT" of "error_handler" of "Parser" cannot be "Callable[[ValidationError, LocalProxy[Any], Schema, int | None, dict[Any, Any] | None], None]"  [type-var]
+ rotkehlchen/api/server.py:488: error: Value of type variable "ErrorHandlerT" of "error_handler" of "Parser" cannot be "Callable[[ValidationError, LocalProxy[Any], Schema, int | None, dict[Any, Any] | None], None]"  [type-var]

@ilevkivskyi

Copy link
Copy Markdown
Member Author

The diff in rotki is because we now have more precise location for errors in decorators (as a side effect of more precise expression context). The diff in homeassistant is spurious, see hauntsaninja/mypy_primer#263

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant