# Path: cbl/native_type.py
# class NativeType:
# 
#     def __repr__(self):
#         return self.__class__.__name__
# 
#     def instantiate(self, compiler, args):
#         assert not args, "%s does not take arguments" % self
#         return self
# 
#     @property
#     def typename(self):
#         return self.__typename
# 
#     @typename.setter
#     def typename(self, name):
#         self.__typename = name
#         meta = self.metatype
#         if meta is not None:
#             meta.typename = name + '--meta'
# 
#     def allocate(self, compiler, namehint):
#         assert False, "%s is not allocatable" % self.typename
# 
#     @property
#     def metatype(self):
#         return None
# 
#     @property
#     def ir_type(self):
#         raise TypeError('%s does not have an IR type' % self)
# 
#     def get_property(self, compiler, container, prop):
#         raise TypeError('Unknown property %s on %s' % (prop, self))
# 
#     def dispatch_operator(self, compiler, op, left, right=None):
#         if op in ASSIGN_OP:
#             # Remove '=' from op
#             return self._assign_op(compiler, op[:-1], left, right)
#         raise TypeError('Invalid operation "%s" on %s' % (op, self))
# 
#     def _assign_op(self, compiler, op, left, right):
#         tmp = self.dispatch_operator(compiler, op, left, right)
#         return self.dispatch_operator(compiler, '=', left, tmp)
# 
#     def ir_types(self):
#         return (self.ir_type,)
# 
#     def as_variables(self, instance):
#         return (self.as_variable(instance),)
# 
#     def as_variable(self, instance):
#         raise TypeError('%s cannot be converted to a variable' % self)
# 
#     def as_ir_variable(self, instance):
#         return self.as_variable(instance)
# 
#     # Convert a sequence of variables (e.g. from as_variables()) back into
#     # Our high-level value
#     def from_variables(self, compiler, vars):
#         it = iter(vars)
# 
#         # The default implementation is to call allocate but provide variables
#         # via the pool of yet-to-consume variables
#         def shift_var(subname, var_type):
#             var = next(it)
#             # verify IR type is consistent
#             assert var.type == var_type
#             return var
# 
#         with compiler.set_create_var(shift_var):
#             value = self.allocate(compiler, 'restored')
#             # Check we consumed all the variables
#             assert all(False for _ in it)
#             return value
# 
#     def effective_var_size(self):
#         if self.ir_type:
#             return 1
#         assert False
# 
#     def run_constructor(self, compiler, container, arguments):
#         assert not arguments, (self, arguments)
# 
#     def do_construction(self, compiler, instance, member_inits):
#         assert not member_inits
# 
#     def coerce_to(self, compiler, container, type):
#         if type == self:
#             return container
#         return None
# 
# Path: cbl/containers.py
# class AsyncReturn:
# class DelegatedWrite:
#     def __init__(self, realret, callback):
#     def must_await(self):
#     def type(self):
#     def value(self):
#     def write(self, compiler, other):


import abc
import cmd_ir.instructions as i
from .native_type import NativeType
from .containers import InstanceSymbol, Parameter, Temporary
        from .macro_type import MacroType
                return c, args
        for c in candidates:
            new_args = []
            fail = False
            for param, arg in zip(c.type.params, args):
                new_arg = arg.type.coerce_to(self.compiler, arg, param.type)
                if not new_arg:
                    fail = True
                    break
                new_args.append(new_arg)
            if not fail:
                return c, new_args
        arg_types = ', '.join(a.type.typename for a in args)
        err = "Failed to find funtion overload of %s\n" % self.func_name
        err += "Unable to satisfy arguments types: (%s)\n" % (arg_types,)
        err += "Tried candidates:\n"
        for c in self.candidates:
            err += "  %s%s\n" % (self.func_name, c.type.param_str())
        raise TypeError(err)

class FunctionDispatchType(NativeType, Invokable):

    def match_arguments(self, compiler, container, args):
        # TODO possibly refactor
        has_this = isinstance(container, InstanceSymbol)
        if container.value._static:
            assert not has_this
            thiscont = None
        else:
            assert has_this

