Skip to content

Commit 05f3857

Browse files
authored
Fix type guard crashes (#11061)
Fixes #11007, fixes #10899, fixes #10647 Since the initial implementation of TypeGuard, there have been several fixes quickly applied to make mypy not crash on various TypeGuard things. This includes #10496, #10683 and #11015. We'll discuss how this PR relates to each of these three changes. In particular, #10496 seems incorrect. As A5rocks discusses in #10899 , it introduces confusion between a type guarded variable and a TypeGuard[T]. This PR basically walks back that change entirely and renames TypeGuardType to TypeGuardedType to reduce that possible confusion. Now, we still have the issue that TypeGuardedTypes are getting everywhere and causing unhappiness. I see two high level solutions to this: a) Make TypeGuardedType a proper type, then delegate to the wrapped type in a bunch of type visitors and arbitrary amounts of other places where multiple types interact, and hope that we got all of them, b) Make TypeGuardedType as an improper type (as it was in the original implementation)! Similar to TypeAliasType, it's just a wrapper for another type, so we unwrap it in get_proper_type. This is the approach this PR takes. This might feel controversial, but I think it could be the better option. It also means that if we type check we won't get type guard crashes. #10683 is basically "remove call that leads to crash from the stacktrace". I think the join here (that ends up being with the wrapped type of the TypeGuardedType) is actually fine: if it's different, it tells us that the type changed, which is what we want to know. So seems fine to remove the special casing. Finally, #11015. This is the other contentious part of this PR. I liked the idea of moving the core "type guard overrides narrowing" idea into meet.py, so I kept that. But my changes ended up regressing a reveal_type testTypeGuardNestedRestrictionAny test that was added. But it's not really clear to me how that worked or really, what it tested. I tried writing a simpler version of what I thought the test was meant to test (this is testTypeGuardMultipleCondition added in this PR), but that fails on master. Anyway, this should at least fix the type guard crashes that have been coming up.
1 parent e654572 commit 05f3857

19 files changed

+84
-117
lines changed

mypy/binder.py

+2-14
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from typing_extensions import DefaultDict
66

77
from mypy.types import (
8-
Type, AnyType, PartialType, UnionType, TypeOfAny, NoneType, TypeGuardType, get_proper_type
8+
Type, AnyType, PartialType, UnionType, TypeOfAny, NoneType, get_proper_type
99
)
1010
from mypy.subtypes import is_subtype
1111
from mypy.join import join_simple
@@ -210,9 +210,7 @@ def update_from_options(self, frames: List[Frame]) -> bool:
210210
else:
211211
for other in resulting_values[1:]:
212212
assert other is not None
213-
# Ignore the error about using get_proper_type().
214-
if not contains_type_guard(other):
215-
type = join_simple(self.declarations[key], type, other)
213+
type = join_simple(self.declarations[key], type, other)
216214
if current_value is None or not is_same_type(type, current_value):
217215
self._put(key, type)
218216
changed = True
@@ -440,13 +438,3 @@ def get_declaration(expr: BindableExpression) -> Optional[Type]:
440438
if not isinstance(type, PartialType):
441439
return type
442440
return None
443-
444-
445-
def contains_type_guard(other: Type) -> bool:
446-
# Ignore the error about using get_proper_type().
447-
if isinstance(other, TypeGuardType): # type: ignore[misc]
448-
return True
449-
other = get_proper_type(other)
450-
if isinstance(other, UnionType):
451-
return any(contains_type_guard(item) for item in other.relevant_items())
452-
return False

mypy/checker.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
UnionType, TypeVarId, TypeVarType, PartialType, DeletedType, UninhabitedType,
3737
is_named_instance, union_items, TypeQuery, LiteralType,
3838
is_optional, remove_optional, TypeTranslator, StarType, get_proper_type, ProperType,
39-
get_proper_types, is_literal_type, TypeAliasType, TypeGuardType)
39+
get_proper_types, is_literal_type, TypeAliasType, TypeGuardedType)
4040
from mypy.sametypes import is_same_type
4141
from mypy.messages import (
4242
MessageBuilder, make_inferred_type_note, append_invariance_notes, pretty_seq,
@@ -4265,7 +4265,7 @@ def find_isinstance_check_helper(self, node: Expression) -> Tuple[TypeMap, TypeM
42654265
# considered "always right" (i.e. even if the types are not overlapping).
42664266
# Also note that a care must be taken to unwrap this back at read places
42674267
# where we use this to narrow down declared type.
4268-
return {expr: TypeGuardType(node.callee.type_guard)}, {}
4268+
return {expr: TypeGuardedType(node.callee.type_guard)}, {}
42694269
elif isinstance(node, ComparisonExpr):
42704270
# Step 1: Obtain the types of each operand and whether or not we can
42714271
# narrow their types. (For example, we shouldn't try narrowing the

mypy/constraints.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
CallableType, Type, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarType, Instance,
88
TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType,
99
UninhabitedType, TypeType, TypeVarId, TypeQuery, is_named_instance, TypeOfAny, LiteralType,
10-
ProperType, get_proper_type, TypeAliasType, TypeGuardType
10+
ProperType, get_proper_type, TypeAliasType
1111
)
1212
from mypy.maptype import map_instance_to_supertype
1313
import mypy.subtypes
@@ -544,9 +544,6 @@ def visit_union_type(self, template: UnionType) -> List[Constraint]:
544544
def visit_type_alias_type(self, template: TypeAliasType) -> List[Constraint]:
545545
assert False, "This should be never called, got {}".format(template)
546546

547-
def visit_type_guard_type(self, template: TypeGuardType) -> List[Constraint]:
548-
assert False, "This should be never called, got {}".format(template)
549-
550547
def infer_against_any(self, types: Iterable[Type], any_type: AnyType) -> List[Constraint]:
551548
res: List[Constraint] = []
552549
for t in types:

mypy/erasetype.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Type, TypeVisitor, UnboundType, AnyType, NoneType, TypeVarId, Instance, TypeVarType,
55
CallableType, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType,
66
DeletedType, TypeTranslator, UninhabitedType, TypeType, TypeOfAny, LiteralType, ProperType,
7-
get_proper_type, TypeAliasType, TypeGuardType
7+
get_proper_type, TypeAliasType
88
)
99
from mypy.nodes import ARG_STAR, ARG_STAR2
1010

