# Test cases for functions and calls (compile and run)

[case testCallTrivialFunction]
def f(x: int) -> int:
    return x
[file driver.py]
from native import f
print(f(3))
print(f(-157))
print(f(10**20))
print(f(-10**20))
[out]
3
-157
100000000000000000000
-100000000000000000000

[case testRecursiveFibonacci]
def fib(n: int) -> int:
    if n <= 1:
        return 1
    else:
        return fib(n - 1) + fib(n - 2)
[file driver.py]
from native import fib
print(fib(0))
print(fib(1))
print(fib(2))
print(fib(6))
[out]
1
1
2
13

[case testNestedFunctions]
from typing import Callable, List

def a() -> Callable[[], object]:
    def inner() -> object:
        return None
    return inner

def b() -> Callable[[], Callable[[], str]]:
    def first() -> Callable[[], str]:
        def second() -> str:
            return 'b.first.second: nested function'
        return second
    return first

def c(num: float) -> Callable[[str], str]:
    def inner(s: str) -> str:
        return s + '!'
    return inner

def d(num: float) -> str:
    def inner(s: str) -> str:
        return s + '?'
    a = inner('one')
    b = inner('two')
    return a

def e() -> int:
    return 0

def f() -> int:
    def inner() -> int:
        return e()
    return inner()

def g() -> Callable[[], Callable[[], int]]:
    def inner() -> Callable[[], int]:
        return e
    return inner

def h(num: int) -> int:
    def inner() -> int:
        return num
    return inner()

def i() -> int:
    num = 3
    def inner() -> int:
        return num
    return inner()

def j(num: int) -> int:
    x = 1
    y = 2
    def inner() -> int:
        nonlocal x
        x = 3
        return num + x + y
    return inner()

def k() -> int:
    num = 3
    def inner() -> int:
        nonlocal num
        num = 5
        return num
    return inner() + num

def l() -> int:
    num = 3
    def inner() -> int:
        num = 5
        return num
    return inner() + num

def m() -> Callable[[], int]:
    num = 1
    def inner() -> int:
        num += 1
        return num
    num += 1
    return inner

def n() -> int:
    x = 1
    def add_one() -> None:
        x += 1
    def add_two() -> None:
        x += 2
    add_one()
    add_two()
    return x

def triple(a: int) -> Callable[[], Callable[[int], int]]:
    x = 1
    def outer() -> Callable[[int], int]:
        nonlocal x
        x += 1
        x += a
        a += 1
        def inner(b: int) -> int:
            x += b
            return x
        return inner
    return outer

def if_else(flag: int) -> str:
    def dummy_funtion() -> str:
        return 'if_else.dummy_function'

    if flag < 0:
        def inner() -> str:
            return 'if_else.inner: first definition'
    elif flag > 0:
        def inner() -> str:
            return 'if_else.inner: second definition'
    else:
        def inner() -> str:
            return 'if_else.inner: third definition'
    return inner()

def for_loop() -> int:
    def dummy_funtion() -> str:
        return 'for_loop.dummy_function'

    for i in range(5):
        def inner(i: int) -> int:
            return i
        if i == 3:
            return inner(i)
    return 0

def while_loop() -> int:
    def dummy_funtion() -> str:
        return 'while_loop.dummy_function'

    i = 0
    while i < 5:
        def inner(i: int) -> int:
            return i
        if i == 3:
            return inner(i)
        i += 1
    return 0

def free_vars(foo: int, bar: int) -> int:
    x = 1
    y = 2
    def g():  # type: ignore  # missing type annotation for testing
        nonlocal y
        y = 3
        nonlocal bar
        bar += y
    z = 3
    g()
    return bar

def lambdas(x: int, y: int) -> int:
    s = lambda a, b: a + b + x + y
    return s(1, 2)

def outer() -> str:
    return 'outer: normal function'

def inner() -> str:
    return 'inner: normal function'

class A:
    def __init__(self, x: int) -> None:
        self.x = x

    def outer(self, num: int) -> int:
        y = 5
        def inner() -> int:
            return self.x + y + num
        return inner()

def o() -> int:
    a = [0, 0]
    b = 0
    def b_incr() -> List[int]:
        b += 10
        return a
    c = 0
    def c_incr() -> int:
        c += 1
        return c

    # x = 1, y = 1
    x = y = c_incr()

    # a = [2, 2], b = 20
    b_incr()[0] = b_incr()[1] = c_incr()
    # Should return 26.
    return x + y + a[0] + a[1] + b

