Пример #1
0
 def object_dump(self, obj):
     """
     Dump a Python object on C stderr.  For debugging purposes.
     """
     fnty = Type.function(Type.void(), [self.pyobj])
     fn = self._get_function(fnty, name="_PyObject_Dump")
     return self.builder.call(fn, (obj,))
Пример #2
0
def int_utruediv_impl(context, builder, sig, args):
    x, y = args
    fx = builder.uitofp(x, Type.double())
    fy = builder.uitofp(y, Type.double())
    cgutils.guard_zero(context, builder, y,
                       (ZeroDivisionError, "division by zero"))
    return builder.fdiv(fx, fy)
Пример #3
0
def atan2_f32_impl(context, builder, sig, args):
    assert len(args) == 2
    mod = builder.module
    fnty = Type.function(Type.float(), [Type.float(), Type.float()])
    fn = cgutils.insert_pure_function(builder.module, fnty, name="atan2f")
    res = builder.call(fn, args)
    return impl_ret_untracked(context, builder, sig.return_type, res)
Пример #4
0
def hypot_u64_impl(context, builder, sig, args):
    [x, y] = args
    y = builder.sitofp(y, Type.double())
    x = builder.sitofp(x, Type.double())
    fsig = signature(types.float64, types.float64, types.float64)
    res = hypot_float_impl(context, builder, fsig, (x, y))
    return impl_ret_untracked(context, builder, sig.return_type, res)
Пример #5
0
    def string_as_string_and_size(self, strobj):
        """
        Returns a tuple of ``(ok, buffer, length)``.
        The ``ok`` is i1 value that is set if ok.
        The ``buffer`` is a i8* of the output buffer.
        The ``length`` is a i32/i64 (py_ssize_t) of the length of the buffer.
        """

        p_length = cgutils.alloca_once(self.builder, self.py_ssize_t)
        if PYVERSION >= (3, 0):
            fnty = Type.function(self.cstring, [self.pyobj,
                                                self.py_ssize_t.as_pointer()])
            fname = "PyUnicode_AsUTF8AndSize"
            fn = self._get_function(fnty, name=fname)

            buffer = self.builder.call(fn, [strobj, p_length])
            ok = self.builder.icmp_unsigned('!=',
                                            ir.Constant(buffer.type, None),
                                            buffer)
        else:
            fnty = Type.function(lc.Type.int(), [self.pyobj,
                                                 self.cstring.as_pointer(),
                                                 self.py_ssize_t.as_pointer()])
            fname = "PyString_AsStringAndSize"
            fn = self._get_function(fnty, name=fname)
            # Allocate space for the output parameters
            p_buffer = cgutils.alloca_once(self.builder, self.cstring)

            status = self.builder.call(fn, [strobj, p_buffer, p_length])

            negone = ir.Constant(status.type, -1)
            ok = self.builder.icmp_signed("!=", status, negone)
            buffer = self.builder.load(p_buffer)

        return (ok, buffer, self.builder.load(p_length))
Пример #6
0
def wavebarrier_impl(context, builder, sig, args):
    assert not args
    fnty = Type.function(Type.void(), [])
    fn = builder.module.get_or_insert_function(fnty, name="__hsail_wavebarrier")
    fn.calling_convention = target.CC_SPIR_FUNC
    builder.call(fn, [])
    return _void_value
Пример #7
0
 def call_function_pointer(self, builder, funcptr, signature, args, cconv=None):
     retty = self.get_value_type(signature.return_type)
     fnty = Type.function(retty, [a.type for a in args])
     fnptrty = Type.pointer(fnty)
     addr = self.get_constant(types.intp, funcptr)
     ptr = builder.inttoptr(addr, fnptrty)
     return builder.call(ptr, args, cconv=cconv)
Пример #8
0
    def __init__(self, context, builder, value=None, ref=None, cast_ref=False):
        self._type = context.get_struct_type(self)
        self._context = context
        self._builder = builder
        if ref is None:
            self._value = alloca_once(builder, self._type)
            if value is not None:
                assert not is_pointer(value.type)
                assert value.type == self._type, (value.type, self._type)
                builder.store(value, self._value)
        else:
            assert value is None
            assert is_pointer(ref.type)
            if self._type != ref.type.pointee:
                if cast_ref:
                    ref = builder.bitcast(ref, Type.pointer(self._type))
                else:
                    raise TypeError(
                        "mismatching pointer type: got %s, expected %s"
                        % (ref.type.pointee, self._type))
            self._value = ref

        self._namemap = {}
        self._fdmap = []
        self._typemap = []
        base = Constant.int(Type.int(), 0)
        for i, (k, tp) in enumerate(self._fields):
            self._namemap[k] = i
            self._fdmap.append((base, Constant.int(Type.int(), i)))
            self._typemap.append(tp)
