1"""
2Define typing templates
3"""
4
5from abc import ABC, abstractmethod
6import functools
7import sys
8import inspect
9import os.path
10from collections import namedtuple
11from collections.abc import Sequence
12from types import MethodType, FunctionType
13
14import numba
15from numba.core import types, utils
16from numba.core.errors import TypingError, InternalError
17from numba.core.cpu_options import InlineOptions
18
19# info store for inliner callback functions e.g. cost model
20_inline_info = namedtuple('inline_info',
21                          'func_ir typemap calltypes signature')
22
23
24class Signature(object):
25    """
26    The signature of a function call or operation, i.e. its argument types
27    and return type.
28    """
29
30    # XXX Perhaps the signature should be a BoundArguments, instead
31    # of separate args and pysig...
32    __slots__ = '_return_type', '_args', '_recvr', '_pysig'
33
34    def __init__(self, return_type, args, recvr, pysig=None):
35        if isinstance(args, list):
36            args = tuple(args)
37        self._return_type = return_type
38        self._args = args
39        self._recvr = recvr
40        self._pysig = pysig
41
42    @property
43    def return_type(self):
44        return self._return_type
45
46    @property
47    def args(self):
48        return self._args
49
50    @property
51    def recvr(self):
52        return self._recvr
53
54    @property
55    def pysig(self):
56        return self._pysig
57
58    def replace(self, **kwargs):
59        """Copy and replace the given attributes provided as keyword arguments.
60        Returns an updated copy.
61        """
62        curstate = dict(return_type=self.return_type,
63                        args=self.args,
64                        recvr=self.recvr,
65                        pysig=self.pysig)
66        curstate.update(kwargs)
67        return Signature(**curstate)
68
69    def __getstate__(self):
70        """
71        Needed because of __slots__.
72        """
73        return self._return_type, self._args, self._recvr, self._pysig
74
75    def __setstate__(self, state):
76        """
77        Needed because of __slots__.
78        """
79        self._return_type, self._args, self._recvr, self._pysig = state
80
81    def __hash__(self):
82        return hash((self.args, self.return_type))
83
84    def __eq__(self, other):
85        if isinstance(other, Signature):
86            return (self.args == other.args and
87                    self.return_type == other.return_type and
88                    self.recvr == other.recvr and
89                    self.pysig == other.pysig)
90
91    def __ne__(self, other):
92        return not (self == other)
93
94    def __repr__(self):
95        return "%s -> %s" % (self.args, self.return_type)
96
97    @property
98    def is_method(self):
99        """
100        Whether this signature represents a bound method or a regular
101        function.
102        """
103        return self.recvr is not None
104
105    def as_method(self):
106        """
107        Convert this signature to a bound method signature.
108        """
109        if self.recvr is not None:
110            return self
111        sig = signature(self.return_type, *self.args[1:],
112                        recvr=self.args[0])
113
114        # Adjust the python signature
115        params = list(self.pysig.parameters.values())[1:]
116        sig = sig.replace(
117            pysig=utils.pySignature(
118                parameters=params,
119                return_annotation=self.pysig.return_annotation,
120            ),
121        )
122        return sig
123
124    def as_function(self):
125        """
126        Convert this signature to a regular function signature.
127        """
128        if self.recvr is None:
129            return self
130        sig = signature(self.return_type, *((self.recvr,) + self.args))
131        return sig
132
133    def as_type(self):
134        """
135        Convert this signature to a first-class function type.
136        """
137        return types.FunctionType(self)
138
139    def __unliteral__(self):
140        return signature(types.unliteral(self.return_type),
141                         *map(types.unliteral, self.args))
142
143    def dump(self, tab=''):
144        c = self.as_type()._code
145        print(f'{tab}DUMP {type(self).__name__} [type code: {c}]')
146        print(f'{tab}  Argument types:')
147        for a in self.args:
148            a.dump(tab=tab + '  | ')
149        print(f'{tab}  Return type:')
150        self.return_type.dump(tab=tab + '  | ')
151        print(f'{tab}END DUMP')
152
153    def is_precise(self):
154        for atype in self.args:
155            if not atype.is_precise():
156                return False
157        return self.return_type.is_precise()
158
159
160def make_concrete_template(name, key, signatures):
161    baseclasses = (ConcreteTemplate,)
162    gvars = dict(key=key, cases=list(signatures))
163    return type(name, baseclasses, gvars)
164
165
166def make_callable_template(key, typer, recvr=None):
167    """
168    Create a callable template with the given key and typer function.
169    """
170    def generic(self):
171        return typer
172
173    name = "%s_CallableTemplate" % (key,)
174    bases = (CallableTemplate,)
175    class_dict = dict(key=key, generic=generic, recvr=recvr)
176    return type(name, bases, class_dict)
177
178
179def signature(return_type, *args, **kws):
180    recvr = kws.pop('recvr', None)
181    assert not kws
182    return Signature(return_type, args, recvr=recvr)
183
184
185def fold_arguments(pysig, args, kws, normal_handler, default_handler,
186                   stararg_handler):
187    """
188    Given the signature *pysig*, explicit *args* and *kws*, resolve
189    omitted arguments and keyword arguments. A tuple of positional
190    arguments is returned.
191    Various handlers allow to process arguments:
192    - normal_handler(index, param, value) is called for normal arguments
193    - default_handler(index, param, default) is called for omitted arguments
194    - stararg_handler(index, param, values) is called for a "*args" argument
195    """
196    if isinstance(kws, Sequence):
197        # Normalize dict kws
198        kws = dict(kws)
199
200    # deal with kwonly args
201    params = pysig.parameters
202    kwonly = []
203    for name, p in params.items():
204        if p.kind == p.KEYWORD_ONLY:
205            kwonly.append(name)
206
207    if kwonly:
208        bind_args = args[:-len(kwonly)]
209    else:
210        bind_args = args
211    bind_kws = kws.copy()
212    if kwonly:
213        for idx, n in enumerate(kwonly):
214            bind_kws[n] = args[len(kwonly) + idx]
215
216    # now bind
217    ba = pysig.bind(*bind_args, **bind_kws)
218    for i, param in enumerate(pysig.parameters.values()):
219        name = param.name
220        default = param.default
221        if param.kind == param.VAR_POSITIONAL:
222            # stararg may be omitted, in which case its "default" value
223            # is simply the empty tuple
224            if name in ba.arguments:
225                argval = ba.arguments[name]
226                # NOTE: avoid wrapping the tuple type for stararg in another
227                #       tuple.
228                if (len(argval) == 1 and
229                        isinstance(argval[0], (types.StarArgTuple,
230                                               types.StarArgUniTuple))):
231                    argval = tuple(argval[0])
232            else:
233                argval = ()
234            out = stararg_handler(i, param, argval)
235
236            ba.arguments[name] = out
237        elif name in ba.arguments:
238            # Non-stararg, present
239            ba.arguments[name] = normal_handler(i, param, ba.arguments[name])
240        else:
241            # Non-stararg, omitted
242            assert default is not param.empty
243            ba.arguments[name] = default_handler(i, param, default)
244    # Collect args in the right order
245    args = tuple(ba.arguments[param.name]
246                 for param in pysig.parameters.values())
247    return args
248
249
250class FunctionTemplate(ABC):
251    # Set to true to disable unsafe cast.
252    # subclass overide-able
253    unsafe_casting = True
254    # Set to true to require exact match without casting.
255    # subclass overide-able
256    exact_match_required = False
257    # Set to true to prefer literal arguments.
258    # Useful for definitions that specialize on literal but also support
259    # non-literals.
260    # subclass overide-able
261    prefer_literal = False
262
263    def __init__(self, context):
264        self.context = context
265
266    def _select(self, cases, args, kws):
267        options = {
268            'unsafe_casting': self.unsafe_casting,
269            'exact_match_required': self.exact_match_required,
270        }
271        selected = self.context.resolve_overload(self.key, cases, args, kws,
272                                                 **options)
273        return selected
274
275    def get_impl_key(self, sig):
276        """
277        Return the key for looking up the implementation for the given
278        signature on the target context.
279        """
280        # Lookup the key on the class, to avoid binding it with `self`.
281        key = type(self).key
282        # On Python 2, we must also take care about unbound methods
283        if isinstance(key, MethodType):
284            assert key.im_self is None
285            key = key.im_func
286        return key
287
288    @classmethod
289    def get_source_code_info(cls, impl):
290        """
291        Gets the source information about function impl.
292        Returns:
293
294        code - str: source code as a string
295        firstlineno - int: the first line number of the function impl
296        path - str: the path to file containing impl
297
298        if any of the above are not available something generic is returned
299        """
300        try:
301            code, firstlineno = inspect.getsourcelines(impl)
302        except OSError: # missing source, probably a string
303            code = "None available (built from string?)"
304            firstlineno = 0
305        path = inspect.getsourcefile(impl)
306        if path is None:
307            path = "<unknown> (built from string?)"
308        return code, firstlineno, path
309
310    @abstractmethod
311    def get_template_info(self):
312        """
313        Returns a dictionary with information specific to the template that will
314        govern how error messages are displayed to users. The dictionary must
315        be of the form:
316        info = {
317            'kind': "unknown", # str: The kind of template, e.g. "Overload"
318            'name': "unknown", # str: The name of the source function
319            'sig': "unknown",  # str: The signature(s) of the source function
320            'filename': "unknown", # str: The filename of the source function
321            'lines': ("start", "end"), # tuple(int, int): The start and
322                                         end line of the source function.
323            'docstring': "unknown" # str: The docstring of the source function
324        }
325        """
326        pass
327
328    def __str__(self):
329        info = self.get_template_info()
330        srcinfo = f"{info['filename']}:{info['lines'][0]}"
331        return f"<{self.__class__.__name__} {srcinfo}>"
332
333    __repr__ = __str__
334
335
336class AbstractTemplate(FunctionTemplate):
337    """
338    Defines method ``generic(self, args, kws)`` which compute a possible
339    signature base on input types.  The signature does not have to match the
340    input types. It is compared against the input types afterwards.
341    """
342
343    def apply(self, args, kws):
344        generic = getattr(self, "generic")
345        sig = generic(args, kws)
346        # Enforce that *generic()* must return None or Signature
347        if sig is not None:
348            if not isinstance(sig, Signature):
349                raise AssertionError(
350                    "generic() must return a Signature or None. "
351                    "{} returned {}".format(generic, type(sig)),
352                )
353
354        # Unpack optional type if no matching signature
355        if not sig and any(isinstance(x, types.Optional) for x in args):
356            def unpack_opt(x):
357                if isinstance(x, types.Optional):
358                    return x.type
359                else:
360                    return x
361
362            args = list(map(unpack_opt, args))
363            assert not kws  # Not supported yet
364            sig = generic(args, kws)
365
366        return sig
367
368    def get_template_info(self):
369        impl = getattr(self, "generic")
370        basepath = os.path.dirname(os.path.dirname(numba.__file__))
371
372        code, firstlineno, path = self.get_source_code_info(impl)
373        sig = str(utils.pysignature(impl))
374        info = {
375            'kind': "overload",
376            'name': getattr(impl, '__qualname__', impl.__name__),
377            'sig': sig,
378            'filename': utils.safe_relpath(path, start=basepath),
379            'lines': (firstlineno, firstlineno + len(code) - 1),
380            'docstring': impl.__doc__
381        }
382        return info
383
384
385class CallableTemplate(FunctionTemplate):
386    """
387    Base class for a template defining a ``generic(self)`` method
388    returning a callable to be called with the actual ``*args`` and
389    ``**kwargs`` representing the call signature.  The callable has
390    to return a return type, a full signature, or None.  The signature
391    does not have to match the input types. It is compared against the
392    input types afterwards.
393    """
394    recvr = None
395
396    def apply(self, args, kws):
397        generic = getattr(self, "generic")
398        typer = generic()
399        sig = typer(*args, **kws)
400
401        # Unpack optional type if no matching signature
402        if sig is None:
403            if any(isinstance(x, types.Optional) for x in args):
404                def unpack_opt(x):
405                    if isinstance(x, types.Optional):
406                        return x.type
407                    else:
408                        return x
409
410                args = list(map(unpack_opt, args))
411                sig = typer(*args, **kws)
412            if sig is None:
413                return
414
415        # Get the pysig
416        try:
417            pysig = typer.pysig
418        except AttributeError:
419            pysig = utils.pysignature(typer)
420
421        # Fold any keyword arguments
422        bound = pysig.bind(*args, **kws)
423        if bound.kwargs:
424            raise TypingError("unsupported call signature")
425        if not isinstance(sig, Signature):
426            # If not a signature, `sig` is assumed to be the return type
427            if not isinstance(sig, types.Type):
428                raise TypeError("invalid return type for callable template: "
429                                "got %r" % (sig,))
430            sig = signature(sig, *bound.args)
431        if self.recvr is not None:
432            sig = sig.replace(recvr=self.recvr)
433        # Hack any omitted parameters out of the typer's pysig,
434        # as lowering expects an exact match between formal signature
435        # and actual args.
436        if len(bound.args) < len(pysig.parameters):
437            parameters = list(pysig.parameters.values())[:len(bound.args)]
438            pysig = pysig.replace(parameters=parameters)
439        sig = sig.replace(pysig=pysig)
440        cases = [sig]
441        return self._select(cases, bound.args, bound.kwargs)
442
443    def get_template_info(self):
444        impl = getattr(self, "generic")
445        basepath = os.path.dirname(os.path.dirname(numba.__file__))
446        code, firstlineno, path = self.get_source_code_info(impl)
447        sig = str(utils.pysignature(impl))
448        info = {
449            'kind': "overload",
450            'name': getattr(self.key, '__name__',
451                            getattr(impl, '__qualname__', impl.__name__),),
452            'sig': sig,
453            'filename': utils.safe_relpath(path, start=basepath),
454            'lines': (firstlineno, firstlineno + len(code) - 1),
455            'docstring': impl.__doc__
456        }
457        return info
458
459
460class ConcreteTemplate(FunctionTemplate):
461    """
462    Defines attributes "cases" as a list of signature to match against the
463    given input types.
464    """
465
466    def apply(self, args, kws):
467        cases = getattr(self, 'cases')
468        return self._select(cases, args, kws)
469
470    def get_template_info(self):
471        import operator
472        name = getattr(self.key, '__name__', "unknown")
473        op_func = getattr(operator, name, None)
474
475        kind = "Type restricted function"
476        if op_func is not None:
477            if self.key is op_func:
478                kind = "operator overload"
479        info = {
480            'kind': kind,
481            'name': name,
482            'sig': "unknown",
483            'filename': "unknown",
484            'lines': ("unknown", "unknown"),
485            'docstring': "unknown"
486        }
487        return info
488
489
490class _EmptyImplementationEntry(InternalError):
491    def __init__(self, reason):
492        super(_EmptyImplementationEntry, self).__init__(
493            "_EmptyImplementationEntry({!r})".format(reason),
494        )
495
496
497class _OverloadFunctionTemplate(AbstractTemplate):
498    """
499    A base class of templates for overload functions.
500    """
501
502    def _validate_sigs(self, typing_func, impl_func):
503        # check that the impl func and the typing func have the same signature!
504        typing_sig = utils.pysignature(typing_func)
505        impl_sig = utils.pysignature(impl_func)
506        # the typing signature is considered golden and must be adhered to by
507        # the implementation...
508        # Things that are valid:
509        # 1. args match exactly
510        # 2. kwargs match exactly in name and default value
511        # 3. Use of *args in the same location by the same name in both typing
512        #    and implementation signature
513        # 4. Use of *args in the implementation signature to consume any number
514        #    of arguments in the typing signature.
515        # Things that are invalid:
516        # 5. Use of *args in the typing signature that is not replicated
517        #    in the implementing signature
518        # 6. Use of **kwargs
519
520        def get_args_kwargs(sig):
521            kws = []
522            args = []
523            pos_arg = None
524            for x in sig.parameters.values():
525                if x.default == utils.pyParameter.empty:
526                    args.append(x)
527                    if x.kind == utils.pyParameter.VAR_POSITIONAL:
528                        pos_arg = x
529                    elif x.kind == utils.pyParameter.VAR_KEYWORD:
530                        msg = ("The use of VAR_KEYWORD (e.g. **kwargs) is "
531                               "unsupported. (offending argument name is '%s')")
532                        raise InternalError(msg % x)
533                else:
534                    kws.append(x)
535            return args, kws, pos_arg
536
537        ty_args, ty_kws, ty_pos = get_args_kwargs(typing_sig)
538        im_args, im_kws, im_pos = get_args_kwargs(impl_sig)
539
540        sig_fmt = ("Typing signature:         %s\n"
541                   "Implementation signature: %s")
542        sig_str = sig_fmt % (typing_sig, impl_sig)
543
544        err_prefix = "Typing and implementation arguments differ in "
545
546        a = ty_args
547        b = im_args
548        if ty_pos:
549            if not im_pos:
550                # case 5. described above
551                msg = ("VAR_POSITIONAL (e.g. *args) argument kind (offending "
552                       "argument name is '%s') found in the typing function "
553                       "signature, but is not in the implementing function "
554                       "signature.\n%s") % (ty_pos, sig_str)
555                raise InternalError(msg)
556        else:
557            if im_pos:
558                # no *args in typing but there's a *args in the implementation
559                # this is case 4. described above
560                b = im_args[:im_args.index(im_pos)]
561                try:
562                    a = ty_args[:ty_args.index(b[-1]) + 1]
563                except ValueError:
564                    # there's no b[-1] arg name in the ty_args, something is
565                    # very wrong, we can't work out a diff (*args consumes
566                    # unknown quantity of args) so just report first error
567                    specialized = "argument names.\n%s\nFirst difference: '%s'"
568                    msg = err_prefix + specialized % (sig_str, b[-1])
569                    raise InternalError(msg)
570
571        def gen_diff(typing, implementing):
572            diff = set(typing) ^ set(implementing)
573            return "Difference: %s" % diff
574
575        if a != b:
576            specialized = "argument names.\n%s\n%s" % (sig_str, gen_diff(a, b))
577            raise InternalError(err_prefix + specialized)
578
579        # ensure kwargs are the same
580        ty = [x.name for x in ty_kws]
581        im = [x.name for x in im_kws]
582        if ty != im:
583            specialized = "keyword argument names.\n%s\n%s"
584            msg = err_prefix + specialized % (sig_str, gen_diff(ty_kws, im_kws))
585            raise InternalError(msg)
586        same = [x.default for x in ty_kws] == [x.default for x in im_kws]
587        if not same:
588            specialized = "keyword argument default values.\n%s\n%s"
589            msg = err_prefix + specialized % (sig_str, gen_diff(ty_kws, im_kws))
590            raise InternalError(msg)
591
592    def generic(self, args, kws):
593        """
594        Type the overloaded function by compiling the appropriate
595        implementation for the given args.
596        """
597        disp, new_args = self._get_impl(args, kws)
598        if disp is None:
599            return
600        # Compile and type it for the given types
601        disp_type = types.Dispatcher(disp)
602        # Store the compiled overload for use in the lowering phase if there's
603        # no inlining required (else functions are being compiled which will
604        # never be used as they are inlined)
605        if not self._inline.is_never_inline:
606            # need to run the compiler front end up to type inference to compute
607            # a signature
608            from numba.core import typed_passes, compiler
609            from numba.core.inline_closurecall import InlineWorker
610            fcomp = disp._compiler
611            flags = compiler.Flags()
612
613            # Updating these causes problems?!
614            #fcomp.targetdescr.options.parse_as_flags(flags,
615            #                                         fcomp.targetoptions)
616            #flags = fcomp._customize_flags(flags)
617
618            # spoof a compiler pipline like the one that will be in use
619            tyctx = fcomp.targetdescr.typing_context
620            tgctx = fcomp.targetdescr.target_context
621            compiler_inst = fcomp.pipeline_class(tyctx, tgctx, None, None, None,
622                                                 flags, None, )
623            inline_worker = InlineWorker(tyctx, tgctx, fcomp.locals,
624                                         compiler_inst, flags, None,)
625
626            # If the inlinee contains something to trigger literal arg dispatch
627            # then the pipeline call will unconditionally fail due to a raised
628            # ForceLiteralArg exception. Therefore `resolve` is run first, as
629            # type resolution must occur at some point, this will hit any
630            # `literally` calls and because it's going via the dispatcher will
631            # handle them correctly i.e. ForceLiteralArg propagates. This having
632            # the desired effect of ensuring the pipeline call is only made in
633            # situations that will succeed. For context see #5887.
634            resolve = disp_type.dispatcher.get_call_template
635            template, pysig, folded_args, kws = resolve(new_args, kws)
636            ir = inline_worker.run_untyped_passes(disp_type.dispatcher.py_func)
637
638            typemap, return_type, calltypes = typed_passes.type_inference_stage(
639                self.context, ir, folded_args, None)
640            sig = Signature(return_type, folded_args, None)
641            # this stores a load of info for the cost model function if supplied
642            # it by default is None
643            self._inline_overloads[sig.args] = {'folded_args': folded_args}
644            # this stores the compiled overloads, if there's no compiled
645            # overload available i.e. function is always inlined, the key still
646            # needs to exist for type resolution
647
648            # NOTE: If lowering is failing on a `_EmptyImplementationEntry`,
649            #       the inliner has failed to inline this entry corretly.
650            impl_init = _EmptyImplementationEntry('always inlined')
651            self._compiled_overloads[sig.args] = impl_init
652            if not self._inline.is_always_inline:
653                # this branch is here because a user has supplied a function to
654                # determine whether to inline or not. As a result both compiled
655                # function and inliner info needed, delaying the computation of
656                # this leads to an internal state mess at present. TODO: Fix!
657                sig = disp_type.get_call_type(self.context, new_args, kws)
658                self._compiled_overloads[sig.args] = disp_type.get_overload(sig)
659                # store the inliner information, it's used later in the cost
660                # model function call
661            iinfo = _inline_info(ir, typemap, calltypes, sig)
662            self._inline_overloads[sig.args] = {'folded_args': folded_args,
663                                                'iinfo': iinfo}
664        else:
665            sig = disp_type.get_call_type(self.context, new_args, kws)
666            self._compiled_overloads[sig.args] = disp_type.get_overload(sig)
667        return sig
668
669    def _get_impl(self, args, kws):
670        """Get implementation given the argument types.
671
672        Returning a Dispatcher object.  The Dispatcher object is cached
673        internally in `self._impl_cache`.
674        """
675        cache_key = self.context, tuple(args), tuple(kws.items())
676        try:
677            impl, args = self._impl_cache[cache_key]
678        except KeyError:
679            impl, args = self._build_impl(cache_key, args, kws)
680        return impl, args
681
682    def _build_impl(self, cache_key, args, kws):
683        """Build and cache the implementation.
684
685        Given the positional (`args`) and keyword arguments (`kws`), obtains
686        the `overload` implementation and wrap it in a Dispatcher object.
687        The expected argument types are returned for use by type-inference.
688        The expected argument types are only different from the given argument
689        types if there is an imprecise type in the given argument types.
690
691        Parameters
692        ----------
693        cache_key : hashable
694            The key used for caching the implementation.
695        args : Tuple[Type]
696            Types of positional argument.
697        kws : Dict[Type]
698            Types of keyword argument.
699
700        Returns
701        -------
702        disp, args :
703            On success, returns `(Dispatcher, Tuple[Type])`.
704            On failure, returns `(None, None)`.
705
706        """
707        from numba import jit
708
709        # Get the overload implementation for the given types
710        ovf_result = self._overload_func(*args, **kws)
711        if ovf_result is None:
712            # No implementation => fail typing
713            self._impl_cache[cache_key] = None, None
714            return None, None
715        elif isinstance(ovf_result, tuple):
716            # The implementation returned a signature that the type-inferencer
717            # should be using.
718            sig, pyfunc = ovf_result
719            args = sig.args
720            kws = {}
721            cache_key = None            # don't cache
722        else:
723            # Regular case
724            pyfunc = ovf_result
725
726        # Check type of pyfunc
727        if not isinstance(pyfunc, FunctionType):
728            msg = ("Implementator function returned by `@overload` "
729                   "has an unexpected type.  Got {}")
730            raise AssertionError(msg.format(pyfunc))
731
732        # check that the typing and impl sigs match up
733        if self._strict:
734            self._validate_sigs(self._overload_func, pyfunc)
735        # Make dispatcher
736        jitdecor = jit(nopython=True, **self._jit_options)
737        disp = jitdecor(pyfunc)
738        # Make sure that the implementation can be fully compiled
739        disp_type = types.Dispatcher(disp)
740        disp_type.get_call_type(self.context, args, kws)
741        if cache_key is not None:
742            self._impl_cache[cache_key] = disp, args
743        return disp, args
744
745    def get_impl_key(self, sig):
746        """
747        Return the key for looking up the implementation for the given
748        signature on the target context.
749        """
750        return self._compiled_overloads[sig.args]
751
752    @classmethod
753    def get_source_info(cls):
754        """Return a dictionary with information about the source code of the
755        implementation.
756
757        Returns
758        -------
759        info : dict
760            - "kind" : str
761                The implementation kind.
762            - "name" : str
763                The name of the function that provided the definition.
764            - "sig" : str
765                The formatted signature of the function.
766            - "filename" : str
767                The name of the source file.
768            - "lines": tuple (int, int)
769                First and list line number.
770            - "docstring": str
771                The docstring of the definition.
772        """
773        basepath = os.path.dirname(os.path.dirname(numba.__file__))
774        impl = cls._overload_func
775        code, firstlineno, path = cls.get_source_code_info(impl)
776        sig = str(utils.pysignature(impl))
777        info = {
778            'kind': "overload",
779            'name': getattr(impl, '__qualname__', impl.__name__),
780            'sig': sig,
781            'filename': utils.safe_relpath(path, start=basepath),
782            'lines': (firstlineno, firstlineno + len(code) - 1),
783            'docstring': impl.__doc__
784        }
785        return info
786
787    def get_template_info(self):
788        basepath = os.path.dirname(os.path.dirname(numba.__file__))
789        impl = self._overload_func
790        code, firstlineno, path = self.get_source_code_info(impl)
791        sig = str(utils.pysignature(impl))
792        info = {
793            'kind': "overload",
794            'name': getattr(impl, '__qualname__', impl.__name__),
795            'sig': sig,
796            'filename': utils.safe_relpath(path, start=basepath),
797            'lines': (firstlineno, firstlineno + len(code) - 1),
798            'docstring': impl.__doc__
799        }
800        return info
801
802
803def make_overload_template(func, overload_func, jit_options, strict,
804                           inline, prefer_literal=False):
805    """
806    Make a template class for function *func* overloaded by *overload_func*.
807    Compiler options are passed as a dictionary to *jit_options*.
808    """
809    func_name = getattr(func, '__name__', str(func))
810    name = "OverloadTemplate_%s" % (func_name,)
811    base = _OverloadFunctionTemplate
812    dct = dict(key=func, _overload_func=staticmethod(overload_func),
813               _impl_cache={}, _compiled_overloads={}, _jit_options=jit_options,
814               _strict=strict, _inline=staticmethod(InlineOptions(inline)),
815               _inline_overloads={}, prefer_literal=prefer_literal)
816    return type(base)(name, (base,), dct)
817
818
819class _IntrinsicTemplate(AbstractTemplate):
820    """
821    A base class of templates for intrinsic definition
822    """
823
824    def generic(self, args, kws):
825        """
826        Type the intrinsic by the arguments.
827        """
828        from numba.core.imputils import lower_builtin
829
830        cache_key = self.context, args, tuple(kws.items())
831        try:
832            return self._impl_cache[cache_key]
833        except KeyError:
834            result = self._definition_func(self.context, *args, **kws)
835            if result is None:
836                return
837            [sig, imp] = result
838            pysig = utils.pysignature(self._definition_func)
839            # omit context argument from user function
840            parameters = list(pysig.parameters.values())[1:]
841            sig = sig.replace(pysig=pysig.replace(parameters=parameters))
842            self._impl_cache[cache_key] = sig
843            self._overload_cache[sig.args] = imp
844            # register the lowering
845            lower_builtin(imp, *sig.args)(imp)
846            return sig
847
848    def get_impl_key(self, sig):
849        """
850        Return the key for looking up the implementation for the given
851        signature on the target context.
852        """
853        return self._overload_cache[sig.args]
854
855    def get_template_info(self):
856        basepath = os.path.dirname(os.path.dirname(numba.__file__))
857        impl = self._definition_func
858        code, firstlineno, path = self.get_source_code_info(impl)
859        sig = str(utils.pysignature(impl))
860        info = {
861            'kind': "intrinsic",
862            'name': getattr(impl, '__qualname__', impl.__name__),
863            'sig': sig,
864            'filename': utils.safe_relpath(path, start=basepath),
865            'lines': (firstlineno, firstlineno + len(code) - 1),
866            'docstring': impl.__doc__
867        }
868        return info
869
870
871def make_intrinsic_template(handle, defn, name):
872    """
873    Make a template class for a intrinsic handle *handle* defined by the
874    function *defn*.  The *name* is used for naming the new template class.
875    """
876    base = _IntrinsicTemplate
877    name = "_IntrinsicTemplate_%s" % (name)
878    dct = dict(key=handle, _definition_func=staticmethod(defn),
879               _impl_cache={}, _overload_cache={})
880    return type(base)(name, (base,), dct)
881
882
883class AttributeTemplate(object):
884    _initialized = False
885
886    def __init__(self, context):
887        self._lazy_class_init()
888        self.context = context
889
890    def resolve(self, value, attr):
891        return self._resolve(value, attr)
892
893    @classmethod
894    def _lazy_class_init(cls):
895        if not cls._initialized:
896            cls.do_class_init()
897            cls._initialized = True
898
899    @classmethod
900    def do_class_init(cls):
901        """
902        Class-wide initialization.  Can be overridden by subclasses to
903        register permanent typing or target hooks.
904        """
905
906    def _resolve(self, value, attr):
907        fn = getattr(self, "resolve_%s" % attr, None)
908        if fn is None:
909            fn = self.generic_resolve
910            if fn is NotImplemented:
911                if isinstance(value, types.Module):
912                    return self.context.resolve_module_constants(value, attr)
913                else:
914                    return None
915            else:
916                return fn(value, attr)
917        else:
918            return fn(value)
919
920    generic_resolve = NotImplemented
921
922
923class _OverloadAttributeTemplate(AttributeTemplate):
924    """
925    A base class of templates for @overload_attribute functions.
926    """
927    is_method = False
928
929    def __init__(self, context):
930        super(_OverloadAttributeTemplate, self).__init__(context)
931        self.context = context
932
933    @classmethod
934    def do_class_init(cls):
935        """
936        Register attribute implementation.
937        """
938        from numba.core.imputils import lower_getattr
939        attr = cls._attr
940
941        @lower_getattr(cls.key, attr)
942        def getattr_impl(context, builder, typ, value):
943            typingctx = context.typing_context
944            fnty = cls._get_function_type(typingctx, typ)
945            sig = cls._get_signature(typingctx, fnty, (typ,), {})
946            call = context.get_function(fnty, sig)
947            return call(builder, (value,))
948
949    def _resolve(self, typ, attr):
950        if self._attr != attr:
951            return None
952        fnty = self._get_function_type(self.context, typ)
953        sig = self._get_signature(self.context, fnty, (typ,), {})
954        # There should only be one template
955        for template in fnty.templates:
956            self._inline_overloads.update(template._inline_overloads)
957        return sig.return_type
958
959    @classmethod
960    def _get_signature(cls, typingctx, fnty, args, kws):
961        sig = fnty.get_call_type(typingctx, args, kws)
962        sig = sig.replace(pysig=utils.pysignature(cls._overload_func))
963        return sig
964
965    @classmethod
966    def _get_function_type(cls, typingctx, typ):
967        return typingctx.resolve_value_type(cls._overload_func)
968
969
970class _OverloadMethodTemplate(_OverloadAttributeTemplate):
971    """
972    A base class of templates for @overload_method functions.
973    """
974    is_method = True
975
976    @classmethod
977    def do_class_init(cls):
978        """
979        Register generic method implementation.
980        """
981        from numba.core.imputils import lower_builtin
982        attr = cls._attr
983
984        @lower_builtin((cls.key, attr), cls.key, types.VarArg(types.Any))
985        def method_impl(context, builder, sig, args):
986            typ = sig.args[0]
987            typing_context = context.typing_context
988            fnty = cls._get_function_type(typing_context, typ)
989            sig = cls._get_signature(typing_context, fnty, sig.args, {})
990            call = context.get_function(fnty, sig)
991            # Link dependent library
992            context.add_linking_libs(getattr(call, 'libs', ()))
993            return call(builder, args)
994
995    def _resolve(self, typ, attr):
996        if self._attr != attr:
997            return None
998
999        assert isinstance(typ, self.key)
1000
1001        class MethodTemplate(AbstractTemplate):
1002            key = (self.key, attr)
1003            _inline = self._inline
1004            _overload_func = staticmethod(self._overload_func)
1005            _inline_overloads = self._inline_overloads
1006            prefer_literal = self.prefer_literal
1007
1008            def generic(_, args, kws):
1009                args = (typ,) + tuple(args)
1010                fnty = self._get_function_type(self.context, typ)
1011                sig = self._get_signature(self.context, fnty, args, kws)
1012                sig = sig.replace(pysig=utils.pysignature(self._overload_func))
1013                for template in fnty.templates:
1014                    self._inline_overloads.update(template._inline_overloads)
1015                if sig is not None:
1016                    return sig.as_method()
1017
1018        return types.BoundFunction(MethodTemplate, typ)
1019
1020
1021def make_overload_attribute_template(typ, attr, overload_func, inline,
1022                                     prefer_literal=False,
1023                                     base=_OverloadAttributeTemplate):
1024    """
1025    Make a template class for attribute *attr* of *typ* overloaded by
1026    *overload_func*.
1027    """
1028    assert isinstance(typ, types.Type) or issubclass(typ, types.Type)
1029    name = "OverloadAttributeTemplate_%s_%s" % (typ, attr)
1030    # Note the implementation cache is subclass-specific
1031    dct = dict(key=typ, _attr=attr, _impl_cache={},
1032               _inline=staticmethod(InlineOptions(inline)),
1033               _inline_overloads={},
1034               _overload_func=staticmethod(overload_func),
1035               prefer_literal=prefer_literal,
1036               )
1037    obj = type(base)(name, (base,), dct)
1038    return obj
1039
1040
1041def make_overload_method_template(typ, attr, overload_func, inline,
1042                                  prefer_literal=False):
1043    """
1044    Make a template class for method *attr* of *typ* overloaded by
1045    *overload_func*.
1046    """
1047    return make_overload_attribute_template(
1048        typ, attr, overload_func, inline=inline,
1049        base=_OverloadMethodTemplate, prefer_literal=prefer_literal,
1050    )
1051
1052
1053def bound_function(template_key):
1054    """
1055    Wrap an AttributeTemplate resolve_* method to allow it to
1056    resolve an instance method's signature rather than a instance attribute.
1057    The wrapped method must return the resolved method's signature
1058    according to the given self type, args, and keywords.
1059
1060    It is used thusly:
1061
1062        class ComplexAttributes(AttributeTemplate):
1063            @bound_function("complex.conjugate")
1064            def resolve_conjugate(self, ty, args, kwds):
1065                return ty
1066
1067    *template_key* (e.g. "complex.conjugate" above) will be used by the
1068    target to look up the method's implementation, as a regular function.
1069    """
1070    def wrapper(method_resolver):
1071        @functools.wraps(method_resolver)
1072        def attribute_resolver(self, ty):
1073            class MethodTemplate(AbstractTemplate):
1074                key = template_key
1075
1076                def generic(_, args, kws):
1077                    sig = method_resolver(self, ty, args, kws)
1078                    if sig is not None and sig.recvr is None:
1079                        sig = sig.replace(recvr=ty)
1080                    return sig
1081
1082            return types.BoundFunction(MethodTemplate, ty)
1083        return attribute_resolver
1084    return wrapper
1085
1086
1087class MacroTemplate(object):
1088    pass
1089
1090
1091# -----------------------------
1092
1093class Registry(object):
1094    """
1095    A registry of typing declarations.  The registry stores such declarations
1096    for functions, attributes and globals.
1097    """
1098
1099    def __init__(self):
1100        self.functions = []
1101        self.attributes = []
1102        self.globals = []
1103
1104    def register(self, item):
1105        assert issubclass(item, FunctionTemplate)
1106        self.functions.append(item)
1107        return item
1108
1109    def register_attr(self, item):
1110        assert issubclass(item, AttributeTemplate)
1111        self.attributes.append(item)
1112        return item
1113
1114    def register_global(self, val=None, typ=None, **kwargs):
1115        """
1116        Register the typing of a global value.
1117        Functional usage with a Numba type::
1118            register_global(value, typ)
1119
1120        Decorator usage with a template class::
1121            @register_global(value, typing_key=None)
1122            class Template:
1123                ...
1124        """
1125        if typ is not None:
1126            # register_global(val, typ)
1127            assert val is not None
1128            assert not kwargs
1129            self.globals.append((val, typ))
1130        else:
1131            def decorate(cls, typing_key):
1132                class Template(cls):
1133                    key = typing_key
1134                if callable(val):
1135                    typ = types.Function(Template)
1136                else:
1137                    raise TypeError("cannot infer type for global value %r")
1138                self.globals.append((val, typ))
1139                return cls
1140
1141            # register_global(val, typing_key=None)(<template class>)
1142            assert val is not None
1143            typing_key = kwargs.pop('typing_key', val)
1144            assert not kwargs
1145            if typing_key is val:
1146                # Check the value is globally reachable, as it is going
1147                # to be used as the key.
1148                mod = sys.modules[val.__module__]
1149                if getattr(mod, val.__name__) is not val:
1150                    raise ValueError("%r is not globally reachable as '%s.%s'"
1151                                     % (mod, val.__module__, val.__name__))
1152
1153            def decorator(cls):
1154                return decorate(cls, typing_key)
1155            return decorator
1156
1157
1158class BaseRegistryLoader(object):
1159    """
1160    An incremental loader for a registry.  Each new call to
1161    new_registrations() will iterate over the not yet seen registrations.
1162
1163    The reason for this object is multiple:
1164    - there can be several contexts
1165    - each context wants to install all registrations
1166    - registrations can be added after the first installation, so contexts
1167      must be able to get the "new" installations
1168
1169    Therefore each context maintains its own loaders for each existing
1170    registry, without duplicating the registries themselves.
1171    """
1172
1173    def __init__(self, registry):
1174        self._registrations = dict(
1175            (name, utils.stream_list(getattr(registry, name)))
1176            for name in self.registry_items)
1177
1178    def new_registrations(self, name):
1179        for item in next(self._registrations[name]):
1180            yield item
1181
1182
1183class RegistryLoader(BaseRegistryLoader):
1184    """
1185    An incremental loader for a typing registry.
1186    """
1187    registry_items = ('functions', 'attributes', 'globals')
1188
1189
1190builtin_registry = Registry()
1191infer = builtin_registry.register
1192infer_getattr = builtin_registry.register_attr
1193infer_global = builtin_registry.register_global
1194