global_upvar = 20

toplevel_lambda = lambda x: 10 + global_upvar + x

[file driver.py]
from native import (
    a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, triple, if_else, for_loop, while_loop,
    free_vars, lambdas, outer, inner, A, toplevel_lambda
)

assert a()() == None
assert b()()() == 'b.first.second: nested function'
assert c(5.0)('c') == 'c!'
assert d(4.0) == 'one?'
assert e() == 0
assert f() == 0
assert g()()() == 0
assert h(3) == 3
assert i() == 3
assert j(3) == 8
assert k() == 10
assert l() == 8
assert m()() == 3
assert n() == 4
assert o() == 26

triple_outer = triple(2)
triple_inner = triple_outer()

assert triple_inner(4) == 8
assert triple_inner(4) == 12
assert triple_outer()(4) == 20

assert if_else(-1) == 'if_else.inner: first definition'
assert if_else(1) == 'if_else.inner: second definition'
assert if_else(0) == 'if_else.inner: third definition'

assert for_loop() == 3
assert while_loop() == 3

assert free_vars(1, 2) == 5
assert lambdas(3, 4) == 10

assert outer() == 'outer: normal function'
assert inner() == 'inner: normal function'

assert A(3).outer(4) == 12

assert toplevel_lambda(5) == 35

[case testNestedFunctions2]
from typing import Callable

def outer() -> Callable[[], object]:
    def inner() -> object:
        return None
    return inner

def first() -> Callable[[], Callable[[], str]]:
    def second() -> Callable[[], str]:
        def third() -> str:
            return 'third: nested function'
        return third
    return second

def f1() -> int:
        x = 1
        def f2() -> int:
                y = 2
                def f3() -> int:
                        z = 3
                        return y
                return f3()
        return f2()

def outer_func() -> int:
    def inner_func() -> int:
        return x
    x = 1
    return inner_func()

def mutual_recursion(start : int) -> int:
    def f1(k : int) -> int:
        if k <= 0:
            return 0
        k -= 1
        return f2(k)

    def f2(k : int) -> int:
        if k <= 0:
            return 0
        k -= 1
        return f1(k)
    return f1(start)

def topLayer() -> int:
    def middleLayer() -> int:
        def bottomLayer() -> int:
            return x

        return bottomLayer()

    x = 1
    return middleLayer()

def nest1() -> str:
    def nest2() -> str:
        def nest3() -> str:
            def mut1(val: int) -> str:
                if val <= 0:
                    return "bottomed"
                val -= 1
                return mut2(val)
            def mut2(val: int) -> str:
                if val <= 0:
                        return "bottomed"
                val -= 1
                return mut1(val)
            return mut1(start)
        return nest3()
    start = 3
    return nest2()

def uno(num: float) -> Callable[[str], str]:
    def dos(s: str) -> str:
        return s + '!'
    return dos

def eins(num: float) -> str:
    def zwei(s: str) -> str:
        return s + '?'
    a = zwei('eins')
    b = zwei('zwei')
    return a

def call_other_inner_func(a: int) -> int:
    def foo() -> int:
        return a + 1

    def bar() -> int:
        return foo()

    def baz(n: int) -> int:
        if n == 0:
            return 0
        return n + baz(n - 1)

    return bar() + baz(a)

def inner() -> str:
    return 'inner: normal function'

def second() -> str:
    return 'second: normal function'

def third() -> str:
    return 'third: normal function'

[file driver.py]
from native import (outer, inner, first, uno, eins, call_other_inner_func,
second, third, f1, outer_func, mutual_recursion, topLayer, nest1)

assert outer()() == None
assert inner() == 'inner: normal function'
assert first()()() == 'third: nested function'
assert uno(5.0)('uno') == 'uno!'
assert eins(4.0) == 'eins?'
assert call_other_inner_func(5) == 21
assert second() == 'second: normal function'
assert third() == 'third: normal function'
assert f1() == 2
assert outer_func() == 1
assert mutual_recursion(5) == 0
assert topLayer() == 1
assert nest1() == "bottomed"

[case testFunctionCallWithDefaultArgs]
from typing import Tuple, List, Optional, Callable, Any
def f(x: int, y: int = 3, s: str = "test", z: object = 5) -> Tuple[int, str]:
    def inner() -> int:
        return x + y
    return inner(), s
def g() -> None:
    assert f(2) == (5, "test")
    assert f(s = "123", x = -2) == (1, "123")