Пример #9
0
 def restore_thread(self, thread_state):
     """
     Restore the given thread state by reacquiring the GIL.
     """
     fnty = Type.function(Type.void(), [self.voidptr])
     fn = self._get_function(fnty, name="PyEval_RestoreThread")
     self.builder.call(fn, [thread_state])
Пример #10
0
def ptx_warp_sync(context, builder, sig, args):
    fname = 'llvm.nvvm.bar.warp.sync'
    lmod = builder.module
    fnty = Type.function(Type.void(), (Type.int(32),))
    sync = lmod.get_or_insert_function(fnty, name=fname)
    builder.call(sync, args)
    return context.get_dummy_value()
Пример #11
0
 def numba_array_adaptor(self, ary, ptr):
     voidptr = Type.pointer(Type.int(8))
     fnty = Type.function(Type.int(), [self.pyobj, voidptr])
     fn = self._get_function(fnty, name="numba_adapt_ndarray")
     fn.args[0].add_attribute(lc.ATTR_NO_CAPTURE)
     fn.args[1].add_attribute(lc.ATTR_NO_CAPTURE)
     return self.builder.call(fn, (ary, ptr))
Пример #12
0
 def numba_buffer_adaptor(self, buf, ptr):
     fnty = Type.function(Type.void(),
                          [ir.PointerType(self.py_buffer_t), self.voidptr])
     fn = self._get_function(fnty, name="numba_adapt_buffer")
     fn.args[0].add_attribute(lc.ATTR_NO_CAPTURE)
     fn.args[1].add_attribute(lc.ATTR_NO_CAPTURE)
     return self.builder.call(fn, (buf, ptr))
Пример #13
0
def complex128_power_impl(context, builder, sig, args):
    [ca, cb] = args
    a = Complex128(context, builder, value=ca)
    b = Complex128(context, builder, value=cb)
    c = Complex128(context, builder)
    module = builder.module
    pa = a._getpointer()
    pb = b._getpointer()
    pc = c._getpointer()

    # Optimize for square because cpow looses a lot of precsiion
    TWO = context.get_constant(types.float64, 2)
    ZERO = context.get_constant(types.float64, 0)

    b_real_is_two = builder.fcmp(lc.FCMP_OEQ, b.real, TWO)
    b_imag_is_zero = builder.fcmp(lc.FCMP_OEQ, b.imag, ZERO)
    b_is_two = builder.and_(b_real_is_two, b_imag_is_zero)

    with builder.if_else(b_is_two) as (then, otherwise):
        with then:
            # Lower as multiplication
            res = complex_mul_impl(context, builder, sig, (ca, ca))
            cres = Complex128(context, builder, value=res)
            c.real = cres.real
            c.imag = cres.imag

        with otherwise:
            # Lower with call to external function
            fnty = Type.function(Type.void(), [pa.type] * 3)
            cpow = module.get_or_insert_function(fnty, name="numba.math.cpow")
            builder.call(cpow, (pa, pb, pc))

    res = builder.load(pc)
    return impl_ret_untracked(context, builder, sig.return_type, res)
Пример #14
0
 def parse_tuple_and_keywords(self, args, kws, fmt, keywords, *objs):
     charptr = Type.pointer(Type.int(8))
     charptrary = Type.pointer(charptr)
     argtypes = [self.pyobj, self.pyobj, charptr, charptrary]
     fnty = Type.function(Type.int(), argtypes, var_arg=True)
     fn = self._get_function(fnty, name="PyArg_ParseTupleAndKeywords")
     return self.builder.call(fn, [args, kws, fmt, keywords] + list(objs))
