U
    3jg;!                     @   s  d dl Z d dlZd dlZd dlmZmZmZmZmZ d dl	Z	d dl
mZ d dl	mZ e jG dd dZG dd dZeedd	d
Zeeeef dddZee	jjdddZe	jjedddZeedddZeedddZeedddZe	jjdddZdd Zejeed f eeef eeejef  d!d"d#Z e	jjedd$d%Z!ed&d'd(Z"d)d* Z#ejd+d,d-Z$ejd+d.d/Z%dS )0    N)AnyCallableDictIterableTuple)_Cc                   @   s*   e Zd ZU dZeed< eed< dd ZdS )Kernelz$Models a (function, source location)funcsourcec                 O   s   | j ||S N)r	   )selfargskwargs r   8/tmp/pip-unpacked-wheel-ttp2cnii/torch/_library/utils.py__call__   s    zKernel.__call__N)__name__
__module____qualname____doc__r   __annotations__strr   r   r   r   r   r      s   
r   c                   @   s,   e Zd ZdZedddZddddZdS )	RegistrationHandlez2Does something when someone calls .destroy() on it)
on_destroyc                 C   s
   || _ d S r   Z_on_destroy)r   r   r   r   r   __init__   s    zRegistrationHandle.__init__Nreturnc                 C   s   |    d S r   r   )r   r   r   r   destroy   s    zRegistrationHandle.destroy)r   r   r   r   r   r   r   r   r   r   r   r      s   r   )
stacklevelr   c                 C   s&   t t| }|j d|j }|S )zGet a string that represents the caller.

    Example: "/path/to/foo.py:42"

    Use stacklevel=1 to get the caller's source
    Use stacklevel=2 to get the caller's caller's source
    etc.
    :)inspectgetframeinfosys	_getframefilenamelineno)r   framer
   r   r   r   
get_source!   s    	r(   )qualnamer   c                 C   s6   |  d}t|dkr&td|  d|d |d fS )Nz::   zAExpected `qualname` to be of the form "namespace::name", but got zf. The qualname passed to the torch.library APIs must consist of a namespace and a name, e.g. aten::sinr      )splitlen
ValueError)r)   splitsr   r   r   parse_namespace/   s    

r0   c                 C   sH   t | \}}d|kr$|d\}}nd}ttj|}t||}t||S )N.default)r0   r,   getattrtorchops)r)   	namespacenameoverloadnspacketr   r   r   	lookup_op;   s    
r;   )opr   c                 C   s   t | tjjst| jdkS )N>   primsatenprim)
isinstancer4   _ops
OpOverloadAssertionErrorr6   r<   r   r   r   
is_builtinF   s    rE   )schemar   c                 C   sT   dd }t | tjjr|| S ddlm} t | tr>|| } t | |sLt|| S )zCheck if the schema is functional.

    An operator is functional if:
    - it does not mutate any of its inputs
    - it does not return a view on any of its inputs
    - it has at least one return
    c                 S   sD   | j r
dS | j}t|dko,tdd |D }|r6dS | js@dS dS )NFr   c                 s   s"   | ]}|j d k	o|j j V  qd S r   )
alias_infois_write).0rr   r   r   	<genexpr>X   s    z>is_functional_schema.<locals>.is_functional.<locals>.<genexpr>T)
is_mutablereturnsr-   any)rF   ZretsZis_non_mutating_viewr   r   r   is_functionalT   s    z+is_functional_schema.<locals>.is_functionalr   )FunctionSchema)r@   r4   r   rP   Ztorchgen.modelr   parserC   )rF   rO   rP   r   r   r   is_functional_schemaK   s    	

