7
7
import time
8
8
from collections import defaultdict
9
9
from collections .abc import Iterable , Iterator , Sequence
10
- from contextlib import contextmanager
10
+ from contextlib import contextmanager , nullcontext
11
11
from typing import Callable , ClassVar , Final , Optional , cast , overload
12
12
from typing_extensions import TypeAlias as _TypeAlias , assert_never
13
13
94
94
TypedDictExpr ,
95
95
TypeInfo ,
96
96
TypeVarExpr ,
97
+ TypeVarLikeExpr ,
97
98
TypeVarTupleExpr ,
98
99
UnaryExpr ,
99
100
Var ,
173
174
TypeOfAny ,
174
175
TypeType ,
175
176
TypeVarId ,
177
+ TypeVarLikeType ,
176
178
TypeVarTupleType ,
177
179
TypeVarType ,
178
180
UnboundType ,
@@ -377,26 +379,24 @@ def analyze_ref_expr(self, e: RefExpr, lvalue: bool = False) -> Type:
377
379
result = self .analyze_var_ref (node , e )
378
380
if isinstance (result , PartialType ):
379
381
result = self .chk .handle_partial_var_type (result , lvalue , node , e )
380
- elif isinstance (node , FuncDef ):
381
- # Reference to a global function.
382
- result = function_type (node , self .named_type ("builtins.function" ))
382
+ elif isinstance (node , Decorator ):
383
+ result = self .analyze_var_ref (node .var , e )
383
384
elif isinstance (node , OverloadedFuncDef ):
384
385
if node .type is None :
385
386
if self .chk .in_checked_function () and node .items :
386
387
self .chk .handle_cannot_determine_type (node .name , e )
387
388
result = AnyType (TypeOfAny .from_error )
388
389
else :
389
390
result = node .type
390
- elif isinstance (node , TypeInfo ):
391
- # Reference to a type object.
392
- if node .typeddict_type :
393
- # We special-case TypedDict, because they don't define any constructor.
394
- result = self .typeddict_callable (node )
395
- elif node .fullname == "types.NoneType" :
396
- # We special case NoneType, because its stub definition is not related to None.
397
- result = TypeType (NoneType ())
398
- else :
399
- result = type_object_type (node , self .named_type )
391
+ elif isinstance (node , (FuncDef , TypeInfo , TypeAlias , MypyFile , TypeVarLikeExpr )):
392
+ result = self .analyze_static_reference (node , e , e .is_alias_rvalue or lvalue )
393
+ else :
394
+ if isinstance (node , PlaceholderNode ):
395
+ assert False , f"PlaceholderNode { node .fullname !r} leaked to checker"
396
+ # Unknown reference; use any type implicitly to avoid
397
+ # generating extra type errors.
398
+ result = AnyType (TypeOfAny .from_error )
399
+ if isinstance (node , TypeInfo ):
400
400
if isinstance (result , CallableType ) and isinstance ( # type: ignore[misc]
401
401
result .ret_type , Instance
402
402
):
@@ -408,30 +408,56 @@ def analyze_ref_expr(self, e: RefExpr, lvalue: bool = False) -> Type:
408
408
# This is the type in a type[] expression, so substitute type
409
409
# variables with Any.
410
410
result = erasetype .erase_typevars (result )
411
- elif isinstance (node , MypyFile ):
412
- # Reference to a module object.
413
- result = self .module_type (node )
414
- elif isinstance (node , Decorator ):
415
- result = self .analyze_var_ref (node .var , e )
411
+ assert result is not None
412
+ return result
413
+
414
+ def analyze_static_reference (
415
+ self ,
416
+ node : SymbolNode ,
417
+ ctx : Context ,
418
+ is_lvalue : bool ,
419
+ * ,
420
+ include_modules : bool = True ,
421
+ suppress_errors : bool = False ,
422
+ ) -> Type :
423
+ """
424
+ This is the version of analyze_ref_expr() that doesn't do any deferrals.
425
+
426
+ This function can be used by member access to "static" attributes. For example,
427
+ when accessing module attributes in protocol checks, or accessing attributes of
428
+ special kinds (like TypeAlias, TypeInfo, etc.) on an instance or class object.
429
+ # TODO: merge with analyze_ref_expr() when we are confident about performance.
430
+ """
431
+ if isinstance (node , (Var , Decorator , OverloadedFuncDef )):
432
+ return node .type or AnyType (TypeOfAny .special_form )
433
+ elif isinstance (node , FuncDef ):
434
+ return function_type (node , self .named_type ("builtins.function" ))
435
+ elif isinstance (node , TypeInfo ):
436
+ # Reference to a type object.
437
+ if node .typeddict_type :
438
+ # We special-case TypedDict, because they don't define any constructor.
439
+ return self .typeddict_callable (node )
440
+ elif node .fullname == "types.NoneType" :
441
+ # We special case NoneType, because its stub definition is not related to None.
442
+ return TypeType (NoneType ())
443
+ else :
444
+ return type_object_type (node , self .named_type )
416
445
elif isinstance (node , TypeAlias ):
417
446
# Something that refers to a type alias appears in runtime context.
418
447
# Note that we suppress bogus errors for alias redefinitions,
419
448
# they are already reported in semanal.py.
420
- result = self .alias_type_in_runtime_context (
421
- node , ctx = e , alias_definition = e .is_alias_rvalue or lvalue
422
- )
449
+ with self .msg .filter_errors () if suppress_errors else nullcontext ():
450
+ return self .alias_type_in_runtime_context (
451
+ node , ctx = ctx , alias_definition = is_lvalue
452
+ )
423
453
elif isinstance (node , TypeVarExpr ):
424
454
return self .named_type ("typing.TypeVar" )
425
455
elif isinstance (node , (ParamSpecExpr , TypeVarTupleExpr )):
426
- result = self .object_type ()
427
- else :
428
- if isinstance (node , PlaceholderNode ):
429
- assert False , f"PlaceholderNode { node .fullname !r} leaked to checker"
430
- # Unknown reference; use any type implicitly to avoid
431
- # generating extra type errors.
432
- result = AnyType (TypeOfAny .from_error )
433
- assert result is not None
434
- return result
456
+ return self .object_type ()
457
+ elif isinstance (node , MypyFile ):
458
+ # Reference to a module object.
459
+ return self .module_type (node ) if include_modules else AnyType (TypeOfAny .special_form )
460
+ return AnyType (TypeOfAny .from_error )
435
461
436
462
def analyze_var_ref (self , var : Var , context : Context ) -> Type :
437
463
if var .type :
@@ -459,20 +485,21 @@ def module_type(self, node: MypyFile) -> Instance:
459
485
# Fall back to a dummy 'object' type instead to
460
486
# avoid a crash.
461
487
result = self .named_type ("builtins.object" )
462
- module_attrs = {}
488
+ module_attrs : dict [ str , Type ] = {}
463
489
immutable = set ()
464
490
for name , n in node .names .items ():
465
491
if not n .module_public :
466
492
continue
467
493
if isinstance (n .node , Var ) and n .node .is_final :
468
494
immutable .add (name )
469
- typ = self .chk .determine_type_of_member (n )
470
- if typ :
471
- module_attrs [name ] = typ
495
+ if n .node is None :
496
+ module_attrs [name ] = AnyType (TypeOfAny .from_error )
472
497
else :
473
498
# TODO: what to do about nested module references?
474
499
# They are non-trivial because there may be import cycles.
475
- module_attrs [name ] = AnyType (TypeOfAny .special_form )
500
+ module_attrs [name ] = self .analyze_static_reference (
501
+ n .node , n .node , False , include_modules = False , suppress_errors = True
502
+ )
476
503
result .extra_attrs = ExtraAttrs (module_attrs , immutable , node .fullname )
477
504
return result
478
505
@@ -961,19 +988,11 @@ def typeddict_callable(self, info: TypeInfo) -> CallableType:
961
988
assert info .special_alias is not None
962
989
target = info .special_alias .target
963
990
assert isinstance (target , ProperType ) and isinstance (target , TypedDictType )
964
- expected_types = list (target .items .values ())
965
- kinds = [ArgKind .ARG_NAMED ] * len (expected_types )
966
- names = list (target .items .keys ())
967
- return CallableType (
968
- expected_types ,
969
- kinds ,
970
- names ,
971
- target ,
972
- self .named_type ("builtins.type" ),
973
- variables = info .defn .type_vars ,
974
- )
991
+ return self .typeddict_callable_from_context (target , info .defn .type_vars )
975
992
976
- def typeddict_callable_from_context (self , callee : TypedDictType ) -> CallableType :
993
+ def typeddict_callable_from_context (
994
+ self , callee : TypedDictType , variables : Sequence [TypeVarLikeType ] | None = None
995
+ ) -> CallableType :
977
996
return CallableType (
978
997
list (callee .items .values ()),
979
998
[
@@ -983,6 +1002,8 @@ def typeddict_callable_from_context(self, callee: TypedDictType) -> CallableType
983
1002
list (callee .items .keys ()),
984
1003
callee ,
985
1004
self .named_type ("builtins.type" ),
1005
+ variables = variables ,
1006
+ is_bound = True ,
986
1007
)
987
1008
988
1009
def check_typeddict_call_with_kwargs (
0 commit comments