Repository: numba/numba

Issue:
Default value is not literal
<!--

Thanks for opening an issue! To help the Numba team handle your information
efficiently, please first ensure that there is no other issue present that
already describes the issue you have
(search at https://github.com/numba/numba/issues?&q=is%3Aissue).

For more general "how do I do X?" type questions, please speak to us in real
time on https://gitter.im/numba/numba or post to the Numba mailing list
https://groups.google.com/a/continuum.io/forum/#!forum/numba-users.

-->

## Reporting a bug

<!--

Before submitting a bug report please ensure that you can check off these boxes:

-->

- [x] I am using the latest released version of Numba (most recent is visible in
 the change log (https://github.com/numba/numba/blob/master/CHANGE_LOG).
- [x] I have included below a minimal working reproducer (if you are unsure how
 to write one see http://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports).

<!--

Please include details of the bug here, including, if applicable, what you
expected to happen!

-->

```python
import numba

def inner(a):
    pass

@numba.extending.overload(inner)
def inner_overload(a):
    if not isinstance(a, numba.types.Literal):
        return None

    def impl(a):
        print(a)

    return impl

@numba.extending.register_jitable
def my_func(a='a'):
    inner(a)

@numba.njit()
def f():
    my_func()

f()
```

Output:
```
Traceback (most recent call last):
  File "./test.py", line 24, in <module>
    f()
  File ".../numba/core/dispatcher.py", line 401, in _compile_for_args
    error_rewrite(e, 'typing')
  File ".../numba/core/dispatcher.py", line 344, in error_rewrite
    reraise(type(e), e, None)
  File ".../numba/core/utils.py", line 79, in reraise
    raise value.with_traceback(tb)
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Invalid use of Function(<function my_func at 0x7ff222b79f70>) with argument(s) of type(s): ()
 * parameterized
In definition 0:
    TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Invalid use of Function(<function inner at 0x7ff23f0ab700>) with argument(s) of type(s): (unicode_type)
 * parameterized
In definition 0:
    All templates rejected with literals.
In definition 1:
    All templates rejected without literals.
This error is usually caused by passing an argument of a type that is unsupported by the named function.
```

Version:
```python
@numba.njit()
def f_1():
    my_func('a')
```

Works fine.

Numba version is 0a8b8118987944e82603bfa3c90d87b80ffe5d99

Discussion:

Patch:
diff --git a/numba/core/lowering.py b/numba/core/lowering.py
index 2f605d6a9..c49a220c3 100644
--- a/numba/core/lowering.py
+++ b/numba/core/lowering.py
@@ -550,10 +550,12 @@ class Lower(BaseLower):
             argty = self.typeof("arg." + value.name)
             if isinstance(argty, types.Omitted):
                 pyval = argty.value
+                tyctx = self.context.typing_context
+                valty = tyctx.resolve_value_type_prefer_literal(pyval)
                 # use the type of the constant value
-                valty = self.context.typing_context.resolve_value_type(pyval)
-                const = self.context.get_constant_generic(self.builder, valty,
-                                                          pyval)
+                const = self.context.get_constant_generic(
+                    self.builder, valty, pyval,
+                )
                 # cast it to the variable type
                 res = self.context.cast(self.builder, const, valty, ty)
             else:
diff --git a/numba/core/typeinfer.py b/numba/core/typeinfer.py
index 9477a43d1..4ca5d7b61 100644
--- a/numba/core/typeinfer.py
+++ b/numba/core/typeinfer.py
@@ -208,7 +208,9 @@ class ArgConstraint(object):
                 return
             ty = src.getone()
             if isinstance(ty, types.Omitted):
-                ty = typeinfer.context.resolve_value_type(ty.value)
+                ty = typeinfer.context.resolve_value_type_prefer_literal(
+                    ty.value,
+                )
             if not ty.is_precise():
                 raise TypingError('non-precise type {}'.format(ty))
             typeinfer.add_type(self.dst, ty, loc=self.loc)
diff --git a/numba/core/types/misc.py b/numba/core/types/misc.py
index e4c579202..dfc8d63f3 100644
--- a/numba/core/types/misc.py
+++ b/numba/core/types/misc.py
@@ -84,12 +84,16 @@ class Omitted(Opaque):
     """
 
     def __init__(self, value):
-        self.value = value
+        self._value = value
         super(Omitted, self).__init__("omitted(default=%r)" % (value,))
 
     @property
     def key(self):
-        return type(self.value), id(self.value)
+        return type(self._value), id(self._value)
+
+    @property
+    def value(self):
+        return self._value
 
 
 class VarArg(Type):
diff --git a/numba/core/typing/builtins.py b/numba/core/typing/builtins.py
index 0aa397137..3354205f4 100644
--- a/numba/core/typing/builtins.py
+++ b/numba/core/typing/builtins.py
@@ -992,7 +992,9 @@ class TypeBuiltin(AbstractTemplate):
         assert not kws
         if len(args) == 1:
             # One-argument type() -> return the __class__
-            classty = self.context.resolve_getattr(args[0], "__class__")
+            # Avoid literal types
+            arg = types.unliteral(args[0])
+            classty = self.context.resolve_getattr(arg, "__class__")
             if classty is not None:
                 return signature(classty, *args)
 
diff --git a/numba/core/typing/context.py b/numba/core/typing/context.py
index 61f8452fc..81059ac5f 100644
--- a/numba/core/typing/context.py
+++ b/numba/core/typing/context.py
@@ -385,6 +385,15 @@ class BaseContext(object):
 
         raise typeof_exc
 
+    def resolve_value_type_prefer_literal(self, value):
+        """Resolve value type and prefer Literal types whenever possible.
+        """
+        lit = types.maybe_literal(value)
+        if lit is None:
+            return self.resolve_value_type(value)
+        else:
+            return lit
+
     def _get_global_type(self, gv):
         ty = self._lookup_global(gv)
         if ty is not None:


Test patch:
diff --git a/numba/tests/test_types.py b/numba/tests/test_types.py
index e90178628..f09882de7 100644
--- a/numba/tests/test_types.py
+++ b/numba/tests/test_types.py
@@ -785,5 +785,61 @@ class FooType(types.Type):
                              f(Foo()))
 
 
+class TestIssues(TestCase):
+    def test_omitted_type(self):
+        # issue https://github.com/numba/numba/issues/5471
+        def inner(a):
+            pass
+
+        @overload(inner)
+        def inner_overload(a):
+            if not isinstance(a, types.Literal):
+                return
+            return lambda a: a
+
+        @njit
+        def my_func(a='a'):
+            return inner(a)
+
+        @njit
+        def f():
+            return my_func()
+
+        @njit
+        def g():
+            return my_func('b')
+
+        self.assertEqual(f(), 'a')
+        self.assertEqual(g(), 'b')
+
+    def test_type_of_literal(self):
+        # type(val) where val is a literal should not give a literal type.
+        def inner(a):
+            pass
+
+        @overload(inner)
+        def inner_overload(a):
+            if not isinstance(a, types.Literal):
+                return
+            self.assertIsInstance(a, types.Literal)
+            # NOTE: using 1.23 to ensure that the result is indeed an int.
+            return lambda a: type(a)(a + 1.23)
+
+        @njit
+        def my_func(a=1):
+            return inner(a)
+
+        @njit
+        def f():
+            return my_func()
+
+        @njit
+        def g():
+            return my_func(100)
+
+        self.assertEqual(f(), 2)
+        self.assertEqual(g(), 101)
+
+
 if __name__ == '__main__':
     unittest.main()