# Path: cbl/native_type.py
# class NativeType:
# 
#     def __repr__(self):
#         return self.__class__.__name__
# 
#     def instantiate(self, compiler, args):
#         assert not args, "%s does not take arguments" % self
#         return self
# 
#     @property
#     def typename(self):
#         return self.__typename
# 
#     @typename.setter
#     def typename(self, name):
#         self.__typename = name
#         meta = self.metatype
#         if meta is not None:
#             meta.typename = name + '--meta'
# 
#     def allocate(self, compiler, namehint):
#         assert False, "%s is not allocatable" % self.typename
# 
#     @property
#     def metatype(self):
#         return None
# 
#     @property
#     def ir_type(self):
#         raise TypeError('%s does not have an IR type' % self)
# 
#     def get_property(self, compiler, container, prop):
#         raise TypeError('Unknown property %s on %s' % (prop, self))
# 
#     def dispatch_operator(self, compiler, op, left, right=None):
#         if op in ASSIGN_OP:
#             # Remove '=' from op
#             return self._assign_op(compiler, op[:-1], left, right)
#         raise TypeError('Invalid operation "%s" on %s' % (op, self))
# 
#     def _assign_op(self, compiler, op, left, right):
#         tmp = self.dispatch_operator(compiler, op, left, right)
#         return self.dispatch_operator(compiler, '=', left, tmp)
# 
#     def ir_types(self):
#         return (self.ir_type,)
# 
#     def as_variables(self, instance):
#         return (self.as_variable(instance),)
# 
#     def as_variable(self, instance):
#         raise TypeError('%s cannot be converted to a variable' % self)
# 
#     def as_ir_variable(self, instance):
#         return self.as_variable(instance)
# 
#     # Convert a sequence of variables (e.g. from as_variables()) back into
#     # Our high-level value
#     def from_variables(self, compiler, vars):
#         it = iter(vars)
# 
#         # The default implementation is to call allocate but provide variables
#         # via the pool of yet-to-consume variables
#         def shift_var(subname, var_type):
#             var = next(it)
#             # verify IR type is consistent
#             assert var.type == var_type
#             return var
# 
#         with compiler.set_create_var(shift_var):
#             value = self.allocate(compiler, 'restored')
#             # Check we consumed all the variables
#             assert all(False for _ in it)
#             return value
# 
#     def effective_var_size(self):
#         if self.ir_type:
#             return 1
#         assert False
# 
#     def run_constructor(self, compiler, container, arguments):
#         assert not arguments, (self, arguments)
# 
#     def do_construction(self, compiler, instance, member_inits):
#         assert not member_inits
# 
#     def coerce_to(self, compiler, container, type):
#         if type == self:
#             return container
#         return None
# 
# Path: cbl/containers.py
# class AsyncReturn:
# class DelegatedWrite:
#     def __init__(self, realret, callback):
#     def must_await(self):
#     def type(self):
#     def value(self):
#     def write(self, compiler, other):


# Path: cbl/function_type.py
import abc
import cmd_ir.instructions as i
from .native_type import NativeType
from .containers import InstanceSymbol, Parameter, Temporary
        from .macro_type import MacroType

                return c, args
        for c in candidates:
            new_args = []
            fail = False
            for param, arg in zip(c.type.params, args):
                new_arg = arg.type.coerce_to(self.compiler, arg, param.type)
                if not new_arg:
                    fail = True
                    break
                new_args.append(new_arg)
            if not fail:
                return c, new_args
        arg_types = ', '.join(a.type.typename for a in args)
        err = "Failed to find funtion overload of %s\n" % self.func_name
        err += "Unable to satisfy arguments types: (%s)\n" % (arg_types,)
        err += "Tried candidates:\n"
        for c in self.candidates:
            err += "  %s%s\n" % (self.func_name, c.type.param_str())
        raise TypeError(err)

class FunctionDispatchType(NativeType, Invokable):

    def match_arguments(self, compiler, container, args):
        # TODO possibly refactor
        has_this = isinstance(container, InstanceSymbol)
        if container.value._static:
            assert not has_this
            thiscont = None
        else:
            assert has_this

            thiscont = Temporary(container.value._type, container.this)