def h(a: Optional[object] = None, b: Optional[str] = None) -> Tuple[object, Optional[str]]:
    return (a, b)

def same(x: object = object()) -> object:
    return x

a_lambda: Callable[..., Any] = lambda n=20: n

def nested_funcs(n: int) -> List[Callable[..., Any]]:
    ls: List[Callable[..., Any]] = []
    for i in range(n):
        def f(i: int = i) -> int:
            return i
        ls.append(f)
    return ls

def bool_default(x: bool = False, y: bool = True) -> str:
    return str(x) + '-' + str(y)

[file driver.py]
from native import f, g, h, same, nested_funcs, a_lambda, bool_default
g()
assert f(2) == (5, "test")
assert f(s = "123", x = -2) == (1, "123")
assert h() == (None, None)
assert h(10) == (10, None)
assert h(b='a') == (None, 'a')
assert h(10, 'a') == (10, 'a')
assert same() == same()

assert [f() for f in nested_funcs(10)] == list(range(10))

assert a_lambda(10) == 10
assert a_lambda() == 20

assert bool_default() == 'False-True'
assert bool_default(True) == 'True-True'
assert bool_default(True, False) == 'True-False'

[case testMethodCallWithDefaultArgs]
from typing import Tuple, List
class A:
    def f(self, x: int, y: int = 3, s: str = "test") -> Tuple[int, str]:
        def inner() -> int:
            return x + y
        return inner(), s
def g() -> None:
    a = A()
    assert a.f(2) == (5, "test")
    assert a.f(s = "123", x = -2) == (1, "123")
[file driver.py]
from native import A, g
g()
a = A()
assert a.f(2) == (5, "test")
assert a.f(s = "123", x = -2) == (1, "123")

[case testMethodCallOrdering]
class A:
    def __init__(self, s: str) -> None:
        print(s)
    def f(self, x: 'A', y: 'A') -> None:
        pass

def g() -> None:
    A('A!').f(A('hello'), A('world'))
[file driver.py]
from native import g
g()
[out]
A!
hello
world

[case testPyMethodCall]
from typing import List
def f(x: List[int]) -> int:
    return x.pop()
def g(x: List[int], y: List[int]) -> None:
    x.extend(y)
[file driver.py]
from native import f, g
l = [1, 2]
assert f(l) == 2
g(l, [10])
assert l == [1, 10]
assert f(l) == 10
assert f(l) == 1
g(l, [11, 12])
assert l == [11, 12]

[case testMethodCallWithKeywordArgs]
from typing import Tuple
import testmodule
class A:
    def echo(self, a: int, b: int, c: int) -> Tuple[int, int, int]:
        return a, b, c
def test_native_method_call_with_kwargs() -> None:
    a = A()
    assert a.echo(1, c=3, b=2) == (1, 2, 3)
    assert a.echo(c = 3, a = 1, b = 2) == (1, 2, 3)
def test_module_method_call_with_kwargs() -> None:
    a = testmodule.A()
    assert a.echo(1, c=3, b=2) == (1, 2, 3)
    assert a.echo(c = 3, a = 1, b = 2) == (1, 2, 3)
[file testmodule.py]
from typing import Tuple
class A:
    def echo(self, a: int, b: int, c: int) -> Tuple[int, int, int]:
        return a, b, c
[file driver.py]
import native
native.test_native_method_call_with_kwargs()
native.test_module_method_call_with_kwargs()

[case testAnyCall]
from typing import Any
def call(f: Any) -> Any:
    return f(1, 'x')
[file driver.py]
from native import call
def f(x, y):
    return (x, y)
def g(x): pass

assert call(f) == (1, 'x')
for bad in g, 1:
    try:
        call(bad)
    except TypeError:
        pass
    else:
        assert False, bad

[case testCallableTypes]
from typing import Callable
def absolute_value(x: int) -> int:
    return x if x > 0 else -x

def call_native_function(x: int) -> int:
    return absolute_value(x)

def call_python_function(x: int) -> int:
    return int(x)

def return_float() -> float:
    return 5.0

def return_callable_type() -> Callable[[], float]:
    return return_float

def call_callable_type() -> float:
    f = return_callable_type()
    return f()

def return_passed_in_callable_type(f: Callable[[], float]) -> Callable[[], float]:
    return f

def call_passed_in_callable_type(f: Callable[[], float]) -> float:
    return f()