@@ -90,9 +90,6 @@ def visit_union_type(self, t: UnionType) -> ProperType:
9090
from mypy.typeops import make_simplified_union
9191
return make_simplified_union(erased_items)
9292

93-
def visit_type_guard_type(self, t: TypeGuardType) -> ProperType:
94-
return TypeGuardType(t.type_guard.accept(self))
95-
9693
def visit_type_type(self, t: TypeType) -> ProperType:
9794
return TypeType.make_normalized(t.item.accept(self), line=t.line)
9895

mypy/expandtype.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import Dict, Iterable, List, TypeVar, Mapping, cast
22

33
from mypy.types import (
4-
Type, Instance, CallableType, TypeGuardType, TypeVisitor, UnboundType, AnyType,
4+
Type, Instance, CallableType, TypeVisitor, UnboundType, AnyType,
55
NoneType, TypeVarType, Overloaded, TupleType, TypedDictType, UnionType,
66
ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, TypeVarId,
77
FunctionLike, TypeVarType, LiteralType, get_proper_type, ProperType,
@@ -129,9 +129,6 @@ def visit_union_type(self, t: UnionType) -> Type:
129129
from mypy.typeops import make_simplified_union # asdf
130130
return make_simplified_union(self.expand_types(t.items), t.line, t.column)
131131

132-
def visit_type_guard_type(self, t: TypeGuardType) -> ProperType:
133-
return TypeGuardType(t.type_guard.accept(self))
134-
135132
def visit_partial_type(self, t: PartialType) -> Type:
136133
return t
137134

mypy/fixup.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
TypeVarExpr, ClassDef, Block, TypeAlias,
1010
)
1111
from mypy.types import (
12-
CallableType, Instance, Overloaded, TupleType, TypeGuardType, TypedDictType,
12+
CallableType, Instance, Overloaded, TupleType, TypedDictType,
1313
TypeVarType, UnboundType, UnionType, TypeVisitor, LiteralType,
1414
TypeType, NOT_READY, TypeAliasType, AnyType, TypeOfAny
1515
)
@@ -254,9 +254,6 @@ def visit_union_type(self, ut: UnionType) -> None:
254254
for it in ut.items:
255255
it.accept(self)
256256

