Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speed up the implementation of hasattr() checks #14333

Merged
merged 2 commits into from
Dec 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mypy/meet.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def meet_types(s: Type, t: Type) -> ProperType:
# Code in checker.py should merge any extra_items where possible, so we
# should have only compatible extra_items here. We check this before
# the below subtype check, so that extra_attrs will not get erased.
if is_same_type(s, t) and (s.extra_attrs or t.extra_attrs):
if (s.extra_attrs or t.extra_attrs) and is_same_type(s, t):
if s.extra_attrs and t.extra_attrs:
if len(s.extra_attrs.attrs) > len(t.extra_attrs.attrs):
# Return the one that has more precise information.
Expand Down
42 changes: 28 additions & 14 deletions mypy/typeops.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
ENUM_REMOVED_PROPS,
AnyType,
CallableType,
ExtraAttrs,
FormalArgument,
FunctionLike,
Instance,
Expand Down Expand Up @@ -466,16 +467,27 @@ def make_simplified_union(

result = get_proper_type(UnionType.make_union(simplified_set, line, column))

# Step 4: At last, we erase any (inconsistent) extra attributes on instances.
extra_attrs_set = set()
for item in items:
instance = try_getting_instance_fallback(item)
if instance and instance.extra_attrs:
extra_attrs_set.add(instance.extra_attrs)

fallback = try_getting_instance_fallback(result)
if len(extra_attrs_set) > 1 and fallback:
fallback.extra_attrs = None
nitems = len(items)
if nitems > 1 and (
nitems > 2 or not (type(items[0]) is NoneType or type(items[1]) is NoneType)
):
# Step 4: At last, we erase any (inconsistent) extra attributes on instances.

# Initialize with None instead of an empty set as a micro-optimization. The set
# is needed very rarely, so we try to avoid constructing it.
extra_attrs_set: set[ExtraAttrs] | None = None
for item in items:
instance = try_getting_instance_fallback(item)
if instance and instance.extra_attrs:
if extra_attrs_set is None:
extra_attrs_set = {instance.extra_attrs}
else:
extra_attrs_set.add(instance.extra_attrs)

if extra_attrs_set is not None and len(extra_attrs_set) > 1:
fallback = try_getting_instance_fallback(result)
if fallback:
fallback.extra_attrs = None

return result

Expand Down Expand Up @@ -1006,13 +1018,15 @@ def try_getting_instance_fallback(typ: Type) -> Instance | None:
typ = get_proper_type(typ)
if isinstance(typ, Instance):
return typ
elif isinstance(typ, TupleType):
return typ.partial_fallback
elif isinstance(typ, TypedDictType):
elif isinstance(typ, LiteralType):
return typ.fallback
elif isinstance(typ, NoneType):
return None # Fast path for None, which is common
elif isinstance(typ, FunctionLike):
return typ.fallback
elif isinstance(typ, LiteralType):
elif isinstance(typ, TupleType):
return typ.partial_fallback
elif isinstance(typ, TypedDictType):
return typ.fallback
elif isinstance(typ, TypeVarType):
return try_getting_instance_fallback(typ.upper_bound)
Expand Down