[file driver.py]
from native import call_native_function, call_python_function, return_float, return_callable_type, call_callable_type, return_passed_in_callable_type, call_passed_in_callable_type
a = call_native_function(1)
b = call_python_function(1)
c = return_callable_type()
d = call_callable_type()
e = return_passed_in_callable_type(return_float)
f = call_passed_in_callable_type(return_float)
assert a == 1
assert b == 1
assert c() == 5.0
assert d == 5.0
assert e() == 5.0
assert f == 5.0

[case testKeywordArgs]
from typing import Tuple
import testmodule

def g(a: int, b: int, c: int) -> Tuple[int, int, int]:
    return a, b, c

def test_call_native_function_with_keyword_args() -> None:
    assert g(1, c = 3, b = 2) == (1, 2, 3)
    assert g(c = 3, a = 1, b = 2) == (1, 2, 3)

def test_call_module_function_with_keyword_args() -> None:
    assert testmodule.g(1, c = 3, b = 2) == (1, 2, 3)
    assert testmodule.g(c = 3, a = 1, b = 2) == (1, 2, 3)

def test_call_python_function_with_keyword_args() -> None:
    assert int("11", base=2) == 3

def test_call_lambda_function_with_keyword_args() -> None:
    g = testmodule.get_lambda_function()
    assert g(1, c = 3, b = 2) == (1, 2, 3)
    assert g(c = 3, a = 1, b = 2) == (1, 2, 3)

[file testmodule.py]
from typing import Tuple

def g(a: int, b: int, c: int) -> Tuple[int, int, int]:
    return a, b, c

def get_lambda_function():
    return (lambda a, b, c: (a, b, c))

[file driver.py]
import native
native.test_call_native_function_with_keyword_args()
native.test_call_module_function_with_keyword_args()
native.test_call_python_function_with_keyword_args()
native.test_call_lambda_function_with_keyword_args()

[case testStarArgs]
from typing import Tuple

def g(a: int, b: int, c: int) -> Tuple[int, int, int]:
    return a, b, c

def test_star_args() -> None:
    assert g(*[1, 2, 3]) == (1, 2, 3)
    assert g(*(1, 2, 3)) == (1, 2, 3)
    assert g(*(1,), *[2, 3]) == (1, 2, 3)
    assert g(*(), *(1,), *(), *(2,), *(3,), *()) == (1, 2, 3)
    assert g(*range(3)) == (0, 1, 2)

[file driver.py]
import native
native.test_star_args()

[case testStar2Args]
from typing import Tuple

def g(a: int, b: int, c: int) -> Tuple[int, int, int]:
    return a, b, c

def test_star2_args() -> None:
    assert g(**{'a': 1, 'b': 2, 'c': 3}) == (1, 2, 3)
    assert g(**{'c': 3, 'a': 1, 'b': 2}) == (1, 2, 3)
    assert g(b=2, **{'a': 1, 'c': 3}) == (1, 2, 3)

def test_star2_args_bad(v: dict) -> bool:
    return g(a=1, b=2, **v) == (1, 2, 3)
[file driver.py]
import native
native.test_star2_args()

# this should raise TypeError due to duplicate kwarg, but currently it doesn't
assert native.test_star2_args_bad({'b': 2, 'c': 3})

[case testStarAndStar2Args]
from typing import Tuple
def g(a: int, b: int, c: int) -> Tuple[int, int, int]:
    return a, b, c

class C:
    def g(self, a: int, b: int, c: int) -> Tuple[int, int, int]:
        return a, b, c

def test_star_and_star2_args() -> None:
    assert g(1, *(2,), **{'c': 3}) == (1, 2, 3)
    assert g(*[1], **{'b': 2, 'c': 3}) == (1, 2, 3)
    c = C()
    assert c.g(1, *(2,), **{'c': 3}) == (1, 2, 3)
    assert c.g(*[1], **{'b': 2, 'c': 3}) == (1, 2, 3)

[file driver.py]
import native
native.test_star_and_star2_args()

[case testAllTheArgCombinations]
from typing import Tuple
def g(a: int, b: int, c: int, d: int = -1) -> Tuple[int, int, int, int]:
    return a, b, c, d

class C:
    def g(self, a: int, b: int, c: int, d: int = -1) -> Tuple[int, int, int, int]:
        return a, b, c, d

def test_all_the_arg_combinations() -> None:
    assert g(1, *(2,), **{'c': 3}) == (1, 2, 3, -1)
    assert g(*[1], **{'b': 2, 'c': 3, 'd': 4}) == (1, 2, 3, 4)
    c = C()
    assert c.g(1, *(2,), **{'c': 3}) == (1, 2, 3, -1)
    assert c.g(*[1], **{'b': 2, 'c': 3, 'd': 4}) == (1, 2, 3, 4)

