Skip to content

Commit 0562a8b

Browse files
shannonzhufacebook-github-bot
authored andcommitted
Document optional attribute refinement changes
Summary: Update error common issue documentation to reflect new rules around when refinement of globals/attributes is allowed. Didn't spend much time on this wording so adjustments are very welcome. Reviewed By: grievejia Differential Revision: D30431712 fbshipit-source-id: ed2dc639f5a14322525ffcca9ca7c4340371c029
1 parent 7e8666c commit 0562a8b

File tree

1 file changed

+6
-3
lines changed

1 file changed

+6
-3
lines changed

documentation/website/docs/errors.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,15 @@ def process_field(input: int) -> None:
120120

121121
def process_data(data: Data) -> None:
122122
if data.field:
123-
# ...
123+
# ... interleaving logic
124124
process_field(data.field) # Error: expected `int` but got `Optional[int]`
125125
```
126126

127-
The above fails to type-check because Pyre cannot guarantee that `data.field` is not `None` even after checking explicitly in the line before: `field` could be set to `None` by another thread or it could be a property that returns something different the next time we access it.
127+
The above fails to type-check because Pyre cannot guarantee that `data.field` remains not `None` if the interleaving logic between the explicit check and the later reference contains anything that may have side effects, like function calls.
128128

129-
The preferred way to make this code type-check is to mark the attribute `Final`, i.e. to specify that it can't be reassigned.
129+
An interleaving call could set `field` back to `None`, since it's a non local variable and is mutable. Therefore any calls between the None check and the access will invalidate the "not `None`" refinement. If `data.field` is defined as a class property or if the parent class has overridden `__getattr__`, then all bets are off even if there are no interleaving calls.
130+
131+
The preferred way to make this code type-check is to either move the check closer to the access, or to mark the attribute `Final` if it is not meant to be reassigned to, and you can guarantee to the type checker that no interleaving side effects can modify this attribute.
130132

131133
```python
132134
from typing import Final, Optional
@@ -144,6 +146,7 @@ Alternatively, it is also safe to assign the attribute to a local variable befor
144146
def process_data(data: Data) -> None:
145147
field = data.field
146148
if field:
149+
# ... interleaving logic
147150
process_field(field)
148151
```
149152

0 commit comments

Comments
 (0)