Пример #15
0
    def _long_from_native_int(self, ival, func_name, native_int_type,
                              signed):
        fnty = Type.function(self.pyobj, [native_int_type])
        fn = self._get_function(fnty, name=func_name)
        resptr = cgutils.alloca_once(self.builder, self.pyobj)

        if PYVERSION < (3, 0):
            # Under Python 2, we try to return a PyInt object whenever
            # the given number fits in a C long.
            pyint_fnty = Type.function(self.pyobj, [self.long])
            pyint_fn = self._get_function(pyint_fnty, name="PyInt_FromLong")
            long_max = Constant.int(native_int_type, _helperlib.long_max)
            if signed:
                long_min = Constant.int(native_int_type, _helperlib.long_min)
                use_pyint = self.builder.and_(
                    self.builder.icmp(lc.ICMP_SGE, ival, long_min),
                    self.builder.icmp(lc.ICMP_SLE, ival, long_max),
                    )
            else:
                use_pyint = self.builder.icmp(lc.ICMP_ULE, ival, long_max)

            with self.builder.if_else(use_pyint) as (then, otherwise):
                with then:
                    downcast_ival = self.builder.trunc(ival, self.long)
                    res = self.builder.call(pyint_fn, [downcast_ival])
                    self.builder.store(res, resptr)
                with otherwise:
                    res = self.builder.call(fn, [ival])
                    self.builder.store(res, resptr)
        else:
            fn = self._get_function(fnty, name=func_name)
            self.builder.store(self.builder.call(fn, [ival]), resptr)

        return self.builder.load(resptr)
Пример #16
0
def set_branch_weight(builder, brinst, trueweight, falseweight):
    module = get_module(builder)
    mdid = lc.MetaDataString.get(module, "branch_weights")
    trueweight = lc.Constant.int(Type.int(), trueweight)
    falseweight = lc.Constant.int(Type.int(), falseweight)
    md = lc.MetaData.get(module, [mdid, trueweight, falseweight])
    brinst.set_metadata("prof", md)
Пример #17
0
    def insert_string_const_addrspace(self, builder, string):
        """
        Insert a constant string in the constant addresspace and return a
        generic i8 pointer to the data.

        This function attempts to deduplicate.
        """
        lmod = builder.basic_block.function.module
        text = Constant.stringz(string)
        name = "__conststring__.%s" % string
        charty = Type.int(8)

        for gv in lmod.global_variables:
            if gv.name == name and gv.type.pointee == text.type:
                break
        else:
            gv = lmod.add_global_variable(text.type, name=name,
                                          addrspace=nvvm.ADDRSPACE_CONSTANT)
            gv.linkage = LINKAGE_INTERNAL
            gv.global_constant = True
            gv.initializer = text

        constcharptrty = Type.pointer(charty, nvvm.ADDRSPACE_CONSTANT)
        charptr = builder.bitcast(gv, constcharptrty)

        conv = nvvmutils.insert_addrspace_conv(lmod, charty,
                                               nvvm.ADDRSPACE_CONSTANT)
        return builder.call(conv, [charptr])
Пример #18
0
 def nrt_adapt_ndarray_from_python(self, ary, ptr):
     assert self.context.enable_nrt
     fnty = Type.function(Type.int(), [self.pyobj, self.voidptr])
     fn = self._get_function(fnty, name="NRT_adapt_ndarray_from_python")
     fn.args[0].add_attribute(lc.ATTR_NO_CAPTURE)
     fn.args[1].add_attribute(lc.ATTR_NO_CAPTURE)
     return self.builder.call(fn, (ary, ptr))
Пример #19
0
 def tuple_setitem(self, tuple_val, index, item):
     """
     Steals a reference to `item`.
     """
     fnty = Type.function(Type.int(), [self.pyobj, Type.int(), self.pyobj])
     setitem_fn = self._get_function(fnty, name='PyTuple_SetItem')
     index = self.context.get_constant(types.int32, index)
     self.builder.call(setitem_fn, [tuple_val, index, item])
Пример #20
0
def ptx_threadfence_device(context, builder, sig, args):
    assert not args
    fname = "llvm.nvvm.membar.gl"
    lmod = builder.module
    fnty = Type.function(Type.void(), ())
    sync = lmod.get_or_insert_function(fnty, name=fname)
    builder.call(sync, ())
    return context.get_dummy_value()
Пример #21
0
 def err_set_string(self, exctype, msg):
     fnty = Type.function(Type.void(), [self.pyobj, self.cstring])
     fn = self._get_function(fnty, name="PyErr_SetString")
     if isinstance(exctype, str):
         exctype = self.get_c_object(exctype)
     if isinstance(msg, str):
         msg = self.context.insert_const_string(self.module, msg)
     return self.builder.call(fn, (exctype, msg))