[file driver.py]
import native
native.test_all_the_arg_combinations()

[case testOverloads]
from typing import overload, Union, Tuple

@overload
def foo(x: int) -> int: ...

@overload
def foo(x: str) -> str: ...

def foo(x: Union[int, str]) -> Union[int, str]:
    return x

class A:
    @overload
    def foo(self, x: int) -> int: ...

    @overload
    def foo(self, x: str) -> str: ...

    def foo(self, x: Union[int, str]) -> Union[int, str]:
        return x

def call1() -> Tuple[int, str]:
    return (foo(10), foo('10'))
def call2() -> Tuple[int, str]:
    x = A()
    return (x.foo(10), x.foo('10'))

[file driver.py]
from native import *
assert call1() == (10, '10')
assert call2() == (10, '10')

[case testDecorators1]
from typing import Generator, Callable, Iterator
from contextlib import contextmanager

def a(f: Callable[[], None]) -> Callable[[], None]:
    def g() -> None:
        print('Entering')
        f()
        print('Exited')
    return g

def b(f: Callable[[], None]) -> Callable[[], None]:
    def g() -> None:
        print('***')
        f()
        print('***')
    return g

@contextmanager
def foo() -> Iterator[int]:
    try:
        print('started')
        yield 0
    finally:
        print('finished')

@contextmanager
def catch() -> Iterator[None]:
    try:
        print('started')
        yield
    except IndexError:
        print('index')
        raise
    except Exception:
        print('lol')

def thing() -> None:
    c()

@a
@b
def c() -> None:
    @a
    @b
    def d() -> None:
        print('d')
    print('c')
    d()

def hm() -> None:
    x = [1]
    with catch():
        x[2]

[file driver.py]
from native import foo, c, thing, hm

with foo() as f:
    print('hello')

c()
thing()
print('==')
try:
    hm()
except IndexError:
    pass
else:
    assert False

[out]
started
hello
finished
Entering
***
c
Entering
***
d
***
Exited
***
Exited
Entering
***
c
Entering
***
d
***
Exited
***
Exited
==
started
index

[case testDecoratorsMethods]
from typing import Any, Callable, Iterator, TypeVar
from contextlib import contextmanager

T = TypeVar('T')
def dec(f: T) -> T:
    return f

def a(f: Callable[[Any], None]) -> Callable[[Any], None]:
    def g(a: Any) -> None:
        print('Entering')
        f(a)
        print('Exited')
    return g

class A:
    @a
    def foo(self) -> None:
        print('foo')

    @contextmanager
    def generator(self) -> Iterator[int]:
        try:
            print('contextmanager: entering')
            yield 0
        finally:
            print('contextmanager: exited')

class Lol:
    @staticmethod
    def foo() -> None:
        Lol.bar()
        Lol.baz()

    @staticmethod
    @dec
    def bar() -> None:
        pass

    @classmethod
    @dec
    def baz(cls) -> None:
        pass

def inside() -> None:
    with A().generator() as g:
        print('hello!')

with A().generator() as g:
    print('hello!')

def lol() -> None:
    with A().generator() as g:
        raise Exception

[file driver.py]
from native import A, lol

A.foo(A())
A().foo()
with A().generator() as g:
    print('hello!')
try:
    lol()
except:
    pass
else:
    assert False

[out]
contextmanager: entering
hello!
contextmanager: exited
Entering
foo
Exited
Entering
foo
Exited
contextmanager: entering
hello!
contextmanager: exited
contextmanager: entering
contextmanager: exited

[case testUnannotatedFunction]
def g(x: int) -> int:
    return x * 2

def f(x):
    return g(x)
[file driver.py]
from native import f
assert f(3) == 6

[case testUnannotatedModuleLevelInitFunction]
# Ensure that adding an implicit `-> None` annotation only applies to `__init__`
# _methods_ specifically (not module-level `__init__` functions).
def __init__():
    return 42
[file driver.py]
from native import __init__
assert __init__() == 42

[case testDifferentArgCountsFromInterpreted]
# Test various signatures from interpreted code.
def noargs() -> int:
    return 5

def onearg(x: int) -> int:
    return x + 1

def twoargs(x: int, y: str) -> int:
    return x + len(y)