257-
def visit_type_guard_type(self, t: TypeGuardType) -> None:
258-
t.type_guard.accept(self)
259-
260257
def visit_void(self, o: Any) -> None:
261258
pass # Nothing to descend into.
262259

mypy/indirection.py

-3
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,6 @@ def visit_literal_type(self, t: types.LiteralType) -> Set[str]:
9797
def visit_union_type(self, t: types.UnionType) -> Set[str]:
9898
return self._visit(t.items)
9999

100-
def visit_type_guard_type(self, t: types.TypeGuardType) -> Set[str]:
101-
return self._visit(t.type_guard)
102-
103100
def visit_partial_type(self, t: types.PartialType) -> Set[str]:
104101
return set()
105102

mypy/join.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
Type, AnyType, NoneType, TypeVisitor, Instance, UnboundType, TypeVarType, CallableType,
88
TupleType, TypedDictType, ErasedType, UnionType, FunctionLike, Overloaded, LiteralType,
99
PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, get_proper_type,
10-
ProperType, get_proper_types, TypeAliasType, PlaceholderType, TypeGuardType
10+
ProperType, get_proper_types, TypeAliasType, PlaceholderType
1111
)
1212
from mypy.maptype import map_instance_to_supertype
1313
from mypy.subtypes import (
@@ -432,9 +432,6 @@ def visit_type_type(self, t: TypeType) -> ProperType:
432432
def visit_type_alias_type(self, t: TypeAliasType) -> ProperType:
433433
assert False, "This should be never called, got {}".format(t)
434434

435-
def visit_type_guard_type(self, t: TypeGuardType) -> ProperType:
436-
assert False, "This should be never called, got {}".format(t)
437-
438435
def join(self, s: Type, t: Type) -> ProperType:
439436
return join_types(s, t)
440437

mypy/meet.py

+13-14
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Type, AnyType, TypeVisitor, UnboundType, NoneType, TypeVarType, Instance, CallableType,
66
TupleType, TypedDictType, ErasedType, UnionType, PartialType, DeletedType,
77
UninhabitedType, TypeType, TypeOfAny, Overloaded, FunctionLike, LiteralType,
8-
ProperType, get_proper_type, get_proper_types, TypeAliasType, TypeGuardType
8+
ProperType, get_proper_type, get_proper_types, TypeAliasType, TypeGuardedType
99
)
1010
from mypy.subtypes import is_equivalent, is_subtype, is_callable_compatible, is_proper_subtype
1111
from mypy.erasetype import erase_type
@@ -51,16 +51,16 @@ def meet_types(s: Type, t: Type) -> ProperType:
5151
def narrow_declared_type(declared: Type, narrowed: Type) -> Type:
5252
"""Return the declared type narrowed down to another type."""
5353
# TODO: check infinite recursion for aliases here.
54+
if isinstance(narrowed, TypeGuardedType): # type: ignore[misc]
55+
# A type guard forces the new type even if it doesn't overlap the old.
56+
return narrowed.type_guard
57+
5458
declared = get_proper_type(declared)
5559
narrowed = get_proper_type(narrowed)
5660

