NL i;<UdZddlmZddlmZddlmZmZmZm Z m Z m Z ddl m Z ddlmZddlmZmZmZmZmZmZmZmZmZmZmZmZmZddlmZd Z d e!d <dd Z"dd Z# ddZ$ ddZ% d dZ&e'e(e)e(e)fZ*d!dZ+d!dZ,Gdde e)Z- d"dZ.Gdde e)Z/ d#dZ0ddZ1ddZ2y)$a_ Always defined attribute analysis. An always defined attribute has some statements in __init__ or the class body that cause the attribute to be always initialized when an instance is constructed. It must also not be possible to read the attribute before initialization, and it can't be deletable. We can assume that the value is always defined when reading an always defined attribute. Otherwise we'll need to raise AttributeError if the value is undefined (i.e. has the error value). We use data flow analysis to figure out attributes that are always defined. Example: class C: def __init__(self) -> None: self.x = 0 if func(): self.y = 1 else: self.y = 2 self.z = 3 In this example, the attributes 'x' and 'y' are always defined, but 'z' is not. The analysis assumes that we know that there won't be any subclasses. The analysis also works if there is a known, closed set of subclasses. An attribute defined in a base class can only be always defined if it's also always defined in all subclasses. As soon as __init__ contains an op that can 'leak' self to another function, we will stop inferring always defined attributes, since the analysis is mostly intra-procedural and only looks at __init__ methods. The called code could read an uninitialized attribute. Example: class C: def __init__(self) -> None: self.x = self.foo() def foo(self) -> int: ... Now we won't infer 'x' as always defined, since 'foo' might read 'x' before initialization. As an exception to the above limitation, we perform inter-procedural analysis of super().__init__ calls, since these are very common. Our analysis is somewhat optimistic. We assume that nobody calls a method of a partially uninitialized object through gc.get_objects(), in particular. Code like this could potentially cause a segfault with a null pointer dereference. This seems very unlikely to be an issue in practice, however. Accessing an attribute via getattr always checks for undefined attributes and thus works if the object is partially uninitialized. This can be used as a workaround if somebody ever needs to inspect partially uninitialized objects via gc.get_objects(). The analysis runs after IR building as a separate pass. Since we only run this on __init__ methods, this analysis pass will be fairly quick. ) annotations)Final)CFGMAYBE_ANALYSISAnalysisResultBaseAnalysisVisitorget_cfg run_analysis)analyze_self_leaks)ClassIR) Assign AssignMulti BasicBlockBranchCall ControlOpGetAttrRegister RegisterOpReturnSetAttrSetMem Unreachable) RInstanceFrdump_always_definedct}|D]}t||t}|D]}t||t}|D]}t||y)akFind always defined attributes all classes of a compilation unit. Also tag attribute initialization ops to not decref the previous value (as this would read a NULL pointer and segfault). Update the _always_initialized_attrs, _sometimes_initialized_attrs and init_self_leak attributes in ClassIR instances. This is the main entry point. N)set%analyze_always_defined_attrs_in_class,update_always_defined_attrs_using_subclassesdetect_undefined_bitmap) class_irsseencls `/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/mypyc/analysis/attrdefined.pyanalyze_always_defined_attrsr%dsjD8-b$78 5D?4R>? 5D*D)*c>||vry|j||jsQ|jsE|js9|j-|j !|j s|jdry|jddD]}t|||jd}|?|jj|_ |jj|_y|jd}t!|j"}t%|j"||}t'|j"||j|}t)}|jD]}|j+|j,t/|j"|||jz |} t1|j"|||| |} | D chc]} |j3| r| } } | |_ t4rt7|j8t;| t=|j"||||_t?|j"|||d} |j"D]E} tA| jBD]+\}}|jD| |fstG|tHr)d} EG| |_%ycc} w)N__new____init__r)initial_undefinedcfgFT)&addis_traitinherits_pythonallow_interpreted_subclasses builtin_basechildrenis_serializable has_methodmror get_methodattrs_with_defaultscopy_always_initialized_attrs_sometimes_initialized_attrsarg_regsr blocksr #analyze_maybe_defined_attrs_in_initrupdate attributes%analyze_maybe_undefined_attrs_in_initfind_always_defined_attributes is_deletablerprintnamesorted!find_sometimes_defined_attributesmark_attr_initialization_ops enumerateopsafter isinstancerinit_self_leak)r#r"basemself_regr,dirty maybe_defined all_attrsmaybe_undefinedalways_defineda any_dirtybiops r$rrsY TzHHRL   * * ?? & ;;     == # qr :-dD9: j!Ay')'='='B'B'D$*,*@*@*E*E*G'zz!}H !(( C qxx3 7E7 (B22CM%I*)*; (i":P:P.PVYO4 (I}ouN"0JArq7IaJNJ#1B  bggvn-.&G (M5'B#!8]EJI XXquu% EAr{{1a4 B)?   "B%Ks >JJc|j}|D]}t|jD]\}} t| trF| j |ur8| j |j||fvr|j| j t| trc| j |urU| j |j||fvr8| j |j||fvr|j| j |j||fr:|j||fs&||j||f|j||fz z}4t| ts-| jD]L} |j||fr|j| dfs'||j| df|j| dfz z}N|S)zFind attributes that are always initialized in some basic blocks. The analysis results are expected to be up-to-date for the blocks. Return a set of always defined attributes. r) r8rHrIrKrobjattrbeforediscardrrJrtargets) r<rOrRrQrSrPattrsblockrXrYtargets r$rArAs NN Euyy) EAr"g&266X+=77o44UAX>>MM"''* "g&266X+=GG55eQh??=#7#7q#AAMM"''*{{5!8$||E1H-!%++E1H58M8MeUVh8WWE"i( jjlF ;;uax0U\\&!)5L %)// :_=R=RSY[\S\=]]!3 @ Lr&ct}|D]}t|jD]\}}|j||fr'|j||fs||j||fz}Vt |t sO|jD]:}|j||fr|j|dfs'||j|dfz}<|S)zDFind attributes that are sometimes initialized in some basic blocks.r)rrHrIrJr]rKrr_) r<rOrQrPr`rarXrYrbs r$rFrFseE Guyy) GEAr{{5!8$||E1H-!M$7$7q$AAE"i( jjlGF ;;uax0U\\&!)5L % (;(;FAI(F FG G G Lr&c|D]}t|jD]g\}}t|ts|j|us&|j }||j ||fvsF|j||frX|jiy)zTag all SetAttr ops in the basic blocks that initialize attributes. Initialization ops assume that the previous attribute value is the error value, so there's no need to decref or check for definedness. N) rHrIrKrr[r\r]rJmark_as_initializer)r<rOrQrPrarXrYr\s r$rGrGs-uyy) -EAr"g&266X+=ww}33E1H==ekkRWYZRZF[**,  --r&c,|jjjdj}t |t sJ||j }|jDchc]'}|jD]}|j|s|)c}}Scc}}w)zLCalculate attributes that are always initialized by a super().__init__ call.r) fnsigargstyperKrclass_irr5r?is_always_defined)rY self_typer#rMrUs r$#attributes_initialized_by_init_callrnst q!&&I i +6Y6 +   B&& W$$// WQT=S=STU=VA WA WW Ws %BBc|jjjdj}t |t sJ||j }t||jzS)zHCalculate attributes that may be initialized by a super().__init__ call.r) rgrhrirjrKrrkrnr:)rYrmr#s r$)attributes_maybe_initialized_by_init_callrp&sT q!&&I i +6Y6 +   B .r 2R5T5T TTr&cPeZdZdZd dZd dZd dZddZddZddZ ddZ dd Z y )AttributeMaybeDefinedVisitorzFind attributes that may have been defined via some code path. Consider initializations in class body and assignments to 'self.x' and calls to base class '__init__'. c||_yNrOselfrOs r$r*z%AttributeMaybeDefinedVisitor.__init__5   r&c*ttfSrtrrwrYs r$ visit_branchz)AttributeMaybeDefinedVisitor.visit_branch8uce|r&c*ttfSrtrzr{s r$ visit_returnz)AttributeMaybeDefinedVisitor.visit_return;r}r&c*ttfSrtrzr{s r$visit_unreachablez.AttributeMaybeDefinedVisitor.visit_unreachable>r}r&cPt|tr/|j|jur|jht fSt|t rD|jjr.|jjdk(rt|t fSt t fSNr*) rKrr[rOr\rrrg class_namerDrpr{s r$visit_register_opz.AttributeMaybeDefinedVisitor.visit_register_opAss b' "rvv'>GG9ce# # b$ BEE$4$4z9Qt||t||dtSNF)r<r, gen_and_killinitialbackwardkind)r rrr)r<rOr7r,s r$r=r=Rs(  1(;#   r&cPeZdZdZd dZd dZd dZddZddZddZ ddZ dd Z y )AttributeMaybeUndefinedVisitorzFind attributes that may be undefined via some code path. Consider initializations in class body, assignments to 'self.x' and calls to base class '__init__'. c||_yrtrurvs r$r*z'AttributeMaybeUndefinedVisitor.__init__frxr&c*ttfSrtrzr{s r$r|z+AttributeMaybeUndefinedVisitor.visit_branchir}r&c*ttfSrtrzr{s r$rz+AttributeMaybeUndefinedVisitor.visit_returnlr}r&c*ttfSrtrzr{s r$rz0AttributeMaybeUndefinedVisitor.visit_unreachableor}r&cPt|tr/|j|jurt |j hfSt|t rD|jjr.|jjdk(rt t|fSt t fSr) rKrr[rOrr\rrgrrDrnr{s r$rz0AttributeMaybeUndefinedVisitor.visit_register_oprst b' "rvv'>5277)# # b$ BEE$4$4z9Q5=bAA Auce|r&c*ttfSrtrzr{s r$rz+AttributeMaybeUndefinedVisitor.visit_assignyr}r&c*ttfSrtrzr{s r$rz1AttributeMaybeUndefinedVisitor.visit_assign_multi|r}r&c*ttfSrtrzr{s r$rz,AttributeMaybeUndefinedVisitor.visit_set_memr}r&Nrrrrrrrrrrr&r$rr_rr&rc>t||t||dtSr)r rr)r<rOr+r,s r$r@r@s(  3H=!   r&c$||vry|jyt}|jD]?}|jD].}t||||jvs|j |0A|xj|zc_|j |y)zJRemove attributes not defined in all subclasses from always defined attrs.N)r2rr9rr-)r#r"removedr\childs r$rrs Tz {{eG,,"[[ "E 8 E5::: D! ""   G+ HHRLr&c|jry||vry|j||jddD]}t||t |jdkDr2|j j |jdj |jjD]?\}}|js|j|r%|j j|A|jddD]z}|js|jjD]N\}}|js|j|r%||j vs4|j j|P|y)Nr)) r.r-base_mror len bitmap_attrsextendr?items error_overlaprlappendr5)r#r"rMnts r$r r s3 {{ TzHHRL AB,d+, 2;;! r{{1~::; ##%&1 ??2#7#7#: OO " "1 %&qr . ==--/ .1??2+?+?+BqPRP_P_G_OO**1- ..r&N)r!z list[ClassIR]rr)r#r r"z set[ClassIR]rr)r<list[BasicBlock]rOrrRset[str]rQAnalysisResult[str]rSrrPAnalysisResult[None]rr) r<rrOrrQrrPrrr) r<rrOrrQrrPrrr)rYrrr) r<rrOrr7rr,rrr) r<rrOrr+rr,rrr)3r __future__rtypingrmypyc.analysis.dataflowrrrrr r mypyc.analysis.selfleaksr mypyc.ir.class_irr mypyc.ir.opsr rrrrrrrrrrrrmypyc.ir.rtypesrr__annotations__r%rrArFrGtuplerstr GenAndKillrnrprrr=rr@rr rr&r$rs=~#8%&#U"*8="@/ ///' / ) / //d '   ,- --'- -  -&3s8SX% & XU!#6s#;!H   (0 GO VY  !%8%=!H   (0 EM TW  ".r&