def one_or_two(x: int, y: str = 'a') -> int:
    return x + len(y)

[file driver.py]
from native import noargs, onearg, twoargs, one_or_two
from testutil import assertRaises

assert noargs() == 5
t = ()
assert noargs(*t) == 5
d = {}
assert noargs(**d) == 5
assert noargs(*t, **d) == 5

assert onearg(12) == 13
assert onearg(x=8) == 9
t = (1,)
assert onearg(*t) == 2
d = {'x': 5}
assert onearg(**d) == 6

# Test a bogus call to twoargs before any correct calls are made
with assertRaises(TypeError, "twoargs() missing required argument 'x' (pos 1)"):
    twoargs()

assert twoargs(5, 'foo') == 8
assert twoargs(4, y='foo') == 7
assert twoargs(y='foo', x=7) == 10
t = (1, 'xy')
assert twoargs(*t) == 3
d = {'y': 'xy'}
assert twoargs(2, **d) == 4

assert one_or_two(5) == 6
assert one_or_two(x=3) == 4
assert one_or_two(6, 'xy') == 8
assert one_or_two(7, y='xy') == 9
assert one_or_two(y='xy', x=2) == 4
assert one_or_two(*t) == 3
d = {'x': 5}
assert one_or_two(**d) == 6
assert one_or_two(y='xx', **d) == 7
d = {'y': 'abc'}
assert one_or_two(1, **d) == 4

with assertRaises(TypeError, 'noargs() takes at most 0 arguments (1 given)'):
    noargs(1)
with assertRaises(TypeError, 'noargs() takes at most 0 keyword arguments (1 given)'):
    noargs(x=1)

with assertRaises(TypeError, "onearg() missing required argument 'x' (pos 1)"):
    onearg()
with assertRaises(TypeError, 'onearg() takes at most 1 argument (2 given)'):
    onearg(1, 2)
with assertRaises(TypeError, "onearg() missing required argument 'x' (pos 1)"):
    onearg(y=1)
with assertRaises(TypeError, "onearg() takes at most 1 argument (2 given)"):
    onearg(1, y=1)

with assertRaises(TypeError, "twoargs() missing required argument 'x' (pos 1)"):
    twoargs()
with assertRaises(TypeError, "twoargs() missing required argument 'y' (pos 2)"):
    twoargs(1)
with assertRaises(TypeError, 'twoargs() takes at most 2 arguments (3 given)'):
    twoargs(1, 'x', 2)
with assertRaises(TypeError, 'twoargs() takes at most 2 arguments (3 given)'):
    twoargs(1, 'x', y=2)

with assertRaises(TypeError, "one_or_two() missing required argument 'x' (pos 1)"):
    one_or_two()
with assertRaises(TypeError, 'one_or_two() takes at most 2 arguments (3 given)'):
    one_or_two(1, 'x', 2)
with assertRaises(TypeError, 'one_or_two() takes at most 2 arguments (3 given)'):
    one_or_two(1, 'x', y=2)

[case testComplicatedArgs]
from typing import Tuple, Dict

def kwonly1(x: int = 0, *, y: int) -> Tuple[int, int]:
    return x, y

def kwonly2(*, x: int = 0, y: int) -> Tuple[int, int]:
    return x, y

def kwonly3(a: int, b: int = 0, *, y: int, x: int = 1) -> Tuple[int, int, int, int]:
    return a, b, x, y

def kwonly4(*, x: int, y: int) -> Tuple[int, int]:
    return x, y

def varargs1(*args: int) -> Tuple[int, ...]:
    return args

def varargs2(*args: int, **kwargs: int) -> Tuple[Tuple[int, ...], Dict[str, int]]:
    return args, kwargs

def varargs3(**kwargs: int) -> Dict[str, int]:
    return kwargs

def varargs4(a: int, b: int = 0,
             *args: int, y: int, x: int = 1,
             **kwargs: int) -> Tuple[Tuple[int, ...], Dict[str, int]]:
    return (a, b, *args), {'x': x, 'y': y, **kwargs}

class A:
    def f(self, x: int) -> Tuple[int, ...]:
        return (x,)
    def g(self, x: int) -> Tuple[Tuple[int, ...], Dict[str, int]]:
        return (x,), {}

class B(A):
    def f(self, *args: int) -> Tuple[int, ...]:
        return args
    def g(self, *args: int, **kwargs: int) -> Tuple[Tuple[int, ...], Dict[str, int]]:
        return args, kwargs

