-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[red-knot] Lookup of __new__
#17733
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[red-knot] Lookup of __new__
#17733
Conversation
|
__new__ and __init__ calls__new__
3191359 to
d1e9046
Compare
d1e9046 to
e0cc310
Compare
crates/red_knot_python_semantic/resources/mdtest/call/constructor.md
Outdated
Show resolved
Hide resolved
|
|
||
| match new_method { | ||
| Symbol::Type(new_method, boundness) => { | ||
| let result = new_method.try_call(db, CallArgumentTypes::clone(argument_types)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: If it's not too invasive, can we update try_call to take in &mut CallArgumentTypes? That would let you avoid the clone here. (I did that in a previous PR to try_call_dunder_with_policy) It's probably not performance-critical, just seems like conceptually unnecessary work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did that in 7768b9b. It's a bit awkward if you want to call it with a temporary CallArgumentTypes:
x.try_call(db, &mut CallArgumentTypes::positional(…)…)
I'm not entirely sure why the call API takes in mutable references to CallArgumentTypes in functions like Bindings::check_types etc.? For performance reasons.. since we want to make .with_self efficient? It looks a bit weird, because as a caller, I don't know if it's guaranteed that my call arguments are left unmodified.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For performance reasons.. since we want to make
.with_selfefficient?
That's right, so that we're not cloning the non-bound arguments each time we prepend a bound self.
It looks a bit weird, because as a caller, I don't know if it's guaranteed that my call arguments are left unmodified.
That's a good point. It does signify that we're using internal state in a way that isn't reentrant, but doesn't describe that it comes back to you unmodified. (Or rather, with any modifications reverted.)
I can see two other ways to handle with_self, either of which would drop the mut requirement:
-
Eat the cost of copying the non-bound arguments
-
Use something like
struct CallArgumentTypes { bound_self: Option<Type>, non_bound_arguments: Rc<[Type]>, }
I'd be fine with either of those modifications, but think that should be a separate PR, and that this one should try to remain consistent with our current handling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, thanks. I'll note this down as a (lower priority) TODO for myself.
AlexWaygood
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not yet a full review
crates/red_knot_python_semantic/resources/mdtest/call/constructor.md
Outdated
Show resolved
Hide resolved
crates/red_knot_python_semantic/resources/mdtest/call/constructor.md
Outdated
Show resolved
Hide resolved
crates/red_knot_python_semantic/resources/mdtest/call/constructor.md
Outdated
Show resolved
Hide resolved
crates/red_knot_python_semantic/resources/mdtest/call/constructor.md
Outdated
Show resolved
Hide resolved
crates/red_knot_python_semantic/resources/mdtest/call/constructor.md
Outdated
Show resolved
Hide resolved
AlexWaygood
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks excellent, thank you
* main: [red-knot] Preliminary `NamedTuple` support (#17738) [red-knot] Add tests for classes that have incompatible `__new__` and `__init__` methods (#17747) Update dependency vite to v6.2.7 (#17746) [red-knot] Update call binding to return all matching overloads (#17618) [`airflow`] apply Replacement::AutoImport to `AIR312` (#17570) [`ruff`] Add fix safety section (`RUF028`) (#17722) [syntax-errors] Detect single starred expression assignment `x = *y` (#17624) py-fuzzer: fix minimization logic when `--only-new-bugs` is passed (#17739) Fix example syntax for pydocstyle ignore_var_parameters option (#17740) [red-knot] Update salsa to prevent panic in custom panic-handler (#17742) [red-knot] Ban direct instantiation of generic protocols as well as non-generic ones (#17741) [red-knot] Lookup of `__new__` (#17733) [red-knot] Check decorator consistency on overloads (#17684) [`flake8-use-pathlib`] Avoid suggesting `Path.iterdir()` for `os.listdir` with file descriptor (`PTH208`) (#17715) [red-knot] Check overloads without an implementation (#17681) Expand Semantic Syntax Coverage (#17725) [red-knot] Check for invalid overload usages (#17609)
## Summary Remove mutability in parameter types for a few functions such as `with_self` and `try_call`. I tried the `Rc`-approach with cheap cloning [suggest here](#17733 (comment)) first, but it turns out we need a whole stack of prepended arguments (there can be [both `self` *and* `cls`](https://github.com/astral-sh/ruff/blob/3cf44e401a64658c17652cd3a17c897dc50261eb/crates/red_knot_python_semantic/resources/mdtest/call/constructor.md?plain=1#L113)), and we would need the same construct not just for `CallArguments` but also for `CallArgumentTypes`. At that point we're cloning `VecDeque`s anyway, so the overhead of cloning the whole `VecDeque` with all arguments didn't seem to justify the additional code complexity. ## Benchmarks Benchmarks on tomllib, black, jinja, isort seem neutral.
Summary
Model the lookup of
__new__without going throughType::try_call_dunder. The__new__method is only looked up on the constructed type itself, not on the meta-type.This now removes ~930 false positives across the ecosystem (vs 255 for #17662). It introduces 30 new false positives related to the construction of enums via something like
Color = enum.Enum("Color", ["RED", "GREEN"]). This is expected, because we don't handle custom metaclass__call__methods. The fact that we previously didn't emit diagnostics there was a coincidence (we incorrectly calledEnumMeta.__new__, and since we don't fully understand its signature, that happened to work withstr,listarguments).closes #17462
Test Plan
Regression test