Fix False positive - Final local scope variable in Protocol#17308
Fix False positive - Final local scope variable in Protocol#17308JelleZijlstra merged 2 commits intopython:masterfrom
Conversation
This comment has been minimized.
This comment has been minimized.
stroxler
left a comment
There was a problem hiding this comment.
The tests seem good but I do have a question about whether the code change is implying new behavior for ClassVars.
| self.fail("Cannot use Final inside a loop", s) | ||
| if self.type and self.type.is_protocol: | ||
| self.msg.protocol_members_cant_be_final(s) | ||
| if self.is_class_scope(): |
There was a problem hiding this comment.
(at least as I'm reading it, this is the key change and hence my question about line 1623)
| assert self.type is not None, "No type set at class scope" | ||
| if self.type.is_protocol: | ||
| self.msg.protocol_members_cant_be_final(d) | ||
| if dec.var.is_classvar: |
There was a problem hiding this comment.
It looks like this change is allowing classvars to be Final on protocols.
Is that intended? I don't see a test for it, and I'm also not entirely sure it makes sense... what would a Final protocol classvar even mean, that classes which implement it must have a final classvar of matching type?
This comment has been minimized.
This comment has been minimized.
1 similar comment
This comment has been minimized.
This comment has been minimized.
|
@stroxler Thank you for your feedback. |
9b07d71 to
11a8027
Compare
This comment has been minimized.
This comment has been minimized.
|
I have squashed all of my commits into a single commit to simplify the commit history and make it easier to review. |
stroxler
left a comment
There was a problem hiding this comment.
Looks good to me with the simplified change, tests look solid.
You'll still need a maintainer review, but approving because that may make it quicker (I volunteered to start helping with reviews but I'm still new to MyPy).###
|
I feel this could theoretically still have bugs if there are nested classes involved (e.g., a class inside a protocol method). However, that's a much more obscure bug and I'm OK with merging this so we fix the reported bug. |
|
If it helps, I'd be happy to take a look at nested classes and either add tests proving this works or come up with a fix-forward as a follow-up. |
|
@JelleZijlstra as far as I understand, this implementation doesn't suffer from such problems. In case of a nested class (or a class defined in a method) we do not work in I cannot find any explicit documentation entries regarding (it may be worth including this test to document the behaviour For reference, |
|
Thanks! Would you mind adding a test for this behavior? I missed that the implementation already looks only at the topmost level in the stack. I don't really know what an inner class directly in a protocol should mean, but that's a separate issue. |
|
Would be glad to, but it's not my fork, sorry, I just wanted to review something:) @stroxler would you consider incorporating my suggested testcase? |
|
Ah sorry, should have checked the usernames. I can push your test case to this branch. |
Co-Authored-By: Stanislav Terliakov
|
Interesting that PyRight allows this. Now that I think about it, there's arguably a use case for Final attributes in protocols (which is not to say I necessarily think MyPy has to support it). Final in a class attribute actually means two mostly unrelated things, which I think is actually a bit problematic:
This actually strikes me as a gap in the typing semantics because it makes perfect sense to talk about non-final non-mutable attributes. In the case of a Protocol, non-overrideability doesn't really make any sense, but non-mutability does. Maybe I'll bring it up on the typing discourse at some point. In principle we could extend |
|
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅ |
|
You can also use an Agree that expanding ReadOnly to protocols could be useful. |
This PR fixes and closes #17281 ,which reported a false positive when using Final within the local function scope of a protocol method.
With these changes:
Modified
semanal.pyfile and added a unit test intest-data/unit/check.final.test