[file other.py]
# This file is imported in both compiled and interpreted mode in order to
# test both native calls and calls via the C API.

from native import (
    kwonly1, kwonly2, kwonly3, kwonly4,
    varargs1, varargs2, varargs3, varargs4,
    A, B
)

# kwonly arg tests
assert kwonly1(10, y=20) == (10, 20)
assert kwonly1(y=20) == (0, 20)

assert kwonly2(x=10, y=20) == (10, 20)
assert kwonly2(y=20) == (0, 20)

assert kwonly3(10, y=20) == (10, 0, 1, 20)
assert kwonly3(a=10, y=20) == (10, 0, 1, 20)
assert kwonly3(10, 30, y=20) == (10, 30, 1, 20)
assert kwonly3(10, b=30, y=20) == (10, 30, 1, 20)
assert kwonly3(a=10, b=30, y=20) == (10, 30, 1, 20)

assert kwonly3(10, x=40, y=20) == (10, 0, 40, 20)
assert kwonly3(a=10, x=40, y=20) == (10, 0, 40, 20)
assert kwonly3(10, 30, x=40, y=20) == (10, 30, 40, 20)
assert kwonly3(10, b=30, x=40, y=20) == (10, 30, 40, 20)
assert kwonly3(a=10, b=30, x=40, y=20) == (10, 30, 40, 20)

assert kwonly4(x=1, y=2) == (1, 2)
assert kwonly4(y=2, x=1) == (1, 2)

# varargs tests
assert varargs1() == ()
assert varargs1(1, 2, 3) == (1, 2, 3)
assert varargs1(1, *[2, 3, 4], 5, *[6, 7, 8], 9) == (1, 2, 3, 4, 5, 6, 7, 8, 9)
assert varargs2(1, 2, 3) == ((1, 2, 3), {})
assert varargs2(1, 2, 3, x=4) == ((1, 2, 3), {'x': 4})
assert varargs2(x=4) == ((), {'x': 4})
assert varargs3() == {}
assert varargs3(x=4) == {'x': 4}
assert varargs3(x=4, y=5) == {'x': 4, 'y': 5}

assert varargs4(-1, y=2) == ((-1, 0), {'x': 1, 'y': 2})
assert varargs4(-1, 2, y=2) == ((-1, 2), {'x': 1, 'y': 2})
assert varargs4(-1, 2, 3, y=2) == ((-1, 2, 3), {'x': 1, 'y': 2})
assert varargs4(-1, 2, 3, x=10, y=2) == ((-1, 2, 3), {'x': 10, 'y': 2})
assert varargs4(-1, x=10, y=2) == ((-1, 0), {'x': 10, 'y': 2})
assert varargs4(-1, y=2, z=20) == ((-1, 0), {'x': 1, 'y': 2, 'z': 20})
assert varargs4(-1, 2, y=2, z=20) == ((-1, 2), {'x': 1, 'y': 2, 'z': 20})
assert varargs4(-1, 2, 3, y=2, z=20) == ((-1, 2, 3), {'x': 1, 'y': 2, 'z': 20})
assert varargs4(-1, 2, 3, x=10, y=2, z=20) == ((-1, 2, 3), {'x': 10, 'y': 2, 'z': 20})
assert varargs4(-1, x=10, y=2, z=20) == ((-1, 0), {'x': 10, 'y': 2, 'z': 20})

x = B()  # type: A
assert x.f(1) == (1,)
assert x.g(1) == ((1,), {})
# This one is really funny! When we make native calls we lose
# track of which arguments are positional or keyword, so the glue
# calls them all positional unless they are keyword only...
# It would be possible to fix this by dynamically tracking which
# arguments were passed by keyword (for example, by passing a bitmask
# to functions indicating this), but paying a speed, size, and complexity
# cost for something so deeply marginal seems like a bad choice.
# assert x.g(x=1) == ((), {'x': 1})

[file driver.py]
from testutil import assertRaises
from native import (
    kwonly1, kwonly2, kwonly3, kwonly4,
    varargs1, varargs2, varargs3, varargs4,
)

# Run the non-exceptional tests in both interpreted and compiled mode
import other
import other_interpreted


# And the tests for errors at the interfaces in interpreted only
with assertRaises(TypeError, "missing required keyword-only argument 'y'"):
    kwonly1()
with assertRaises(TypeError, "takes at most 1 positional argument (2 given)"):
    kwonly1(10, 20)

with assertRaises(TypeError, "missing required keyword-only argument 'y'"):
    kwonly2()
