|
33 | 33 | ENUM_REMOVED_PROPS,
|
34 | 34 | AnyType,
|
35 | 35 | CallableType,
|
| 36 | + ExtraAttrs, |
36 | 37 | FormalArgument,
|
37 | 38 | FunctionLike,
|
38 | 39 | Instance,
|
@@ -466,16 +467,27 @@ def make_simplified_union(
|
466 | 467 |
|
467 | 468 | result = get_proper_type(UnionType.make_union(simplified_set, line, column))
|
468 | 469 |
|
469 |
| - # Step 4: At last, we erase any (inconsistent) extra attributes on instances. |
470 |
| - extra_attrs_set = set() |
471 |
| - for item in items: |
472 |
| - instance = try_getting_instance_fallback(item) |
473 |
| - if instance and instance.extra_attrs: |
474 |
| - extra_attrs_set.add(instance.extra_attrs) |
475 |
| - |
476 |
| - fallback = try_getting_instance_fallback(result) |
477 |
| - if len(extra_attrs_set) > 1 and fallback: |
478 |
| - fallback.extra_attrs = None |
| 470 | + nitems = len(items) |
| 471 | + if nitems > 1 and ( |
| 472 | + nitems > 2 or not (type(items[0]) is NoneType or type(items[1]) is NoneType) |
| 473 | + ): |
| 474 | + # Step 4: At last, we erase any (inconsistent) extra attributes on instances. |
| 475 | + |
| 476 | + # Initialize with None instead of an empty set as a micro-optimization. The set |
| 477 | + # is needed very rarely, so we try to avoid constructing it. |
| 478 | + extra_attrs_set: set[ExtraAttrs] | None = None |
| 479 | + for item in items: |
| 480 | + instance = try_getting_instance_fallback(item) |
| 481 | + if instance and instance.extra_attrs: |
| 482 | + if extra_attrs_set is None: |
| 483 | + extra_attrs_set = {instance.extra_attrs} |
| 484 | + else: |
| 485 | + extra_attrs_set.add(instance.extra_attrs) |
| 486 | + |
| 487 | + if extra_attrs_set is not None and len(extra_attrs_set) > 1: |
| 488 | + fallback = try_getting_instance_fallback(result) |
| 489 | + if fallback: |
| 490 | + fallback.extra_attrs = None |
479 | 491 |
|
480 | 492 | return result
|
481 | 493 |
|
@@ -1006,13 +1018,15 @@ def try_getting_instance_fallback(typ: Type) -> Instance | None:
|
1006 | 1018 | typ = get_proper_type(typ)
|
1007 | 1019 | if isinstance(typ, Instance):
|
1008 | 1020 | return typ
|
1009 |
| - elif isinstance(typ, TupleType): |
1010 |
| - return typ.partial_fallback |
1011 |
| - elif isinstance(typ, TypedDictType): |
| 1021 | + elif isinstance(typ, LiteralType): |
1012 | 1022 | return typ.fallback
|
| 1023 | + elif isinstance(typ, NoneType): |
| 1024 | + return None # Fast path for None, which is common |
1013 | 1025 | elif isinstance(typ, FunctionLike):
|
1014 | 1026 | return typ.fallback
|
1015 |
| - elif isinstance(typ, LiteralType): |
| 1027 | + elif isinstance(typ, TupleType): |
| 1028 | + return typ.partial_fallback |
| 1029 | + elif isinstance(typ, TypedDictType): |
1016 | 1030 | return typ.fallback
|
1017 | 1031 | elif isinstance(typ, TypeVarType):
|
1018 | 1032 | return try_getting_instance_fallback(typ.upper_bound)
|
|
0 commit comments