Skip to content

Commit f650315

Browse files
committed
fix: isinstance narrowing regression with dynamic tuple argument
When isinstance is called with a dynamically-computed tuple of types (e.g. isinstance(exc, tuple(expected_excs))), the second argument's stored type gets widened to match the _ClassInfo recursive type alias (type | types.UnionType | tuple[_ClassInfo, ...]). The union handler in get_type_range_of_type then decomposes this into individual members, producing TypeRange(object, ...) from bare 'type', which incorrectly narrows the expression to 'object' instead of keeping its existing type. Fix by checking if the simplified union result is just 'object' — which indicates we've lost type precision — and returning None to fall back to keeping the current type, matching the v1.19 behavior. Also handle None sub-items explicitly (propagate uncertainty) and filter out UninhabitedType entries before simplifying. Fixes #21181 Signed-off-by: bahtya <bahtyar153@qq.com>
1 parent bb05513 commit f650315

File tree

1 file changed

+11
-1
lines changed

1 file changed

+11
-1
lines changed

mypy/checker.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8028,7 +8028,17 @@ def get_type_range_of_type(self, typ: Type) -> TypeRange | None:
80288028

80298029
if isinstance(typ, UnionType):
80308030
type_ranges = [self.get_type_range_of_type(item) for item in typ.items]
8031-
item = make_simplified_union([t.item for t in type_ranges if t is not None])
8031+
if any(t is None for t in type_ranges):
8032+
return None
8033+
valid_ranges = [t for t in type_ranges if not isinstance(get_proper_type(t.item), UninhabitedType)]
8034+
if not valid_ranges:
8035+
return TypeRange(UninhabitedType(), is_upper_bound=False)
8036+
# If the only meaningful type we can extract is "object", we've lost
8037+
# type precision (e.g. from a widened _ClassInfo alias). Return None
8038+
# to avoid narrowing to a useless type.
8039+
item = make_simplified_union([t.item for t in valid_ranges])
8040+
if isinstance(get_proper_type(item), Instance) and get_proper_type(item).type.fullname == "builtins.object":
8041+
return None
80328042
return TypeRange(item, is_upper_bound=True)
80338043
if isinstance(typ, FunctionLike) and typ.is_type_obj():
80348044
# If a type is generic, `isinstance` can only narrow its variables to Any.

0 commit comments

Comments
 (0)