5761
if declared == narrowed:
5862
return declared
59-
# Ignore the error about using get_proper_type().
60-
if isinstance(narrowed, TypeGuardType):
61-
# A type guard forces the new type even if it doesn't overlap the old.
62-
return narrowed.type_guard
63-
elif isinstance(declared, UnionType):
63+
if isinstance(declared, UnionType):
6464
return make_simplified_union([narrow_declared_type(x, narrowed)
6565
for x in declared.relevant_items()])
6666
elif not is_overlapping_types(declared, narrowed,
@@ -146,6 +146,13 @@ def is_overlapping_types(left: Type,
146146
If 'prohibit_none_typevar_overlap' is True, we disallow None from overlapping with
147147
TypeVars (in both strict-optional and non-strict-optional mode).
148148
"""
149+
if (
150+
isinstance(left, TypeGuardedType) # type: ignore[misc]
151+
or isinstance(right, TypeGuardedType) # type: ignore[misc]
152+
):
153+
# A type guard forces the new type even if it doesn't overlap the old.
154+
return True
155+
149156
left, right = get_proper_types((left, right))
150157

151158
def _is_overlapping_types(left: Type, right: Type) -> bool:
@@ -161,11 +168,6 @@ def _is_overlapping_types(left: Type, right: Type) -> bool:
161168
if isinstance(left, PartialType) or isinstance(right, PartialType):
162169
assert False, "Unexpectedly encountered partial type"
163170

164-
# Ignore the error about using get_proper_type().
165-
if isinstance(left, TypeGuardType) or isinstance(right, TypeGuardType):
166-
# A type guard forces the new type even if it doesn't overlap the old.
167-
return True
168-
169171
# We should also never encounter these types, but it's possible a few
170172
# have snuck through due to unrelated bugs. For now, we handle these
171173
# in the same way we handle 'Any'.
@@ -657,9 +659,6 @@ def visit_type_type(self, t: TypeType) -> ProperType:
657659
def visit_type_alias_type(self, t: TypeAliasType) -> ProperType:
658660
assert False, "This should be never called, got {}".format(t)
659661

660-
def visit_type_guard_type(self, t: TypeGuardType) -> ProperType:
661-
assert False, "This should be never called, got {}".format(t)
662-
663662
def meet(self, s: Type, t: Type) -> ProperType:
664663
return meet_types(s, t)
665664

mypy/sametypes.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import Sequence
22

33
from mypy.types import (
4-
Type, TypeGuardType, UnboundType, AnyType, NoneType, TupleType, TypedDictType,
4+
Type, UnboundType, AnyType, NoneType, TupleType, TypedDictType,
55
UnionType, CallableType, TypeVarType, Instance, TypeVisitor, ErasedType,
66
Overloaded, PartialType, DeletedType, UninhabitedType, TypeType, LiteralType,
77
ProperType, get_proper_type, TypeAliasType)
@@ -151,12 +151,6 @@ def visit_union_type(self, left: UnionType) -> bool:
151151
else:
152152
return False
153153

154-
def visit_type_guard_type(self, left: TypeGuardType) -> bool:
155-
if isinstance(self.right, TypeGuardType):
156-
return is_same_type(left.type_guard, self.right.type_guard)
157-
else:
158-
return False
159-
160154
def visit_overloaded(self, left: Overloaded) -> bool:
161155
if isinstance(self.right, Overloaded):
162156
return is_same_types(left.items, self.right.items)

mypy/server/astdiff.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class level -- these are handled at attribute level (say, 'mod.Cls.method'
5757
FuncBase, OverloadedFuncDef, FuncItem, MypyFile, UNBOUND_IMPORTED
5858
)
5959
from mypy.types import (
60-
Type, TypeGuardType, TypeVisitor, UnboundType, AnyType, NoneType, UninhabitedType,
60+
Type, TypeVisitor, UnboundType, AnyType, NoneType, UninhabitedType,
6161
ErasedType, DeletedType, Instance, TypeVarType, CallableType, TupleType, TypedDictType,
6262
UnionType, Overloaded, PartialType, TypeType, LiteralType, TypeAliasType
6363
)
@@ -335,9 +335,6 @@ def visit_union_type(self, typ: UnionType) -> SnapshotItem:
335335
normalized = tuple(sorted(items))
336336
return ('UnionType', normalized)
337337

338-
def visit_type_guard_type(self, typ: TypeGuardType) -> SnapshotItem:
339-
return ('TypeGuardType', snapshot_type(typ.type_guard))
340-
341338
def visit_overloaded(self, typ: Overloaded) -> SnapshotItem:
342339
return ('Overloaded', snapshot_types(typ.items))
343340

mypy/server/astmerge.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
Type, SyntheticTypeVisitor, Instance, AnyType, NoneType, CallableType, ErasedType, DeletedType,
6060
TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType,
6161
Overloaded, TypeVarType, TypeList, CallableArgument, EllipsisType, StarType, LiteralType,
62-
RawExpressionType, PartialType, PlaceholderType, TypeAliasType, TypeGuardType
62+
RawExpressionType, PartialType, PlaceholderType, TypeAliasType
6363
)
6464
from mypy.util import get_prefix, replace_object_state
6565
from mypy.typestate import TypeState
@@ -389,9 +389,6 @@ def visit_erased_type(self, t: ErasedType) -> None:
389389
def visit_deleted_type(self, typ: DeletedType) -> None:
390390
pass
391391

392-
def visit_type_guard_type(self, typ: TypeGuardType) -> None:
393-
raise RuntimeError
394-
395392
def visit_partial_type(self, typ: PartialType) -> None:
396393
raise RuntimeError
397394

mypy/server/deps.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class 'mod.Cls'. This can also refer to an attribute inherited from a
9999
Type, Instance, AnyType, NoneType, TypeVisitor, CallableType, DeletedType, PartialType,
100100
TupleType, TypeType, TypeVarType, TypedDictType, UnboundType, UninhabitedType, UnionType,
101101
FunctionLike, Overloaded, TypeOfAny, LiteralType, ErasedType, get_proper_type, ProperType,
102-
TypeAliasType, TypeGuardType
102+
TypeAliasType
103103
)
104104
from mypy.server.trigger import make_trigger, make_wildcard_trigger
105105
from mypy.util import correct_relative_import
@@ -967,9 +967,6 @@ def visit_unbound_type(self, typ: UnboundType) -> List[str]:
967967
def visit_uninhabited_type(self, typ: UninhabitedType) -> List[str]:
968968
return []
969969

970-
def visit_type_guard_type(self, typ: TypeGuardType) -> List[str]:
971-
return typ.type_guard.accept(self)
972-
973970
def visit_union_type(self, typ: UnionType) -> List[str]:
974971
triggers = []
975972
for item in typ.items:

mypy/subtypes.py

+1-12
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from typing_extensions import Final
55

66
from mypy.types import (
7-
Type, AnyType, TypeGuardType, UnboundType, TypeVisitor, FormalArgument, NoneType,
7+
Type, AnyType, UnboundType, TypeVisitor, FormalArgument, NoneType,
88
Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded,
99
ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, is_named_instance,
1010
FunctionLike, TypeOfAny, LiteralType, get_proper_type, TypeAliasType
@@ -475,9 +475,6 @@ def visit_overloaded(self, left: Overloaded) -> bool:
475475
def visit_union_type(self, left: UnionType) -> bool:
476476
return all(self._is_subtype(item, self.orig_right) for item in left.items)
477477

478-
def visit_type_guard_type(self, left: TypeGuardType) -> bool:
479-
raise RuntimeError("TypeGuard should not appear here")
480-
481478
def visit_partial_type(self, left: PartialType) -> bool:
482479
# This is indeterminate as we don't really know the complete type yet.
483480
raise RuntimeError
@@ -1377,14 +1374,6 @@ def visit_overloaded(self, left: Overloaded) -> bool:
13771374
def visit_union_type(self, left: UnionType) -> bool:
13781375
return all([self._is_proper_subtype(item, self.orig_right) for item in left.items])
13791376

1380-
def visit_type_guard_type(self, left: TypeGuardType) -> bool:
1381-
if isinstance(self.right, TypeGuardType):
1382-
# TypeGuard[bool] is a subtype of TypeGuard[int]
1383-
return self._is_proper_subtype(left.type_guard, self.right.type_guard)
1384-
else:
1385-
# TypeGuards aren't a subtype of anything else for now (but see #10489)
1386-
return False
1387-
13881377
def visit_partial_type(self, left: PartialType) -> bool:
13891378
# TODO: What's the right thing to do here?
13901379
return False

mypy/type_visitor.py

+1-11
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
T = TypeVar('T')
2020

2121
from mypy.types import (
22-
Type, AnyType, CallableType, Overloaded, TupleType, TypeGuardType, TypedDictType, LiteralType,
22+
Type, AnyType, CallableType, Overloaded, TupleType, TypedDictType, LiteralType,
2323
RawExpressionType, Instance, NoneType, TypeType,
2424
UnionType, TypeVarType, PartialType, DeletedType, UninhabitedType, TypeVarLikeType,
2525
UnboundType, ErasedType, StarType, EllipsisType, TypeList, CallableArgument,
@@ -103,10 +103,6 @@ def visit_type_type(self, t: TypeType) -> T:
103103
def visit_type_alias_type(self, t: TypeAliasType) -> T:
104104
pass
105105

106-
@abstractmethod
107-
def visit_type_guard_type(self, t: TypeGuardType) -> T:
108-
pass
109-
110106

111107
@trait
112108
@mypyc_attr(allow_interpreted_subclasses=True)
@@ -224,9 +220,6 @@ def visit_union_type(self, t: UnionType) -> Type:
224220
def translate_types(self, types: Iterable[Type]) -> List[Type]:
225221
return [t.accept(self) for t in types]
226222

227-
def visit_type_guard_type(self, t: TypeGuardType) -> Type:
228-
return TypeGuardType(t.type_guard.accept(self))
229-
230223
def translate_variables(self,
231224
variables: Sequence[TypeVarLikeType]) -> Sequence[TypeVarLikeType]:
232225
return variables
@@ -326,9 +319,6 @@ def visit_star_type(self, t: StarType) -> T:
326319
def visit_union_type(self, t: UnionType) -> T:
327320
return self.query_types(t.items)
328321

329-
def visit_type_guard_type(self, t: TypeGuardType) -> T:
330-
return t.type_guard.accept(self)
331-
332322
def visit_overloaded(self, t: Overloaded) -> T:
333323
return self.query_types(t.items)
334324

mypy/typeanal.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from mypy.types import (
1515
Type, UnboundType, TypeVarType, TupleType, TypedDictType, UnionType, Instance, AnyType,
1616
CallableType, NoneType, ErasedType, DeletedType, TypeList, TypeVarType, SyntheticTypeVisitor,
17-
StarType, PartialType, EllipsisType, UninhabitedType, TypeType, TypeGuardType, TypeVarLikeType,
17+
StarType, PartialType, EllipsisType, UninhabitedType, TypeType, TypeVarLikeType,
1818
CallableArgument, TypeQuery, union_items, TypeOfAny, LiteralType, RawExpressionType,
1919
PlaceholderType, Overloaded, get_proper_type, TypeAliasType, TypeVarLikeType, ParamSpecType
2020
)
@@ -547,9 +547,6 @@ def visit_callable_type(self, t: CallableType, nested: bool = True) -> Type:
547547
)
548548
return ret
549549

550-
def visit_type_guard_type(self, t: TypeGuardType) -> Type:
551-
return t
552-
553550
def anal_type_guard(self, t: Type) -> Optional[Type]:
554551
if isinstance(t, UnboundType):
555552
sym = self.lookup_qualified(t.name, t)

0 commit comments

Comments
 (0)