Implement sound type narrowing algorithms that balance precision with correctness. When narrowing types:

  1. For direct assignments, narrow the type to the assigned value’s type:
    x: int | None = None
    x = 42
    # x now has type Literal[42]
    
  2. For attributes and subscripts, only narrow when the operation is known to be sound:

Unsound - property may transform the value

@property def x(self): return self._x @x.setter def x(self, val): self._x = abs(val) obj.x = -1 # obj.x should still be int, not Literal[-1]


3. Reset narrowed types when the base object is reassigned:
```python
c = C()
c.attr = "foo"  # c.attr has type Literal["foo"]
c = C()         # c.attr should revert to its declared type
  1. For type guards, correctly intersect the original type with the guarded type: ```python def is_int(x: object) -> TypeIs[int]: …

def func(x: Any): if is_int(x): # x has type Any & int ```

Sound type narrowing algorithms prevent false negatives while maintaining precision, allowing for safer and more robust code.