Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit14ece7b

Browse files
Merge branch 'master' into fix_typevar_default
2 parents70fbf96 +ad76e16 commit14ece7b

File tree

21 files changed

+540
-123
lines changed

21 files changed

+540
-123
lines changed

‎mypy/binder.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ def __init__(self, options: Options) -> None:
138138
# flexible inference of variable types (--allow-redefinition-new).
139139
self.bind_all=options.allow_redefinition_new
140140

141+
# This tracks any externally visible changes in binder to invalidate
142+
# expression caches when needed.
143+
self.version=0
144+
141145
def_get_id(self)->int:
142146
self.next_id+=1
143147
returnself.next_id
@@ -158,6 +162,7 @@ def push_frame(self, conditional_frame: bool = False) -> Frame:
158162
returnf
159163

160164
def_put(self,key:Key,type:Type,from_assignment:bool,index:int=-1)->None:
165+
self.version+=1
161166
self.frames[index].types[key]=CurrentType(type,from_assignment)
162167

163168
def_get(self,key:Key,index:int=-1)->CurrentType|None:
@@ -185,6 +190,7 @@ def put(self, expr: Expression, typ: Type, *, from_assignment: bool = True) -> N
185190
self._put(key,typ,from_assignment)
186191

187192
defunreachable(self)->None:
193+
self.version+=1
188194
self.frames[-1].unreachable=True
189195

190196
defsuppress_unreachable_warnings(self)->None:

