A Frame represents a specific point in the execution of a program. It carries information about the current types of expressions at that point, arising either from assignments to those expressions or the result of isinstance checks and other type narrowing operations. It also record
| 49 | |
| 50 | |
| 51 | class Frame: |
| 52 | """A Frame represents a specific point in the execution of a program. |
| 53 | |
| 54 | It carries information about the current types of expressions at |
| 55 | that point, arising either from assignments to those expressions |
| 56 | or the result of isinstance checks and other type narrowing |
| 57 | operations. It also records whether it is possible to reach that |
| 58 | point at all. |
| 59 | |
| 60 | We add a new frame wherenever there is a new scope or control flow |
| 61 | branching. |
| 62 | |
| 63 | This information is not copied into a new Frame when it is pushed |
| 64 | onto the stack, so a given Frame only has information about types |
| 65 | that were assigned in that frame. |
| 66 | |
| 67 | Expressions are stored in dicts using 'literal hashes' as keys (type |
| 68 | "Key"). These are hashable values derived from expression AST nodes |
| 69 | (only those that can be narrowed). literal_hash(expr) is used to |
| 70 | calculate the hashes. Note that this isn't directly related to literal |
| 71 | types -- the concept predates literal types. |
| 72 | """ |
| 73 | |
| 74 | def __init__(self, id: int, conditional_frame: bool = False) -> None: |
| 75 | self.id = id |
| 76 | self.types: dict[Key, CurrentType] = {} |
| 77 | self.unreachable = False |
| 78 | self.conditional_frame = conditional_frame |
| 79 | self.suppress_unreachable_warnings = False |
| 80 | |
| 81 | def __repr__(self) -> str: |
| 82 | return f"Frame({self.id}, {self.types}, {self.unreachable}, {self.conditional_frame})" |
| 83 | |
| 84 | |
| 85 | Assigns = defaultdict[Expression, list[tuple[Type, Type | None]]] |
no outgoing calls
no test coverage detected
searching dependent graphs…