1from numba.core.types.abstract import Callable, Literal, Type
2from numba.core.types.common import (Dummy, IterableType, Opaque,
3                                     SimpleIteratorType)
4from numba.core.typeconv import Conversion
5from numba.core.errors import TypingError, LiteralTypingError
6
7
8class PyObject(Dummy):
9    """
10    A generic CPython object.
11    """
12
13    def is_precise(self):
14        return False
15
16
17class Phantom(Dummy):
18    """
19    A type that cannot be materialized.  A Phantom cannot be used as
20    argument or return type.
21    """
22
23
24class Undefined(Dummy):
25    """
26    A type that is left imprecise.  This is used as a temporaray placeholder
27    during type inference in the hope that the type can be later refined.
28    """
29
30    def is_precise(self):
31        return False
32
33
34class RawPointer(Opaque):
35    """
36    A raw pointer without any specific meaning.
37    """
38
39
40class StringLiteral(Literal, Dummy):
41    pass
42
43
44Literal.ctor_map[str] = StringLiteral
45
46
47def unliteral(lit_type):
48    """
49    Get base type from Literal type.
50    """
51    if hasattr(lit_type, '__unliteral__'):
52        return lit_type.__unliteral__()
53    return getattr(lit_type, 'literal_type', lit_type)
54
55
56def literal(value):
57    """Returns a Literal instance or raise LiteralTypingError
58    """
59    ty = type(value)
60    if isinstance(value, Literal):
61        msg = "the function does not accept a Literal type; got {} ({})"
62        raise ValueError(msg.format(value, ty))
63    try:
64        ctor = Literal.ctor_map[ty]
65    except KeyError:
66        raise LiteralTypingError("{} cannot be used as a literal".format(ty))
67    else:
68        return ctor(value)
69
70
71def maybe_literal(value):
72    """Get a Literal type for the value or None.
73    """
74    try:
75        return literal(value)
76    except LiteralTypingError:
77        return
78
79
80class Omitted(Opaque):
81    """
82    An omitted function argument with a default value.
83    """
84
85    def __init__(self, value):
86        self._value = value
87        super(Omitted, self).__init__("omitted(default=%r)" % (value,))
88
89    @property
90    def key(self):
91        return type(self._value), id(self._value)
92
93    @property
94    def value(self):
95        return self._value
96
97
98class VarArg(Type):
99    """
100    Special type representing a variable number of arguments at the
101    end of a function's signature.  Only used for signature matching,
102    not for actual values.
103    """
104
105    def __init__(self, dtype):
106        self.dtype = dtype
107        super(VarArg, self).__init__("*%s" % dtype)
108
109    @property
110    def key(self):
111        return self.dtype
112
113
114class Module(Dummy):
115    def __init__(self, pymod):
116        self.pymod = pymod
117        super(Module, self).__init__("Module(%s)" % pymod)
118
119    @property
120    def key(self):
121        return self.pymod
122
123
124class Macro(Type):
125    def __init__(self, template):
126        self.template = template
127        cls = type(self)
128        super(Macro, self).__init__("%s(%s)" % (cls.__name__, template))
129
130    @property
131    def key(self):
132        return self.template
133
134
135class MemInfoPointer(Type):
136    """
137    Pointer to a Numba "meminfo" (i.e. the information for a managed
138    piece of memory).
139    """
140    mutable = True
141
142    def __init__(self, dtype):
143        self.dtype = dtype
144        name = "memory-managed *%s" % dtype
145        super(MemInfoPointer, self).__init__(name)
146
147    @property
148    def key(self):
149        return self.dtype
150
151
152class CPointer(Type):
153    """
154    Type class for pointers to other types.
155    """
156    mutable = True
157
158    def __init__(self, dtype):
159        self.dtype = dtype
160        name = "%s*" % dtype
161        super(CPointer, self).__init__(name)
162
163    @property
164    def key(self):
165        return self.dtype
166
167
168class EphemeralPointer(CPointer):
169    """
170    Type class for pointers which aren't guaranteed to last long - e.g.
171    stack-allocated slots.  The data model serializes such pointers
172    by copying the data pointed to.
173    """
174
175
176class EphemeralArray(Type):
177    """
178    Similar to EphemeralPointer, but pointing to an array of elements,
179    rather than a single one.  The array size must be known at compile-time.
180    """
181
182    def __init__(self, dtype, count):
183        self.dtype = dtype
184        self.count = count
185        name = "*%s[%d]" % (dtype, count)
186        super(EphemeralArray, self).__init__(name)
187
188    @property
189    def key(self):
190        return self.dtype, self.count
191
192
193class Object(Type):
194    # XXX unused?
195    mutable = True
196
197    def __init__(self, clsobj):
198        self.cls = clsobj
199        name = "Object(%s)" % clsobj.__name__
200        super(Object, self).__init__(name)
201
202    @property
203    def key(self):
204        return self.cls
205
206
207class Optional(Type):
208    """
209    Type class for optional types, i.e. union { some type, None }
210    """
211
212    def __init__(self, typ):
213        assert not isinstance(typ, (Optional, NoneType))
214        typ = unliteral(typ)
215        self.type = typ
216        name = "OptionalType(%s)" % self.type
217        super(Optional, self).__init__(name)
218
219    def __str__(self):
220        return "%s i.e. the type '%s or None'" % (self.name, self.type)
221
222    @property
223    def key(self):
224        return self.type
225
226    def can_convert_to(self, typingctx, other):
227        if isinstance(other, Optional):
228            return typingctx.can_convert(self.type, other.type)
229        else:
230            conv = typingctx.can_convert(self.type, other)
231            if conv is not None:
232                return max(conv, Conversion.safe)
233
234    def can_convert_from(self, typingctx, other):
235        if isinstance(other, NoneType):
236            return Conversion.promote
237        elif isinstance(other, Optional):
238            return typingctx.can_convert(other.type, self.type)
239        else:
240            conv = typingctx.can_convert(other, self.type)
241            if conv is not None:
242                return max(conv, Conversion.promote)
243
244    def unify(self, typingctx, other):
245        if isinstance(other, Optional):
246            unified = typingctx.unify_pairs(self.type, other.type)
247        else:
248            unified = typingctx.unify_pairs(self.type, other)
249
250        if unified is not None:
251            if isinstance(unified, Optional):
252                return unified
253            else:
254                return Optional(unified)
255
256
257class NoneType(Opaque):
258    """
259    The type for None.
260    """
261
262    def unify(self, typingctx, other):
263        """
264        Turn anything to a Optional type;
265        """
266        if isinstance(other, (Optional, NoneType)):
267            return other
268        return Optional(other)
269
270
271class EllipsisType(Opaque):
272    """
273    The type for the Ellipsis singleton.
274    """
275
276
277class ExceptionClass(Callable, Phantom):
278    """
279    The type of exception classes (not instances).
280    """
281
282    def __init__(self, exc_class):
283        assert issubclass(exc_class, BaseException)
284        name = "%s" % (exc_class.__name__)
285        self.exc_class = exc_class
286        super(ExceptionClass, self).__init__(name)
287
288    def get_call_type(self, context, args, kws):
289        return self.get_call_signatures()[0][0]
290
291    def get_call_signatures(self):
292        from numba.core import typing
293        return_type = ExceptionInstance(self.exc_class)
294        return [typing.signature(return_type)], False
295
296    @property
297    def key(self):
298        return self.exc_class
299
300
301class ExceptionInstance(Phantom):
302    """
303    The type of exception instances.  *exc_class* should be the
304    exception class.
305    """
306
307    def __init__(self, exc_class):
308        assert issubclass(exc_class, BaseException)
309        name = "%s(...)" % (exc_class.__name__,)
310        self.exc_class = exc_class
311        super(ExceptionInstance, self).__init__(name)
312
313    @property
314    def key(self):
315        return self.exc_class
316
317
318class SliceType(Type):
319
320    def __init__(self, name, members):
321        assert members in (2, 3)
322        self.members = members
323        self.has_step = members >= 3
324        super(SliceType, self).__init__(name)
325
326    @property
327    def key(self):
328        return self.members
329
330
331class SliceLiteral(Literal, SliceType):
332    def __init__(self, value):
333        self._literal_init(value)
334        name = 'Literal[slice]({})'.format(value)
335        members = 2 if value.step is None else 3
336        SliceType.__init__(self, name=name, members=members)
337
338
339Literal.ctor_map[slice] = SliceLiteral
340
341
342class ClassInstanceType(Type):
343    """
344    The type of a jitted class *instance*.  It will be the return-type
345    of the constructor of the class.
346    """
347    mutable = True
348    name_prefix = "instance"
349
350    def __init__(self, class_type):
351        self.class_type = class_type
352        name = "{0}.{1}".format(self.name_prefix, self.class_type.name)
353        super(ClassInstanceType, self).__init__(name)
354
355    def get_data_type(self):
356        return ClassDataType(self)
357
358    def get_reference_type(self):
359        return self
360
361    @property
362    def key(self):
363        return self.class_type.key
364
365    @property
366    def classname(self):
367        return self.class_type.class_name
368
369    @property
370    def jit_props(self):
371        return self.class_type.jit_props
372
373    @property
374    def jit_static_methods(self):
375        return self.class_type.jit_static_methods
376
377    @property
378    def jit_methods(self):
379        return self.class_type.jit_methods
380
381    @property
382    def struct(self):
383        return self.class_type.struct
384
385    @property
386    def methods(self):
387        return self.class_type.methods
388
389    @property
390    def static_methods(self):
391        return self.class_type.static_methods
392
393
394class ClassType(Callable, Opaque):
395    """
396    The type of the jitted class (not instance).  When the type of a class
397    is called, its constructor is invoked.
398    """
399    mutable = True
400    name_prefix = "jitclass"
401    instance_type_class = ClassInstanceType
402
403    def __init__(self, class_def, ctor_template_cls, struct, jit_methods,
404                 jit_props, jit_static_methods):
405        self.class_name = class_def.__name__
406        self.class_doc = class_def.__doc__
407        self._ctor_template_class = ctor_template_cls
408        self.jit_methods = jit_methods
409        self.jit_props = jit_props
410        self.jit_static_methods = jit_static_methods
411        self.struct = struct
412        fielddesc = ','.join("{0}:{1}".format(k, v) for k, v in struct.items())
413        name = "{0}.{1}#{2:x}<{3}>".format(self.name_prefix, self.class_name,
414                                           id(self), fielddesc)
415        super(ClassType, self).__init__(name)
416
417    def get_call_type(self, context, args, kws):
418        return self.ctor_template(context).apply(args, kws)
419
420    def get_call_signatures(self):
421        return (), True
422
423    @property
424    def methods(self):
425        return {k: v.py_func for k, v in self.jit_methods.items()}
426
427    @property
428    def static_methods(self):
429        return {k: v.py_func for k, v in self.jit_static_methods.items()}
430
431    @property
432    def instance_type(self):
433        return ClassInstanceType(self)
434
435    @property
436    def ctor_template(self):
437        return self._specialize_template(self._ctor_template_class)
438
439    def _specialize_template(self, basecls):
440        return type(basecls.__name__, (basecls,), dict(key=self))
441
442
443class DeferredType(Type):
444    """
445    Represents a type that will be defined later.  It must be defined
446    before it is materialized (used in the compiler).  Once defined, it
447    behaves exactly as the type it is defining.
448    """
449
450    def __init__(self):
451        self._define = None
452        name = "{0}#{1}".format(type(self).__name__, id(self))
453        super(DeferredType, self).__init__(name)
454
455    def get(self):
456        if self._define is None:
457            raise RuntimeError("deferred type not defined")
458        return self._define
459
460    def define(self, typ):
461        if self._define is not None:
462            raise TypeError("deferred type already defined")
463        if not isinstance(typ, Type):
464            raise TypeError("arg is not a Type; got: {0}".format(type(typ)))
465        self._define = typ
466
467    def unify(self, typingctx, other):
468        return typingctx.unify_pairs(self.get(), other)
469
470
471class ClassDataType(Type):
472    """
473    Internal only.
474    Represents the data of the instance.  The representation of
475    ClassInstanceType contains a pointer to a ClassDataType which represents
476    a C structure that contains all the data fields of the class instance.
477    """
478
479    def __init__(self, classtyp):
480        self.class_type = classtyp
481        name = "data.{0}".format(self.class_type.name)
482        super(ClassDataType, self).__init__(name)
483
484
485class ContextManager(Callable, Phantom):
486    """
487    An overly-simple ContextManager type that cannot be materialized.
488    """
489
490    def __init__(self, cm):
491        self.cm = cm
492        super(ContextManager, self).__init__("ContextManager({})".format(cm))
493
494    def get_call_signatures(self):
495        if not self.cm.is_callable:
496            msg = "contextmanager {} is not callable".format(self.cm)
497            raise TypingError(msg)
498
499        return (), False
500
501    def get_call_type(self, context, args, kws):
502        from numba.core import typing
503
504        if not self.cm.is_callable:
505            msg = "contextmanager {} is not callable".format(self.cm)
506            raise TypingError(msg)
507
508        posargs = list(args) + [v for k, v in sorted(kws.items())]
509        return typing.signature(self, *posargs)
510
511
512class UnicodeType(IterableType):
513
514    def __init__(self, name):
515        super(UnicodeType, self).__init__(name)
516
517    @property
518    def iterator_type(self):
519        return UnicodeIteratorType(self)
520
521
522class UnicodeIteratorType(SimpleIteratorType):
523
524    def __init__(self, dtype):
525        name = "iter_unicode"
526        self.data = dtype
527        super(UnicodeIteratorType, self).__init__(name, dtype)
528