|
6 | 6 | if MYPY:
|
7 | 7 | from typing import DefaultDict
|
8 | 8 |
|
9 |
| -from mypy.types import Type, AnyType, PartialType, UnionType, TypeOfAny |
| 9 | +from mypy.types import Type, AnyType, PartialType, UnionType, TypeOfAny, NoneTyp |
10 | 10 | from mypy.subtypes import is_subtype
|
11 | 11 | from mypy.join import join_simple
|
12 | 12 | from mypy.sametypes import is_same_type
|
@@ -276,9 +276,23 @@ def assign_type(self, expr: Expression,
|
276 | 276 | # isinstance check), but now it is reassigned, so broaden back
|
277 | 277 | # to Any (which is the most recent enclosing type)
|
278 | 278 | self.put(expr, enclosing_type)
|
| 279 | + # As a special case, when assigning Any to a variable with a |
| 280 | + # declared Optional type that has been narrowed to None, |
| 281 | + # replace all the Nones in the declared Union type with Any. |
| 282 | + # This overrides the normal behavior of ignoring Any assignments to variables |
| 283 | + # in order to prevent false positives. |
| 284 | + # (See discussion in #3526) |
| 285 | + elif (isinstance(type, AnyType) |
| 286 | + and isinstance(declared_type, UnionType) |
| 287 | + and any(isinstance(item, NoneTyp) for item in declared_type.items) |
| 288 | + and isinstance(self.most_recent_enclosing_type(expr, NoneTyp()), NoneTyp)): |
| 289 | + # Replace any Nones in the union type with Any |
| 290 | + new_items = [type if isinstance(item, NoneTyp) else item |
| 291 | + for item in declared_type.items] |
| 292 | + self.put(expr, UnionType(new_items)) |
279 | 293 | elif (isinstance(type, AnyType)
|
280 | 294 | and not (isinstance(declared_type, UnionType)
|
281 |
| - and any(isinstance(item, AnyType) for item in declared_type.items))): |
| 295 | + and (any(isinstance(item, AnyType) for item in declared_type.items)))): |
282 | 296 | # Assigning an Any value doesn't affect the type to avoid false negatives, unless
|
283 | 297 | # there is an Any item in a declared union type.
|
284 | 298 | self.put(expr, declared_type)
|
|
0 commit comments