Пример #22
0
 def list_setitem(self, seq, idx, val):
     """
     Warning: Steals reference to ``val``
     """
     fnty = Type.function(Type.int(), [self.pyobj, self.py_ssize_t,
                                       self.pyobj])
     fn = self._get_function(fnty, name="PyList_SetItem")
     return self.builder.call(fn, [seq, idx, val])
Пример #23
0
 def core(context, builder, sig, args):
     assert sig.return_type == types.boolean, nvname
     fty = context.get_value_type(ty)
     lmod = builder.module
     fnty = Type.function(Type.int(), [fty])
     fn = lmod.get_or_insert_function(fnty, name=nvname)
     result = builder.call(fn, args)
     return context.cast(builder, result, types.int32, types.boolean)
Пример #24
0
 def nrt_adapt_buffer_from_python(self, buf, ptr):
     assert self.context.enable_nrt
     fnty = Type.function(Type.void(), [Type.pointer(self.py_buffer_t),
                                        self.voidptr])
     fn = self._get_function(fnty, name="NRT_adapt_buffer_from_python")
     fn.args[0].add_attribute(lc.ATTR_NO_CAPTURE)
     fn.args[1].add_attribute(lc.ATTR_NO_CAPTURE)
     return self.builder.call(fn, (buf, ptr))
Пример #25
0
def ptx_syncthreads(context, builder, sig, args):
    assert not args
    fname = 'llvm.nvvm.barrier0'
    lmod = cgutils.get_module(builder)
    fnty = Type.function(Type.void(), ())
    sync = lmod.get_or_insert_function(fnty, name=fname)
    builder.call(sync, ())
    return context.get_dummy_value()
Пример #26
0
def atan2_f64_impl(context, builder, sig, args):
    assert len(args) == 2
    mod = cgutils.get_module(builder)
    fnty = Type.function(Type.double(), [Type.double(), Type.double()])
    # Workaround atan2() issues under Windows
    fname = "atan2_fixed" if sys.platform == "win32" else "atan2"
    fn = mod.get_or_insert_function(fnty, name=fname)
    return builder.call(fn, args)
Пример #27
0
def is_scalar_neg(builder, value):
    """is _value_ negative?. Assumes _value_ is signed"""
    nullval = Constant.null(value.type)
    if value.type in (Type.float(), Type.double()):
        isneg = builder.fcmp(lc.FCMP_OLT, value, nullval)
    else:
        isneg = builder.icmp(lc.ICMP_SLT, value, nullval)
    return isneg
Пример #28
0
 def implementer(context, builder, sig, args):
     [val] = args
     input_type = sig.args[0]
     if input_type.signed:
         fpval = builder.sitofp(val, Type.double())
     else:
         fpval = builder.uitofp(val, Type.double())
     sig = signature(types.float64, types.float64)
     return wrapped_impl(context, builder, sig, [fpval])
Пример #29
0
 def printf(self, builder, format_string, *args):
     mod = builder.module
     if isinstance(format_string, str):
         cstr = self.insert_const_string(mod, format_string)
     else:
         cstr = format_string
     fnty = Type.function(Type.int(), (GENERIC_POINTER,), var_arg=True)
     fn = mod.get_or_insert_function(fnty, "printf")
     return builder.call(fn, (cstr,) + tuple(args))
Пример #30
0
def atan2_f64_impl(context, builder, sig, args):
    assert len(args) == 2
    mod = builder.module
    fnty = Type.function(Type.double(), [Type.double(), Type.double()])
    # Workaround atan2() issues under Windows
    fname = "atan2_fixed" if sys.platform == "win32" else "atan2"
    fn = cgutils.insert_pure_function(builder.module, fnty, name=fname)
    res = builder.call(fn, args)
    return impl_ret_untracked(context, builder, sig.return_type, res)
Пример #31
0
 def set_add(self, set, value):
     fnty = Type.function(Type.int(), [self.pyobj, self.pyobj])
     fn = self._get_function(fnty, name="PySet_Add")
     return self.builder.call(fn, [set, value])