‎mypy/build.py‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ def default_flush_errors(
194194
result.errors=messages
195195
returnresult
196196
exceptCompileErrorase:
197-
# CompileErrors raised from an errors object carry allofthe
197+
# CompileErrors raised from an errors object carry all the
198198
# messages that have not been reported out by error streaming.
199199
# Patch it up to contain either none or all none of the messages,
200200
# depending on whether we are flushing errors.
@@ -802,11 +802,11 @@ def correct_rel_imp(imp: ImportFrom | ImportAll) -> str:
802802
res.append((pri,sub_id,imp.line))
803803
else:
804804
all_are_submodules=False
805-
# Add cur_id as a dependency, even if allofthe
805+
# Add cur_id as a dependency, even if all the
806806
# imports are submodules. Processing import from will try
807807
# to look through cur_id, so we should depend on it.
808-
# As a workaround forforsome bugs in cycle handling (#4498),
809-
# if allofthe imports are submodules, do the import at a lower
808+
# As a workaround for some bugs in cycle handling (#4498),
809+
# if all the imports are submodules, do the import at a lower
810810
# priority.
811811
pri=import_priority(imp,PRI_HIGHifnotall_are_submoduleselsePRI_LOW)
812812
res.append((pri,cur_id,imp.line))
@@ -929,7 +929,7 @@ def write_deps_cache(
929929
)->None:
930930
"""Write cache files for fine-grained dependencies.
931931
932-
Serialize fine-grained dependencies map for finegrained mode.
932+
Serialize fine-grained dependencies map for fine-grained mode.
933933
934934
Dependencies on some module 'm' is stored in the dependency cache
935935
file m.deps.json. This entails some spooky action at a distance:
@@ -943,7 +943,7 @@ def write_deps_cache(
943943
fine-grained dependencies in a global cache file:
944944
* We take a snapshot of current sources to later check consistency
945945
between the fine-grained dependency cache and module cache metadata
946-
* We store the mtime of allofthe dependency files to verify they
946+
* We store the mtime of all the dependency files to verify they
947947
haven't changed
948948
"""
949949
metastore=manager.metastore
@@ -1111,7 +1111,7 @@ def read_deps_cache(manager: BuildManager, graph: Graph) -> dict[str, FgDepMeta]
11111111
ifdeps_metaisNone:
11121112
returnNone
11131113
meta_snapshot=deps_meta["snapshot"]
1114-
# Take a snapshot of the source hashes from allofthe metas we found.
1114+
# Take a snapshot of the source hashes from all the metas we found.
11151115
# (Including the ones we rejected because they were out of date.)
11161116
# We use this to verify that they match up with the proto_deps.
11171117
current_meta_snapshot= {

‎mypy/checker.py‎

Lines changed: 80 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ def __init__(
397397
self.is_stub=tree.is_stub
398398
self.is_typeshed_stub=tree.is_typeshed_file(options)
399399
self.inferred_attribute_types=None
400+
self.allow_constructor_cache=True
400401

401402
# If True, process function definitions. If False, don't. This is used
402403
# for processing module top levels in fine-grained incremental mode.
@@ -448,7 +449,6 @@ def reset(self) -> None:
448449
self.binder=ConditionalTypeBinder(self.options)
449450
self._type_maps[1:]= []
450451
self._type_maps[0].clear()
451-
self.temp_type_map=None
452452
self.expr_checker.reset()
453453
self.deferred_nodes= []
454454
self.partial_types= []
@@ -500,12 +500,16 @@ def check_first_pass(self) -> None:
500500
)
501501

502502
defcheck_second_pass(
503-
self,todo:Sequence[DeferredNode|FineGrainedDeferredNode]|None=None
503+
self,
504+
todo:Sequence[DeferredNode|FineGrainedDeferredNode]|None=None,
505+
*,
506+
allow_constructor_cache:bool=True,
504507
)->bool:
505508
"""Run second or following pass of type checking.
506509
507510
This goes through deferred nodes, returning True if there were any.
508511
"""
512+
self.allow_constructor_cache=allow_constructor_cache
509513
self.recurse_into_functions=True
510514
withstate.strict_optional_set(self.options.strict_optional),checker_state.set(self):
511515
ifnottodoandnotself.deferred_nodes:
@@ -1369,49 +1373,19 @@ def check_func_def(
13691373
)
13701374

13711375
# Store argument types.
1376+
found_self=False
1377+
ifisinstance(defn,FuncDef)andnotdefn.is_decorated:
1378+
found_self=self.require_correct_self_argument(typ,defn)
13721379
foriinrange(len(typ.arg_types)):
13731380
arg_type=typ.arg_types[i]
1374-
if (
1375-
isinstance(defn,FuncDef)
1376-
andref_typeisnotNone
1377-
andi==0
1378-
anddefn.has_self_or_cls_argument
1379-
andtyp.arg_kinds[0]notin [nodes.ARG_STAR,nodes.ARG_STAR2]
1380-
):
1381-
ifdefn.is_classordefn.name=="__new__":
1382-
ref_type=mypy.types.TypeType.make_normalized(ref_type)
1383-
ifnotis_same_type(arg_type,ref_type):
1384-
# This level of erasure matches the one in checkmember.check_self_arg(),
1385-
# better keep these two checks consistent.
1386-
erased=get_proper_type(erase_typevars(erase_to_bound(arg_type)))
1387-
ifnotis_subtype(ref_type,erased,ignore_type_params=True):
1388-
if (
1389-
isinstance(erased,Instance)
1390-
anderased.type.is_protocol
1391-
orisinstance(erased,TypeType)
1392-
andisinstance(erased.item,Instance)
1393-
anderased.item.type.is_protocol
1394-
):
1395-
# We allow the explicit self-type to be not a supertype of
1396-
# the current class if it is a protocol. For such cases
1397-
# the consistency check will be performed at call sites.
1398-
msg=None
1399-
eliftyp.arg_names[i]in {"self","cls"}:
1400-
msg=message_registry.ERASED_SELF_TYPE_NOT_SUPERTYPE.format(
1401-
erased.str_with_options(self.options),
1402-
ref_type.str_with_options(self.options),
1403-
)
1404-
else:
1405-
msg=message_registry.MISSING_OR_INVALID_SELF_TYPE
1406-
ifmsg:
1407-
self.fail(msg,defn)
1408-
elifisinstance(arg_type,TypeVarType):
1381+
ifisinstance(arg_type,TypeVarType):
14091382
# Refuse covariant parameter type variables
14101383
# TODO: check recursively for inner type variables
14111384
if (
14121385
arg_type.variance==COVARIANT
14131386
anddefn.namenotin ("__init__","__new__","__post_init__")
14141387
andnotis_private(defn.name)# private methods are not inherited
1388+
and (i!=0ornotfound_self)
14151389
):
14161390
ctx:Context=arg_type
14171391
ifctx.line<0:
@@ -1561,6 +1535,69 @@ def check_func_def(
15611535

15621536
self.binder=old_binder
15631537

1538+
defrequire_correct_self_argument(self,func:Type,defn:FuncDef)->bool:
1539+
func=get_proper_type(func)
1540+
ifnotisinstance(func,CallableType):
1541+
returnFalse
1542+
1543+
# Do not report errors for untyped methods in classes nested in untyped funcs.
1544+
ifnot (
1545+
self.options.check_untyped_defs
1546+
orlen(self.dynamic_funcs)<2
1547+
ornotself.dynamic_funcs[-2]
1548+
ornotdefn.is_dynamic()
1549+
):
1550+
returnbool(func.arg_types)
1551+
1552+
withself.scope.push_function(defn):
1553+
# We temporary push the definition to get the self type as
1554+
# visible from *inside* of this function/method.
1555+
ref_type:Type|None=self.scope.active_self_type()
1556+
ifref_typeisNone:
1557+
returnFalse
1558+
1559+
ifnotdefn.has_self_or_cls_argumentor (
1560+
func.arg_kindsandfunc.arg_kinds[0]in [nodes.ARG_STAR,nodes.ARG_STAR2]
1561+
):
1562+
returnFalse
1563+
1564+
ifnotfunc.arg_types:
1565+
self.fail(
1566+
'Method must have at least one argument. Did you forget the "self" argument?',defn
1567+
)
1568+
returnFalse
1569+
1570+
arg_type=func.arg_types[0]
1571+
ifdefn.is_classordefn.name=="__new__":
1572+
ref_type=mypy.types.TypeType.make_normalized(ref_type)
1573+
ifis_same_type(arg_type,ref_type):
1574+
returnTrue
1575+
1576+
# This level of erasure matches the one in checkmember.check_self_arg(),
1577+
# better keep these two checks consistent.
1578+
erased=get_proper_type(erase_typevars(erase_to_bound(arg_type)))
1579+
ifnotis_subtype(ref_type,erased,ignore_type_params=True):
1580+
if (
1581+
isinstance(erased,Instance)
1582+
anderased.type.is_protocol
1583+
orisinstance(erased,TypeType)
1584+
andisinstance(erased.item,Instance)
1585+
anderased.item.type.is_protocol
1586+
):
1587+
# We allow the explicit self-type to be not a supertype of
1588+
# the current class if it is a protocol. For such cases
1589+
# the consistency check will be performed at call sites.
1590+
msg=None
1591+
eliffunc.arg_names[0]in {"self","cls"}:
1592+
msg=message_registry.ERASED_SELF_TYPE_NOT_SUPERTYPE.format(
1593+
erased.str_with_options(self.options),ref_type.str_with_options(self.options)
1594+
)
1595+
else:
1596+
msg=message_registry.MISSING_OR_INVALID_SELF_TYPE
1597+
ifmsg:
1598+
self.fail(msg,defn)
1599+
returnTrue
1600+
15641601
defis_var_redefined_in_outer_context(self,v:Var,after_line:int)->bool:
15651602
"""Can the variable be assigned to at module top level or outer function?
15661603
@@ -3019,6 +3056,8 @@ def visit_block(self, b: Block) -> None:
30193056
break
30203057
else:
30213058
self.accept(s)
3059+
# Clear expression cache after each statement to avoid unlimited growth.
3060+
self.expr_checker.expr_cache.clear()
30223061

30233062
defshould_report_unreachable_issues(self)->bool:
30243063
return (
@@ -4000,7 +4039,7 @@ def check_multi_assignment_from_union(
40004039
fort,lvinzip(transposed,self.flatten_lvalues(lvalues)):
40014040
# We can access _type_maps directly since temporary type maps are
40024041
# only created within expressions.
4003-
t.append(self._type_maps[0].pop(lv,AnyType(TypeOfAny.special_form)))
4042+
t.append(self._type_maps[-1].pop(lv,AnyType(TypeOfAny.special_form)))
40044043
union_types=tuple(make_simplified_union(col)forcolintransposed)
40054044
forexpr,itemsinassignments.items():
40064045
# Bind a union of types collected in 'assignments' to every expression.
@@ -4659,6 +4698,8 @@ def replace_partial_type(
46594698
)->None:
46604699
"""Replace the partial type of var with a non-partial type."""
46614700
var.type=new_type
4701+
# Updating a partial type should invalidate expression caches.
4702+
self.binder.version+=1
46624703
delpartial_types[var]
46634704
ifself.options.allow_redefinition_new:
46644705
# When using --allow-redefinition-new, binder tracks all types of
@@ -5298,6 +5339,7 @@ def visit_decorator_inner(
52985339
)
52995340
ifnon_trivial_decorator:
53005341
self.check_untyped_after_decorator(sig,e.func)
5342+
self.require_correct_self_argument(sig,e.func)
53015343
sig=set_callable_name(sig,e.func)
53025344
e.var.type=sig
53035345
e.var.is_ready=True

‎mypy/checker_shared.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ class TypeCheckerSharedApi(CheckerPluginInterface):
137137
module_refs:set[str]
138138
scope:CheckerScope
139139
checking_missing_await:bool
140+
allow_constructor_cache:bool
140141

141142
@property
142143
@abstractmethod

‎mypy/checkexpr.py‎

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
frommypy.checkmemberimportanalyze_member_access,has_operator
2020
frommypy.checkstrformatimportStringFormatterChecker
2121
frommypy.erasetypeimporterase_type,remove_instance_last_known_values,replace_meta_vars
22-
frommypy.errorsimportErrorWatcher,report_internal_error
22+
frommypy.errorsimportErrorInfo,ErrorWatcher,report_internal_error
2323
frommypy.expandtypeimport (
2424
expand_type,
2525
expand_type_by_instance,
@@ -355,9 +355,15 @@ def __init__(
355355
type_state.infer_polymorphic=notself.chk.options.old_type_inference
356356

357357
self._arg_infer_context_cache=None
358+
self.expr_cache:dict[
359+
tuple[Expression,Type|None],
360+
tuple[int,Type,list[ErrorInfo],dict[Expression,Type]],
361+
]= {}
362+
self.in_lambda_expr=False
358363

359364
defreset(self)->None:
360365
self.resolved_type= {}
366+
self.expr_cache.clear()
361367

362368
defvisit_name_expr(self,e:NameExpr)->Type:
363369
"""Type check a name expression.
@@ -5402,6 +5408,8 @@ def find_typeddict_context(
54025408

54035409
defvisit_lambda_expr(self,e:LambdaExpr)->Type:
54045410
"""Type check lambda expression."""
5411+
old_in_lambda=self.in_lambda_expr
5412+
self.in_lambda_expr=True
54055413
self.chk.check_default_args(e,body_is_trivial=False)
54065414
inferred_type,type_override=self.infer_lambda_type_using_context(e)
54075415
ifnotinferred_type:
@@ -5422,6 +5430,7 @@ def visit_lambda_expr(self, e: LambdaExpr) -> Type:
54225430
ret_type=self.accept(e.expr(),allow_none_return=True)
54235431
fallback=self.named_type("builtins.function")
54245432
self.chk.return_types.pop()
5433+
self.in_lambda_expr=old_in_lambda
54255434
returncallable_type(e,fallback,ret_type)
54265435
else:
54275436
# Type context available.
@@ -5434,6 +5443,7 @@ def visit_lambda_expr(self, e: LambdaExpr) -> Type:
54345443
self.accept(e.expr(),allow_none_return=True)
54355444
ret_type=self.chk.lookup_type(e.expr())
54365445
self.chk.return_types.pop()
5446+
self.in_lambda_expr=old_in_lambda
54375447
returnreplace_callable_return_type(inferred_type,ret_type)
54385448

54395449
definfer_lambda_type_using_context(
@@ -5978,6 +5988,24 @@ def accept(
59785988
typ=self.visit_conditional_expr(node,allow_none_return=True)
59795989
elifallow_none_returnandisinstance(node,AwaitExpr):
59805990
typ=self.visit_await_expr(node,allow_none_return=True)
5991+
# Deeply nested generic calls can deteriorate performance dramatically.
5992+
# Although in most cases caching makes little difference, in worst case
5993+
# it avoids exponential complexity.
5994+
# We cannot use cache inside lambdas, because they skip immediate type
5995+
# context, and use enclosing one, see infer_lambda_type_using_context().
5996+
# TODO: consider using cache for more expression kinds.
5997+
elifisinstance(node, (CallExpr,ListExpr,TupleExpr))andnot (
5998+
self.in_lambda_exprorself.chk.current_node_deferred
5999+
):
6000+
if (node,type_context)inself.expr_cache:
6001+
binder_version,typ,messages,type_map=self.expr_cache[(node,type_context)]
6002+
ifbinder_version==self.chk.binder.version:
6003+
self.chk.store_types(type_map)
6004+
self.msg.add_errors(messages)
6005+
else:
6006+
typ=self.accept_maybe_cache(node,type_context=type_context)
6007+
else:
6008+
typ=self.accept_maybe_cache(node,type_context=type_context)
59816009
else:
59826010
typ=node.accept(self)
59836011
exceptExceptionaserr:
@@ -6008,6 +6036,21 @@ def accept(
60086036
self.in_expression=False
60096037
returnresult
60106038

6039+
defaccept_maybe_cache(self,node:Expression,type_context:Type|None=None)->Type:
6040+
binder_version=self.chk.binder.version
6041+
# Micro-optimization: inline local_type_map() as it is somewhat slow in mypyc.
6042+
type_map:dict[Expression,Type]= {}
6043+
self.chk._type_maps.append(type_map)
6044+
withself.msg.filter_errors(filter_errors=True,save_filtered_errors=True)asmsg:
6045+
typ=node.accept(self)
6046+
messages=msg.filtered_errors()
6047+
ifbinder_version==self.chk.binder.versionandnotself.chk.current_node_deferred:
6048+
self.expr_cache[(node,type_context)]= (binder_version,typ,messages,type_map)
6049+
self.chk._type_maps.pop()
6050+
self.chk.store_types(type_map)
6051+
self.msg.add_errors(messages)
6052+
returntyp
6053+
60116054
defnamed_type(self,name:str)->Instance:
60126055
"""Return an instance type with type given by the name and no type
60136056
arguments. Alias for TypeChecker.named_type.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp