U
    dO                     @   s   d dl Z d dlZd dlZd dlZd dlZd dlmZ d dlmZm	Z	m
Z
mZmZmZ d dlmZ d dlmZ d dlmZ d dlZG dd de jZG d	d
 d
eZe	ejje
f e	ejje
f dddZdS )    N)FunctionType)castUnionCallableDictOptionalAny)Tracer)Graph)normalize_source_linesc                   @   s.   e Zd ZdZedddZdd Zdd Zd	S )
AST_Rewriterax  
    Take a FunctionType object representing a `forward` method, then
    perform an AST rewrite to swap out nodes that are not symbolically
    traceable with a callsite to the FX alternative.

    To support swapping out an AST node, define a new `visit` method on
    that node. For more details, see:
    https://docs.python.org/3/library/ast.html#ast.NodeTransformer
    fnc                 C   s   t |\}}t|}d|}t|}t|}t| 	|}t
|dd}t|j}	t|	 }
t||	 tt|	 |
 }t|dkst|	|d  }dd }|||jdS )N exec   r   c                 S   s8   t | j|| j| j| jd}t|| }t| j|_|S )z?Based on https://stackoverflow.com/a/13503277/2988730 (@unutbu))nameZargdefsclosure)	r   __code____name____defaults____closure__	functoolsupdate_wrappercopy__kwdefaults__)fglobalsg r   B/tmp/pip-unpacked-wheel-ua33x9lu/torch/fx/experimental/rewriter.pychange_func_globals.   s    z1AST_Rewriter.rewrite.<locals>.change_func_globals)r   )inspectgetsourcelinesr   jointextwrapdedentastparseZfix_missing_locationsvisitcompiler   __globals__setkeysr   listlenAssertionError)selfr   sourcelines_sourceZnormalized_strZ
source_astZdest_astcodeZglobals_dictZkeys_beforeZnew_keysZfn_compiledr!   r   r   r    rewrite   s    



zAST_Rewriter.rewritec                 C   sr   t jddd}t|t jst|j}t|t js4t|jr@|jnt jddd}|j	|g|_
t j|d}t ||S )z
        Swap out the Assert node (Python's `assert`) with a callsite to the
        symbolically-traceable torch._assert function
        ztorch._assert()eval)moder   N)valuekind)r9   )r'   r(   
isinstanceZ
Expressionr0   bodyCallmsgConstanttestargsZExprZcopy_location)r1   nodenZ	call_noder>   Zexpr_wrapperr   r   r    visit_Assert?   s    zAST_Rewriter.visit_Assertc                 C   s4   t j|jgt jt jdt  d|j|jgg ddS )a  
        Swap out Python's AnnAssign with an Assign node where the annotation function is called.
        Example:
             Original:
             y: Tensor_Type(1,2,3, Dyn) = f2(x)
            Output:
             y = annotate(f2(x),Tensor_Type((1,2,3,Dyn)))
        Zannotate)idctx)funcrA   keywords)targetsr9   )r'   ZAssigntargetr=   NameLoadr9   
annotation)r1   rB   r   r   r    visit_AnnAssignS   s
    	
 zAST_Rewriter.visit_AnnAssignN)r   
__module____qualname____doc__r   r6   rD   rN   r   r   r   r    r      s   
'r   c                       s@   e Zd Zdeejjef ee	e
ef  ed fddZ  ZS )RewritingTracerN)rootconcrete_argsreturnc                    s   t  t||S N)supertrace_rewrite)r1   rS   rT   	__class__r   r    rX   b   s    zRewritingTracer.trace)N)r   rO   rP   r   torchnnModuler   r   r   strr   r
   rX   __classcell__r   r   rZ   r    rR   a   s   rR   )r   rU   c                    sB   t | tjjr,tjjd fdd  | S t tt| S d S )N)mc                    s6   G  fdddt jj}t tt| j|_|| S )Nc                       s   e Zd Z fddZ  ZS )z9_rewrite.<locals>.rewrite_module.<locals>.RewrittenModulec                    sV   t    |j D ]<\}}t|tjjr@t|| j|< qt|| j|< qd S rV   )	rW   __init____dict__itemsr;   r\   r]   r^   r   )r1   origkv)r[   rewrite_moduler   r    rb   m   s
    
zB_rewrite.<locals>.rewrite_module.<locals>.RewrittenModule.__init__)r   rO   rP   rb   r`   r   rh   rZ   r    RewrittenModulel   s   rj   )r\   r]   r^   r   r6   r   r   Zforward)ra   rj   ri   r   r    rh   k   s    z _rewrite.<locals>.rewrite_module)r;   r\   r]   r^   r   r6   r   r   r   r   ri   r    rY   f   s    rY   )r'   r"   r%   r   r   typesr   typingr   r   r   r   r   r   Ztorch.fx._symbolic_tracer	   Ztorch.fx.graphr
   Ztorch._sourcesr   r\   NodeTransformerr   rR   r]   r^   rY   r   r   r   r    <module>   s    T