rR   )typr   c              	   C   sh   | t t j kpf| t t t j kpf| t t t j kpf| t t t t j kS r   )r   ZListType
TensorTypegetOptionalTyperS   r   r   r   is_tensorlist_like_typen   s    rX   c                 C   s"   | t j kp | t t j kS r   )r   rT   rU   rV   rW   r   r   r   is_tensor_like_typex   s    rY   rD   c                 C   s   | j dkrdS | j}t|jdks&dS |jd jdkr:dS |jd jj}t|dkrXdS tt|}t|jdk rvdS |jd }|jdkrdS |jj	sdS |jj}t|dkrdS |tt|krdS |jdd D ]}|jdk	r dS qdS )aN  Check if an op is an inplace aten op, i.e. it mutates and returns the first arg.

    TODO: torchgen/model.py's FunctionSchema.parse is the source of truth for this,
    but not all PyTorch builds have torchgen (due to the yaml dependency being weird).
    Figure this out.

    Example: add_(Tensor(a!) x, Tensor y) -> Tensor(a)
    r>   Fr+   r   NT)
r6   _schemar-   rM   rG   Z	after_setnextiter	argumentsrH   )r<   rF   Z	alias_setlocZ	first_argargr   r   r   mutates_and_returns_first_arg|   s6    	



r`   c                 C   s   g }i }t t| jD ]f}| j| }|jrT|j|krF||j ||j< q||j||j< q|t|k rp|||  q||j qt||fS r   )ranger-   r]   
kwarg_onlyr7   default_valueappendtuple)rF   r   r   new_argsZ
new_kwargsiinfor   r   r   fill_defaults   s    

ri   .)rF   r   r   r   c                 c   s~   t | jt |t | ksttt | jD ]L}| j| }|jr\|j|kr,|||j fV  q,|t |krjq,||| fV  q,dS )zzips schema.arguments and (args, kwargs) together.

    Assumes that (args, kwargs) were the inputs to some torch._ops.OpOverload:
    that is, kwargs must be keyword-only arguments and default values may be omitted.
    N)r-   r]   rC   ra   rb   r7   )rF   r   r   rg   rh   r   r   r   
zip_schema   s    

rj   c                 C   sD   t | tjjstt| rdS | j}|js.dS t|j	dkr@dS dS )NFr   T)
r@   r4   rA   rB   rC   rE   rZ   rL   r-   rM   )r<   rF   r   r   r   can_generate_trivial_fake_impl   s    rk   r   c                   C   s   t tddS )zIf an op was defined in C++ and extended from Python using the
    torch.library APIs, returns if we require that there have been a
    m.set_python_module("mylib.ops") call from C++ that associates
    the C++ op with a python module.
    ZREQUIRES_SET_PYTHON_MODULET)r3   _utils_internalr   r   r   r   requires_set_python_module   s    rm   c                 O   s~   t | tjjjstg }tjj|| f\}}|D ]6}t |tj	r6tj
|tj
jjr6|t| q6| ||||S r   )r@   r4   utilsZ_python_dispatchZTorchDispatchModerC   Z_pytreeZtree_flattenvaluesZTensorr   Z_dispatch_keysZhasZDispatchKeyPythonrd   typeZ__torch_dispatch__)Z	curr_modeZop_overloadr   r   Zoverload_typesZargs_flattened_ar   r   r   handle_dispatch_mode   s    rt   rF   c                 C   s   t dd | jD S )Nc                 s   s   | ]}|j V  qd S r   )rb   )rI   rs   r   r   r   rK      s     z&has_kwarg_only_args.<locals>.<genexpr>)rN   r]   ru   r   r   r   has_kwarg_only_args   s    rv   c                 C   s2   | j D ]&}t|js t|js q|js(q dS dS )NTF)r]   rY   rq   rX   rb   )rF   rs   r   r   r   has_kwarg_only_tensors   s    
rw   )&Zdataclassesr!   r#   typingr   r   r   r   r   r4   Ztorch._utils_internalrl   r   Z	dataclassr   r   intr   r(   r0   rA   rB   r;   boolrE   rR   rX   rY   r`   ri   rP   ZArgumentrj   rk   rm   rt   rv   rw   r   r   r   r   <module>   s8   

#
& 
 
	