Пример #32
0
 def number_invert(self, obj):
     fnty = Type.function(self.pyobj, [self.pyobj])
     fn = self._get_function(fnty, name="PyNumber_Invert")
     return self.builder.call(fn, (obj, ))
Пример #33
0
 def print_string(self, builder, text):
     mod = builder.module
     cstring = GENERIC_POINTER
     fnty = Type.function(Type.int(), [cstring])
     puts = cgutils.get_or_insert_function(mod, fnty, "puts")
     return builder.call(puts, [text])
Пример #34
0
 def complex_imag_as_double(self, cobj):
     fnty = Type.function(Type.double(), [self.pyobj])
     fn = self._get_function(fnty, name="PyComplex_ImagAsDouble")
     return self.builder.call(fn, [cobj])
Пример #35
0
def get_record_member(builder, record, offset, typ):
    pval = gep_inbounds(builder, record, 0, offset)
    assert not is_pointer(pval.type.pointee)
    return builder.bitcast(pval, Type.pointer(typ))
Пример #36
0
 def tuple_size(self, tup):
     fnty = Type.function(self.py_ssize_t, [self.pyobj])
     fn = self._get_function(fnty, name="PyTuple_Size")
     return self.builder.call(fn, [tup])
Пример #37
0
 def sequence_tuple(self, obj):
     fnty = Type.function(self.pyobj, [self.pyobj])
     fn = self._get_function(fnty, name="PySequence_Tuple")
     return self.builder.call(fn, [obj])
Пример #38
0
 def object_getitem(self, obj, key):
     fnty = Type.function(self.pyobj, [self.pyobj, self.pyobj])
     fn = self._get_function(fnty, name="PyObject_GetItem")
     return self.builder.call(fn, (obj, key))
Пример #39
0
 def object_setattr(self, obj, attr, val):
     fnty = Type.function(Type.int(), [self.pyobj, self.pyobj, self.pyobj])
     fn = self._get_function(fnty, name="PyObject_SetAttr")
     return self.builder.call(fn, [obj, attr, val])
Пример #40
0
 def object_str(self, obj):
     fnty = Type.function(self.pyobj, [self.pyobj])
     fn = self._get_function(fnty, name="PyObject_Str")
     return self.builder.call(fn, [obj])
Пример #41
0
 def object_setitem(self, obj, key, val):
     fnty = Type.function(Type.int(), [self.pyobj, self.pyobj, self.pyobj])
     fn = self._get_function(fnty, name="PyObject_SetItem")
     return self.builder.call(fn, (obj, key, val))
Пример #42
0
 def sys_write_stdout(self, fmt, *args):
     fnty = Type.function(Type.void(), [self.cstring], var_arg=True)
     fn = self._get_function(fnty, name="PySys_WriteStdout")
     return self.builder.call(fn, (fmt, ) + args)