with assertRaises(TypeError, "takes no positional arguments"):
    kwonly2(10, 20)

with assertRaises(TypeError, "missing required argument 'a'"):
    kwonly3(b=30, x=40, y=20)
with assertRaises(TypeError, "missing required keyword-only argument 'y'"):
    kwonly3(10)

with assertRaises(TypeError, "missing required keyword-only argument 'y'"):
    kwonly4(x=1)
with assertRaises(TypeError, "missing required keyword-only argument 'x'"):
    kwonly4(y=1)
with assertRaises(TypeError, "missing required keyword-only argument 'x'"):
    kwonly4()

with assertRaises(TypeError, "'x' is an invalid keyword argument for varargs1()"):
    varargs1(x=10)
with assertRaises(TypeError, "'x' is an invalid keyword argument for varargs1()"):
    varargs1(1, x=10)
with assertRaises(TypeError, "varargs3() takes no positional arguments"):
    varargs3(10)
with assertRaises(TypeError, "varargs3() takes no positional arguments"):
    varargs3(10, x=10)

with assertRaises(TypeError, "varargs4() missing required argument 'a' (pos 1)"):
    varargs4()
with assertRaises(TypeError, "varargs4() missing required keyword-only argument 'y'"):
    varargs4(1, 2)
with assertRaises(TypeError, "varargs4() missing required keyword-only argument 'y'"):
    varargs4(1, 2, x=1)
with assertRaises(TypeError, "varargs4() missing required keyword-only argument 'y'"):
    varargs4(1, 2, 3)
with assertRaises(TypeError, "varargs4() missing required argument 'a' (pos 1)"):
    varargs4(y=20)

[case testDecoratorName]
def dec(f): return f

@dec
def foo(): pass

def test_decorator_name():
    assert foo.__name__ == "foo"

[case testLambdaArgToOverloaded]
from lib import sub

def test_str_overload() -> None:
    assert sub('x', lambda m: m) == 'x'

def test_bytes_overload() -> None:
    assert sub(b'x', lambda m: m) == b'x'

[file lib.py]
from typing import overload, Callable, TypeVar, Generic

T = TypeVar("T")

class Match(Generic[T]):
    def __init__(self, x: T) -> None:
        self.x = x

    def group(self, n: int) -> T:
        return self.x

@overload
def sub(s: str, f: Callable[[str], str]) -> str: ...
@overload
def sub(s: bytes, f: Callable[[bytes], bytes]) -> bytes: ...
def sub(s, f):
    return f(s)

[case testContextManagerSpecialCase]
from typing import Generator, Callable, Iterator
from contextlib import contextmanager

@contextmanager
def f() -> Iterator[None]:
    yield

def g() -> None:
    a = ['']
    with f():
        a.pop()

g()

[case testUnpackKwargsCompiled]
from typing_extensions import Unpack, TypedDict

class Person(TypedDict):
    name: str
    age: int

def foo(**kwargs: Unpack[Person]) -> None:
    print(kwargs["name"])

# This is not really supported yet, just test that we behave reasonably.
foo(name='Jennifer', age=38)
[out]
Jennifer

[case testNestedFunctionDunderDict312]
import sys

def foo() -> None:
    def inner() -> str: return "bar"
    print(inner.__dict__)  # type: ignore[attr-defined]
    inner.__dict__.update({"x": 1})  # type: ignore[attr-defined]
    print(inner.__dict__)  # type: ignore[attr-defined]
    print(inner.x)  # type: ignore[attr-defined]

if sys.version_info >= (3, 12):  # type: ignore
    foo()
[out]
[out version>=3.12]
{}
{'x': 1}
1

[case testFunctoolsUpdateWrapper]
import functools

def bar() -> None:
    def inner() -> str: return "bar"
    functools.update_wrapper(inner, bar)  # type: ignore
    print(inner.__dict__)  # type: ignore

bar()
[out]
{'__module__': 'native', '__name__': 'bar', '__qualname__': 'bar', '__doc__': None, '__wrapped__': <built-in function bar>}

[case testCallNestedFunctionWithNamed]
def f() -> None:
    def a() -> None:
        pass
    def b() -> None:
        a()
    b()
[file driver.py]
from native import f
f()

[case testCallNestedFunctionWithLambda]
def f(x: int) -> int:
    def inc(x: int) -> int:
        return x + 1
    return (lambda x: inc(x))(1)
[file driver.py]
from native import f
print(f(1))
[out]
2