Пример #43
0
"""

from __future__ import print_function, division, absolute_import

import collections
from contextlib import contextmanager
import functools
import re

from llvmlite import ir
from llvmlite.llvmpy.core import Constant, Type
import llvmlite.llvmpy.core as lc

from . import utils

true_bit = Constant.int(Type.int(1), 1)
false_bit = Constant.int(Type.int(1), 0)
true_byte = Constant.int(Type.int(8), 1)
false_byte = Constant.int(Type.int(8), 0)

intp_t = Type.int(utils.MACHINE_BITS)


def as_bool_byte(builder, value):
    return builder.zext(value, Type.int(8))


def as_bool_bit(builder, value):
    return builder.icmp(lc.ICMP_NE, value, Constant.null(value.type))

Пример #44
0
def as_bool_byte(builder, value):
    return builder.zext(value, Type.int(8))
Пример #45
0
 def set_new(self, iterable=None):
     if iterable is None:
         iterable = self.get_null_object()
     fnty = Type.function(self.pyobj, [self.pyobj])
     fn = self._get_function(fnty, name="PySet_New")
     return self.builder.call(fn, [iterable])
Пример #46
0
 def object_setattr_string(self, obj, attr, val):
     cstr = self.context.insert_const_string(self.module, attr)
     fnty = Type.function(Type.int(),
                          [self.pyobj, self.cstring, self.pyobj])
     fn = self._get_function(fnty, name="PyObject_SetAttrString")
     return self.builder.call(fn, [obj, cstr, val])
Пример #47
0
 def tuple_new(self, count):
     fnty = Type.function(self.pyobj, [Type.int()])
     fn = self._get_function(fnty, name='PyTuple_New')
     return self.builder.call(
         fn, [self.context.get_constant(types.int32, count)])
Пример #48
0
 def object_getattr(self, obj, attr):
     fnty = Type.function(self.pyobj, [self.pyobj, self.pyobj])
     fn = self._get_function(fnty, name="PyObject_GetAttr")
     return self.builder.call(fn, [obj, attr])
Пример #49
0
 def list_new(self, szval):
     fnty = Type.function(self.pyobj, [self.py_ssize_t])
     fn = self._get_function(fnty, name="PyList_New")
     return self.builder.call(fn, [szval])
Пример #50
0
 def complex_from_doubles(self, realval, imagval):
     fnty = Type.function(self.pyobj, [Type.double(), Type.double()])
     fn = self._get_function(fnty, name="PyComplex_FromDoubles")
     return self.builder.call(fn, [realval, imagval])
Пример #51
0
 def sequence_getslice(self, obj, start, stop):
     fnty = Type.function(self.pyobj,
                          [self.pyobj, self.py_ssize_t, self.py_ssize_t])
     fn = self._get_function(fnty, name="PySequence_GetSlice")
     return self.builder.call(fn, (obj, start, stop))
Пример #52
0
 def bool_from_long(self, ival):
     fnty = Type.function(self.pyobj, [self.long])
     fn = self._get_function(fnty, name="PyBool_FromLong")
     return self.builder.call(fn, [ival])
Пример #53
0
 def iter_next(self, iterobj):
     fnty = Type.function(self.pyobj, [self.pyobj])
     fn = self._get_function(fnty, name="PyIter_Next")
     return self.builder.call(fn, [iterobj])
Пример #54
0
 def number_float(self, val):
     fnty = Type.function(self.pyobj, [self.pyobj])
     fn = self._get_function(fnty, name="PyNumber_Float")
     return self.builder.call(fn, [val])
Пример #55
0
 def object_not(self, obj):
     fnty = Type.function(Type.int(), [self.pyobj])
     fn = self._get_function(fnty, name="PyObject_Not")
     return self.builder.call(fn, [obj])
Пример #56
0
 def call_function_objargs(self, callee, objargs):
     fnty = Type.function(self.pyobj, [self.pyobj], var_arg=True)
     fn = self._get_function(fnty, name="PyObject_CallFunctionObjArgs")
     args = [callee] + list(objargs)
     args.append(self.context.get_constant_null(types.pyobject))
     return self.builder.call(fn, args)
Пример #57
0
 def float_as_double(self, fobj):
     fnty = Type.function(self.double, [self.pyobj])
     fn = self._get_function(fnty, name="PyFloat_AsDouble")
     return self.builder.call(fn, [fobj])
Пример #58
0
 def import_module_noblock(self, modname):
     fnty = Type.function(self.pyobj, [self.cstring])
     fn = self._get_function(fnty, name="PyImport_ImportModuleNoBlock")
     return self.builder.call(fn, [modname])
Пример #59
0
 def number_positive(self, obj):
     fnty = Type.function(self.pyobj, [self.pyobj])
     fn = self._get_function(fnty, name="PyNumber_Positive")
     return self.builder.call(fn, (obj, ))
Пример #60
0
from llvmlite import ir as llvmir
import llvmlite.llvmpy.core as lc
from llvmlite.llvmpy.core import Type, Constant, LLVMException
import llvmlite.binding as ll

from numba.core import types, utils, typing, datamodel, debuginfo, funcdesc, config, cgutils, imputils
from numba.core import event, errors, targetconfig
from numba import _dynfunc, _helperlib
from numba.core.compiler_lock import global_compiler_lock
from numba.core.pythonapi import PythonAPI
from numba.core.imputils import (user_function, user_generator,
                       builtin_registry, impl_ret_borrowed,
                       RegistryLoader)
from numba.cpython import builtins

GENERIC_POINTER = Type.pointer(Type.int(8))
PYOBJECT = GENERIC_POINTER
void_ptr = GENERIC_POINTER


class OverloadSelector(object):
    """
    An object matching an actual signature against a registry of formal
    signatures and choosing the best candidate, if any.

    In the current implementation:
    - a "signature" is a tuple of type classes or type instances
    - the "best candidate" is the most specific match
    """

    def __init__(self):