We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Arrays as default arguments do not properly copy to memory
### Version Information

* vyper Version: latest master
* OS: linux
* Python Version: 3.8.2

### What's your issue about?
When an array used as a default argument is copied to a memory variable, every item in the memory variable has the value of the first item in the array. For example:

```python
@public
@constant
def foo(a: int128[2] = [1, 2]) -> int128[2]:
    b: int128[2] = a
    return b
```

Calls to `foo` produce the following output:

```python
>>> x.foo()
(1, 1)
>>> x.foo([4, 6])
(4, 4)
```

* The same effect is observed with longer arrays and different types.
* Returning directly from calldata gives the expected result.
* Writing to storage gives the expected result.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `vyper/parser/function_definitions/parse_external_function.py`
Content:
```
1 import ast
2 from typing import Any, List, Union
3 
4 from vyper.exceptions import FunctionDeclarationException
5 from vyper.parser.arg_clamps import make_arg_clamper
6 from vyper.parser.context import Context, VariableRecord
7 from vyper.parser.expr import Expr
8 from vyper.parser.function_definitions.utils import (
9     get_default_names_to_set,
10     get_nonreentrant_lock,
11     get_sig_statements,
12 )
13 from vyper.parser.global_context import GlobalContext
14 from vyper.parser.lll_node import LLLnode
15 from vyper.parser.parser_utils import getpos, make_setter
16 from vyper.parser.stmt import parse_body
17 from vyper.signatures import sig_utils
18 from vyper.signatures.function_signature import FunctionSignature
19 from vyper.types.types import ByteArrayLike, get_size_of_type
20 from vyper.utils import MemoryPositions
21 
22 
23 def get_external_arg_copier(
24     total_size: int, memory_dest: int, offset: Union[int, List[Any]] = 4
25 ) -> List[Any]:
26     """
27     Generate argument copier.
28 
29     :param total_size: total memory size to copy
30     :param memory_dest: base memory address to start from
31     :param offset: starting offset, used for ByteArrays
32     """
33     copier = ["calldatacopy", memory_dest, offset, total_size]
34     return copier
35 
36 
37 def validate_external_function(
38     code: ast.FunctionDef, sig: FunctionSignature, global_ctx: GlobalContext
39 ) -> None:
40     """ Validate external function definition. """
41 
42     # __init__ function may not have defaults.
43     if sig.is_initializer() and sig.total_default_args > 0:
44         raise FunctionDeclarationException(
45             "__init__ function may not have default parameters.", code
46         )
47 
48     # Check for duplicate variables with globals
49     for arg in sig.args:
50         if arg.name in global_ctx._globals:
51             raise FunctionDeclarationException(
52                 "Variable name duplicated between " "function arguments and globals: " + arg.name,
53                 code,
54             )
55 
56 
57 def parse_external_function(
58     code: ast.FunctionDef, sig: FunctionSignature, context: Context
59 ) -> LLLnode:
60     """
61     Parse a external function (FuncDef), and produce full function body.
62 
63     :param sig: the FuntionSignature
64     :param code: ast of function
65     :return: full sig compare & function body
66     """
67 
68     validate_external_function(code, sig, context.global_ctx)
69 
70     # Get nonreentrant lock
71     nonreentrant_pre, nonreentrant_post = get_nonreentrant_lock(sig, context.global_ctx)
72 
73     clampers = []
74 
75     # Generate copiers
76     copier: List[Any] = ["pass"]
77     if not len(sig.base_args):
78         copier = ["pass"]
79     elif sig.name == "__init__":
80         copier = ["codecopy", MemoryPositions.RESERVED_MEMORY, "~codelen", sig.base_copy_size]
81         context.memory_allocator.increase_memory(sig.max_copy_size)
82     clampers.append(copier)
83 
84     # Add asserts for payable and internal
85     if sig.mutability != "payable":
86         clampers.append(["assert", ["iszero", "callvalue"]])
87 
88     # Fill variable positions
89     default_args_start_pos = len(sig.base_args)
90     for i, arg in enumerate(sig.args):
91         if i < len(sig.base_args):
92             clampers.append(
93                 make_arg_clamper(
94                     arg.pos,
95                     context.memory_allocator.get_next_memory_position(),
96                     arg.typ,
97                     sig.name == "__init__",
98                 )
99             )
100         if isinstance(arg.typ, ByteArrayLike):
101             mem_pos, _ = context.memory_allocator.increase_memory(32 * get_size_of_type(arg.typ))
102             context.vars[arg.name] = VariableRecord(arg.name, mem_pos, arg.typ, False)
103         else:
104             if sig.name == "__init__":
105                 context.vars[arg.name] = VariableRecord(
106                     arg.name, MemoryPositions.RESERVED_MEMORY + arg.pos, arg.typ, False,
107                 )
108             elif i >= default_args_start_pos:  # default args need to be allocated in memory.
109                 default_arg_pos, _ = context.memory_allocator.increase_memory(32)
110                 context.vars[arg.name] = VariableRecord(
111                     name=arg.name, pos=default_arg_pos, typ=arg.typ, mutable=False,
112                 )
113             else:
114                 context.vars[arg.name] = VariableRecord(
115                     name=arg.name, pos=4 + arg.pos, typ=arg.typ, mutable=False, location="calldata"
116                 )
117 
118     # Create "clampers" (input well-formedness checkers)
119     # Return function body
120     if sig.name == "__init__":
121         o = LLLnode.from_list(
122             ["seq"] + clampers + [parse_body(code.body, context)],  # type: ignore
123             pos=getpos(code),
124         )
125     # Is default function.
126     elif sig.is_default_func():
127         if len(sig.args) > 0:
128             raise FunctionDeclarationException(
129                 "Default function may not receive any arguments.", code
130             )
131         o = LLLnode.from_list(
132             ["seq"] + clampers + [parse_body(code.body, context)],  # type: ignore
133             pos=getpos(code),
134         )
135     # Is a normal function.
136     else:
137         # Function with default parameters.
138         if sig.total_default_args > 0:
139             function_routine = f"{sig.name}_{sig.method_id}"
140             default_sigs = sig_utils.generate_default_arg_sigs(
141                 code, context.sigs, context.global_ctx
142             )
143             sig_chain: List[Any] = ["seq"]
144 
145             for default_sig in default_sigs:
146                 sig_compare, _ = get_sig_statements(default_sig, getpos(code))
147 
148                 # Populate unset default variables
149                 set_defaults = []
150                 for arg_name in get_default_names_to_set(sig, default_sig):
151                     value = Expr(sig.default_values[arg_name], context).lll_node
152                     var = context.vars[arg_name]
153                     left = LLLnode.from_list(
154                         var.pos,
155                         typ=var.typ,
156                         location="memory",
157                         pos=getpos(code),
158                         mutable=var.mutable,
159                     )
160                     set_defaults.append(make_setter(left, value, "memory", pos=getpos(code)))
161 
162                 current_sig_arg_names = {x.name for x in default_sig.args}
163                 base_arg_names = {arg.name for arg in sig.base_args}
164                 copier_arg_count = len(default_sig.args) - len(sig.base_args)
165                 copier_arg_names = list(current_sig_arg_names - base_arg_names)
166 
167                 # Order copier_arg_names, this is very important.
168                 copier_arg_names = [x.name for x in default_sig.args if x.name in copier_arg_names]
169 
170                 # Variables to be populated from calldata/stack.
171                 default_copiers: List[Any] = []
172                 if copier_arg_count > 0:
173                     # Get map of variables in calldata, with thier offsets
174                     offset = 4
175                     calldata_offset_map = {}
176                     for arg in default_sig.args:
177                         calldata_offset_map[arg.name] = offset
178                         offset += (
179                             32
180                             if isinstance(arg.typ, ByteArrayLike)
181                             else get_size_of_type(arg.typ) * 32
182                         )
183 
184                     # Copy default parameters from calldata.
185                     for arg_name in copier_arg_names:
186                         var = context.vars[arg_name]
187                         calldata_offset = calldata_offset_map[arg_name]
188 
189                         # Add clampers.
190                         default_copiers.append(
191                             make_arg_clamper(calldata_offset - 4, var.pos, var.typ,)
192                         )
193                         # Add copying code.
194                         _offset: Union[int, List[Any]] = calldata_offset
195                         if isinstance(var.typ, ByteArrayLike):
196                             _offset = ["add", 4, ["calldataload", calldata_offset]]
197                         default_copiers.append(
198                             get_external_arg_copier(
199                                 memory_dest=var.pos, total_size=var.size * 32, offset=_offset,
200                             )
201                         )
202 
203                     default_copiers.append(0)  # for over arching seq, POP
204 
205                 sig_chain.append(
206                     [
207                         "if",
208                         sig_compare,
209                         [
210                             "seq",
211                             ["seq"] + set_defaults if set_defaults else ["pass"],
212                             ["seq_unchecked"] + default_copiers if default_copiers else ["pass"],
213                             ["goto", function_routine],
214                         ],
215                     ]
216                 )
217 
218             # Function with default parameters.
219             o = LLLnode.from_list(
220                 [
221                     "seq",
222                     sig_chain,
223                     [
224                         "if",
225                         0,  # can only be jumped into
226                         [
227                             "seq",
228                             ["label", function_routine],
229                             ["seq"]
230                             + nonreentrant_pre
231                             + clampers
232                             + [parse_body(c, context) for c in code.body]
233                             + nonreentrant_post
234                             + [["stop"]],
235                         ],
236                     ],
237                 ],
238                 typ=None,
239                 pos=getpos(code),
240             )
241 
242         else:
243             # Function without default parameters.
244             sig_compare, _ = get_sig_statements(sig, getpos(code))
245             o = LLLnode.from_list(
246                 [
247                     "if",
248                     sig_compare,
249                     ["seq"]
250                     + nonreentrant_pre
251                     + clampers
252                     + [parse_body(c, context) for c in code.body]
253                     + nonreentrant_post
254                     + [["stop"]],
255                 ],
256                 typ=None,
257                 pos=getpos(code),
258             )
259     return o
260
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/vyper/parser/function_definitions/parse_external_function.py b/vyper/parser/function_definitions/parse_external_function.py
--- a/vyper/parser/function_definitions/parse_external_function.py
+++ b/vyper/parser/function_definitions/parse_external_function.py
@@ -106,7 +106,8 @@
                     arg.name, MemoryPositions.RESERVED_MEMORY + arg.pos, arg.typ, False,
                 )
             elif i >= default_args_start_pos:  # default args need to be allocated in memory.
-                default_arg_pos, _ = context.memory_allocator.increase_memory(32)
+                type_size = get_size_of_type(arg.typ) * 32
+                default_arg_pos, _ = context.memory_allocator.increase_memory(type_size)
                 context.vars[arg.name] = VariableRecord(
                     name=arg.name, pos=default_arg_pos, typ=arg.typ, mutable=False,
                 )

{"golden_diff": "diff --git a/vyper/parser/function_definitions/parse_external_function.py b/vyper/parser/function_definitions/parse_external_function.py\n--- a/vyper/parser/function_definitions/parse_external_function.py\n+++ b/vyper/parser/function_definitions/parse_external_function.py\n@@ -106,7 +106,8 @@\n                     arg.name, MemoryPositions.RESERVED_MEMORY + arg.pos, arg.typ, False,\n                 )\n             elif i >= default_args_start_pos:  # default args need to be allocated in memory.\n-                default_arg_pos, _ = context.memory_allocator.increase_memory(32)\n+                type_size = get_size_of_type(arg.typ) * 32\n+                default_arg_pos, _ = context.memory_allocator.increase_memory(type_size)\n                 context.vars[arg.name] = VariableRecord(\n                     name=arg.name, pos=default_arg_pos, typ=arg.typ, mutable=False,\n                 )\n", "issue": "Arrays as default arguments do not properly copy to memory\n### Version Information\r\n\r\n* vyper Version: latest master\r\n* OS: linux\r\n* Python Version: 3.8.2\r\n\r\n### What's your issue about?\r\nWhen an array used as a default argument is copied to a memory variable, every item in the memory variable has the value of the first item in the array. For example:\r\n\r\n```python\r\n@public\r\n@constant\r\ndef foo(a: int128[2] = [1, 2]) -> int128[2]:\r\n    b: int128[2] = a\r\n    return b\r\n```\r\n\r\nCalls to `foo` produce the following output:\r\n\r\n```python\r\n>>> x.foo()\r\n(1, 1)\r\n>>> x.foo([4, 6])\r\n(4, 4)\r\n```\r\n\r\n* The same effect is observed with longer arrays and different types.\r\n* Returning directly from calldata gives the expected result.\r\n* Writing to storage gives the expected result.\r\n\n", "before_files": [{"content": "import ast\nfrom typing import Any, List, Union\n\nfrom vyper.exceptions import FunctionDeclarationException\nfrom vyper.parser.arg_clamps import make_arg_clamper\nfrom vyper.parser.context import Context, VariableRecord\nfrom vyper.parser.expr import Expr\nfrom vyper.parser.function_definitions.utils import (\n    get_default_names_to_set,\n    get_nonreentrant_lock,\n    get_sig_statements,\n)\nfrom vyper.parser.global_context import GlobalContext\nfrom vyper.parser.lll_node import LLLnode\nfrom vyper.parser.parser_utils import getpos, make_setter\nfrom vyper.parser.stmt import parse_body\nfrom vyper.signatures import sig_utils\nfrom vyper.signatures.function_signature import FunctionSignature\nfrom vyper.types.types import ByteArrayLike, get_size_of_type\nfrom vyper.utils import MemoryPositions\n\n\ndef get_external_arg_copier(\n    total_size: int, memory_dest: int, offset: Union[int, List[Any]] = 4\n) -> List[Any]:\n    \"\"\"\n    Generate argument copier.\n\n    :param total_size: total memory size to copy\n    :param memory_dest: base memory address to start from\n    :param offset: starting offset, used for ByteArrays\n    \"\"\"\n    copier = [\"calldatacopy\", memory_dest, offset, total_size]\n    return copier\n\n\ndef validate_external_function(\n    code: ast.FunctionDef, sig: FunctionSignature, global_ctx: GlobalContext\n) -> None:\n    \"\"\" Validate external function definition. \"\"\"\n\n    # __init__ function may not have defaults.\n    if sig.is_initializer() and sig.total_default_args > 0:\n        raise FunctionDeclarationException(\n            \"__init__ function may not have default parameters.\", code\n        )\n\n    # Check for duplicate variables with globals\n    for arg in sig.args:\n        if arg.name in global_ctx._globals:\n            raise FunctionDeclarationException(\n                \"Variable name duplicated between \" \"function arguments and globals: \" + arg.name,\n                code,\n            )\n\n\ndef parse_external_function(\n    code: ast.FunctionDef, sig: FunctionSignature, context: Context\n) -> LLLnode:\n    \"\"\"\n    Parse a external function (FuncDef), and produce full function body.\n\n    :param sig: the FuntionSignature\n    :param code: ast of function\n    :return: full sig compare & function body\n    \"\"\"\n\n    validate_external_function(code, sig, context.global_ctx)\n\n    # Get nonreentrant lock\n    nonreentrant_pre, nonreentrant_post = get_nonreentrant_lock(sig, context.global_ctx)\n\n    clampers = []\n\n    # Generate copiers\n    copier: List[Any] = [\"pass\"]\n    if not len(sig.base_args):\n        copier = [\"pass\"]\n    elif sig.name == \"__init__\":\n        copier = [\"codecopy\", MemoryPositions.RESERVED_MEMORY, \"~codelen\", sig.base_copy_size]\n        context.memory_allocator.increase_memory(sig.max_copy_size)\n    clampers.append(copier)\n\n    # Add asserts for payable and internal\n    if sig.mutability != \"payable\":\n        clampers.append([\"assert\", [\"iszero\", \"callvalue\"]])\n\n    # Fill variable positions\n    default_args_start_pos = len(sig.base_args)\n    for i, arg in enumerate(sig.args):\n        if i < len(sig.base_args):\n            clampers.append(\n                make_arg_clamper(\n                    arg.pos,\n                    context.memory_allocator.get_next_memory_position(),\n                    arg.typ,\n                    sig.name == \"__init__\",\n                )\n            )\n        if isinstance(arg.typ, ByteArrayLike):\n            mem_pos, _ = context.memory_allocator.increase_memory(32 * get_size_of_type(arg.typ))\n            context.vars[arg.name] = VariableRecord(arg.name, mem_pos, arg.typ, False)\n        else:\n            if sig.name == \"__init__\":\n                context.vars[arg.name] = VariableRecord(\n                    arg.name, MemoryPositions.RESERVED_MEMORY + arg.pos, arg.typ, False,\n                )\n            elif i >= default_args_start_pos:  # default args need to be allocated in memory.\n                default_arg_pos, _ = context.memory_allocator.increase_memory(32)\n                context.vars[arg.name] = VariableRecord(\n                    name=arg.name, pos=default_arg_pos, typ=arg.typ, mutable=False,\n                )\n            else:\n                context.vars[arg.name] = VariableRecord(\n                    name=arg.name, pos=4 + arg.pos, typ=arg.typ, mutable=False, location=\"calldata\"\n                )\n\n    # Create \"clampers\" (input well-formedness checkers)\n    # Return function body\n    if sig.name == \"__init__\":\n        o = LLLnode.from_list(\n            [\"seq\"] + clampers + [parse_body(code.body, context)],  # type: ignore\n            pos=getpos(code),\n        )\n    # Is default function.\n    elif sig.is_default_func():\n        if len(sig.args) > 0:\n            raise FunctionDeclarationException(\n                \"Default function may not receive any arguments.\", code\n            )\n        o = LLLnode.from_list(\n            [\"seq\"] + clampers + [parse_body(code.body, context)],  # type: ignore\n            pos=getpos(code),\n        )\n    # Is a normal function.\n    else:\n        # Function with default parameters.\n        if sig.total_default_args > 0:\n            function_routine = f\"{sig.name}_{sig.method_id}\"\n            default_sigs = sig_utils.generate_default_arg_sigs(\n                code, context.sigs, context.global_ctx\n            )\n            sig_chain: List[Any] = [\"seq\"]\n\n            for default_sig in default_sigs:\n                sig_compare, _ = get_sig_statements(default_sig, getpos(code))\n\n                # Populate unset default variables\n                set_defaults = []\n                for arg_name in get_default_names_to_set(sig, default_sig):\n                    value = Expr(sig.default_values[arg_name], context).lll_node\n                    var = context.vars[arg_name]\n                    left = LLLnode.from_list(\n                        var.pos,\n                        typ=var.typ,\n                        location=\"memory\",\n                        pos=getpos(code),\n                        mutable=var.mutable,\n                    )\n                    set_defaults.append(make_setter(left, value, \"memory\", pos=getpos(code)))\n\n                current_sig_arg_names = {x.name for x in default_sig.args}\n                base_arg_names = {arg.name for arg in sig.base_args}\n                copier_arg_count = len(default_sig.args) - len(sig.base_args)\n                copier_arg_names = list(current_sig_arg_names - base_arg_names)\n\n                # Order copier_arg_names, this is very important.\n                copier_arg_names = [x.name for x in default_sig.args if x.name in copier_arg_names]\n\n                # Variables to be populated from calldata/stack.\n                default_copiers: List[Any] = []\n                if copier_arg_count > 0:\n                    # Get map of variables in calldata, with thier offsets\n                    offset = 4\n                    calldata_offset_map = {}\n                    for arg in default_sig.args:\n                        calldata_offset_map[arg.name] = offset\n                        offset += (\n                            32\n                            if isinstance(arg.typ, ByteArrayLike)\n                            else get_size_of_type(arg.typ) * 32\n                        )\n\n                    # Copy default parameters from calldata.\n                    for arg_name in copier_arg_names:\n                        var = context.vars[arg_name]\n                        calldata_offset = calldata_offset_map[arg_name]\n\n                        # Add clampers.\n                        default_copiers.append(\n                            make_arg_clamper(calldata_offset - 4, var.pos, var.typ,)\n                        )\n                        # Add copying code.\n                        _offset: Union[int, List[Any]] = calldata_offset\n                        if isinstance(var.typ, ByteArrayLike):\n                            _offset = [\"add\", 4, [\"calldataload\", calldata_offset]]\n                        default_copiers.append(\n                            get_external_arg_copier(\n                                memory_dest=var.pos, total_size=var.size * 32, offset=_offset,\n                            )\n                        )\n\n                    default_copiers.append(0)  # for over arching seq, POP\n\n                sig_chain.append(\n                    [\n                        \"if\",\n                        sig_compare,\n                        [\n                            \"seq\",\n                            [\"seq\"] + set_defaults if set_defaults else [\"pass\"],\n                            [\"seq_unchecked\"] + default_copiers if default_copiers else [\"pass\"],\n                            [\"goto\", function_routine],\n                        ],\n                    ]\n                )\n\n            # Function with default parameters.\n            o = LLLnode.from_list(\n                [\n                    \"seq\",\n                    sig_chain,\n                    [\n                        \"if\",\n                        0,  # can only be jumped into\n                        [\n                            \"seq\",\n                            [\"label\", function_routine],\n                            [\"seq\"]\n                            + nonreentrant_pre\n                            + clampers\n                            + [parse_body(c, context) for c in code.body]\n                            + nonreentrant_post\n                            + [[\"stop\"]],\n                        ],\n                    ],\n                ],\n                typ=None,\n                pos=getpos(code),\n            )\n\n        else:\n            # Function without default parameters.\n            sig_compare, _ = get_sig_statements(sig, getpos(code))\n            o = LLLnode.from_list(\n                [\n                    \"if\",\n                    sig_compare,\n                    [\"seq\"]\n                    + nonreentrant_pre\n                    + clampers\n                    + [parse_body(c, context) for c in code.body]\n                    + nonreentrant_post\n                    + [[\"stop\"]],\n                ],\n                typ=None,\n                pos=getpos(code),\n            )\n    return o\n", "path": "vyper/parser/function_definitions/parse_external_function.py"}], "after_files": [{"content": "import ast\nfrom typing import Any, List, Union\n\nfrom vyper.exceptions import FunctionDeclarationException\nfrom vyper.parser.arg_clamps import make_arg_clamper\nfrom vyper.parser.context import Context, VariableRecord\nfrom vyper.parser.expr import Expr\nfrom vyper.parser.function_definitions.utils import (\n    get_default_names_to_set,\n    get_nonreentrant_lock,\n    get_sig_statements,\n)\nfrom vyper.parser.global_context import GlobalContext\nfrom vyper.parser.lll_node import LLLnode\nfrom vyper.parser.parser_utils import getpos, make_setter\nfrom vyper.parser.stmt import parse_body\nfrom vyper.signatures import sig_utils\nfrom vyper.signatures.function_signature import FunctionSignature\nfrom vyper.types.types import ByteArrayLike, get_size_of_type\nfrom vyper.utils import MemoryPositions\n\n\ndef get_external_arg_copier(\n    total_size: int, memory_dest: int, offset: Union[int, List[Any]] = 4\n) -> List[Any]:\n    \"\"\"\n    Generate argument copier.\n\n    :param total_size: total memory size to copy\n    :param memory_dest: base memory address to start from\n    :param offset: starting offset, used for ByteArrays\n    \"\"\"\n    copier = [\"calldatacopy\", memory_dest, offset, total_size]\n    return copier\n\n\ndef validate_external_function(\n    code: ast.FunctionDef, sig: FunctionSignature, global_ctx: GlobalContext\n) -> None:\n    \"\"\" Validate external function definition. \"\"\"\n\n    # __init__ function may not have defaults.\n    if sig.is_initializer() and sig.total_default_args > 0:\n        raise FunctionDeclarationException(\n            \"__init__ function may not have default parameters.\", code\n        )\n\n    # Check for duplicate variables with globals\n    for arg in sig.args:\n        if arg.name in global_ctx._globals:\n            raise FunctionDeclarationException(\n                \"Variable name duplicated between \" \"function arguments and globals: \" + arg.name,\n                code,\n            )\n\n\ndef parse_external_function(\n    code: ast.FunctionDef, sig: FunctionSignature, context: Context\n) -> LLLnode:\n    \"\"\"\n    Parse a external function (FuncDef), and produce full function body.\n\n    :param sig: the FuntionSignature\n    :param code: ast of function\n    :return: full sig compare & function body\n    \"\"\"\n\n    validate_external_function(code, sig, context.global_ctx)\n\n    # Get nonreentrant lock\n    nonreentrant_pre, nonreentrant_post = get_nonreentrant_lock(sig, context.global_ctx)\n\n    clampers = []\n\n    # Generate copiers\n    copier: List[Any] = [\"pass\"]\n    if not len(sig.base_args):\n        copier = [\"pass\"]\n    elif sig.name == \"__init__\":\n        copier = [\"codecopy\", MemoryPositions.RESERVED_MEMORY, \"~codelen\", sig.base_copy_size]\n        context.memory_allocator.increase_memory(sig.max_copy_size)\n    clampers.append(copier)\n\n    # Add asserts for payable and internal\n    if sig.mutability != \"payable\":\n        clampers.append([\"assert\", [\"iszero\", \"callvalue\"]])\n\n    # Fill variable positions\n    default_args_start_pos = len(sig.base_args)\n    for i, arg in enumerate(sig.args):\n        if i < len(sig.base_args):\n            clampers.append(\n                make_arg_clamper(\n                    arg.pos,\n                    context.memory_allocator.get_next_memory_position(),\n                    arg.typ,\n                    sig.name == \"__init__\",\n                )\n            )\n        if isinstance(arg.typ, ByteArrayLike):\n            mem_pos, _ = context.memory_allocator.increase_memory(32 * get_size_of_type(arg.typ))\n            context.vars[arg.name] = VariableRecord(arg.name, mem_pos, arg.typ, False)\n        else:\n            if sig.name == \"__init__\":\n                context.vars[arg.name] = VariableRecord(\n                    arg.name, MemoryPositions.RESERVED_MEMORY + arg.pos, arg.typ, False,\n                )\n            elif i >= default_args_start_pos:  # default args need to be allocated in memory.\n                type_size = get_size_of_type(arg.typ) * 32\n                default_arg_pos, _ = context.memory_allocator.increase_memory(type_size)\n                context.vars[arg.name] = VariableRecord(\n                    name=arg.name, pos=default_arg_pos, typ=arg.typ, mutable=False,\n                )\n            else:\n                context.vars[arg.name] = VariableRecord(\n                    name=arg.name, pos=4 + arg.pos, typ=arg.typ, mutable=False, location=\"calldata\"\n                )\n\n    # Create \"clampers\" (input well-formedness checkers)\n    # Return function body\n    if sig.name == \"__init__\":\n        o = LLLnode.from_list(\n            [\"seq\"] + clampers + [parse_body(code.body, context)],  # type: ignore\n            pos=getpos(code),\n        )\n    # Is default function.\n    elif sig.is_default_func():\n        if len(sig.args) > 0:\n            raise FunctionDeclarationException(\n                \"Default function may not receive any arguments.\", code\n            )\n        o = LLLnode.from_list(\n            [\"seq\"] + clampers + [parse_body(code.body, context)],  # type: ignore\n            pos=getpos(code),\n        )\n    # Is a normal function.\n    else:\n        # Function with default parameters.\n        if sig.total_default_args > 0:\n            function_routine = f\"{sig.name}_{sig.method_id}\"\n            default_sigs = sig_utils.generate_default_arg_sigs(\n                code, context.sigs, context.global_ctx\n            )\n            sig_chain: List[Any] = [\"seq\"]\n\n            for default_sig in default_sigs:\n                sig_compare, _ = get_sig_statements(default_sig, getpos(code))\n\n                # Populate unset default variables\n                set_defaults = []\n                for arg_name in get_default_names_to_set(sig, default_sig):\n                    value = Expr(sig.default_values[arg_name], context).lll_node\n                    var = context.vars[arg_name]\n                    left = LLLnode.from_list(\n                        var.pos,\n                        typ=var.typ,\n                        location=\"memory\",\n                        pos=getpos(code),\n                        mutable=var.mutable,\n                    )\n                    set_defaults.append(make_setter(left, value, \"memory\", pos=getpos(code)))\n\n                current_sig_arg_names = {x.name for x in default_sig.args}\n                base_arg_names = {arg.name for arg in sig.base_args}\n                copier_arg_count = len(default_sig.args) - len(sig.base_args)\n                copier_arg_names = list(current_sig_arg_names - base_arg_names)\n\n                # Order copier_arg_names, this is very important.\n                copier_arg_names = [x.name for x in default_sig.args if x.name in copier_arg_names]\n\n                # Variables to be populated from calldata/stack.\n                default_copiers: List[Any] = []\n                if copier_arg_count > 0:\n                    # Get map of variables in calldata, with thier offsets\n                    offset = 4\n                    calldata_offset_map = {}\n                    for arg in default_sig.args:\n                        calldata_offset_map[arg.name] = offset\n                        offset += (\n                            32\n                            if isinstance(arg.typ, ByteArrayLike)\n                            else get_size_of_type(arg.typ) * 32\n                        )\n\n                    # Copy default parameters from calldata.\n                    for arg_name in copier_arg_names:\n                        var = context.vars[arg_name]\n                        calldata_offset = calldata_offset_map[arg_name]\n\n                        # Add clampers.\n                        default_copiers.append(\n                            make_arg_clamper(calldata_offset - 4, var.pos, var.typ,)\n                        )\n                        # Add copying code.\n                        _offset: Union[int, List[Any]] = calldata_offset\n                        if isinstance(var.typ, ByteArrayLike):\n                            _offset = [\"add\", 4, [\"calldataload\", calldata_offset]]\n                        default_copiers.append(\n                            get_external_arg_copier(\n                                memory_dest=var.pos, total_size=var.size * 32, offset=_offset,\n                            )\n                        )\n\n                    default_copiers.append(0)  # for over arching seq, POP\n\n                sig_chain.append(\n                    [\n                        \"if\",\n                        sig_compare,\n                        [\n                            \"seq\",\n                            [\"seq\"] + set_defaults if set_defaults else [\"pass\"],\n                            [\"seq_unchecked\"] + default_copiers if default_copiers else [\"pass\"],\n                            [\"goto\", function_routine],\n                        ],\n                    ]\n                )\n\n            # Function with default parameters.\n            o = LLLnode.from_list(\n                [\n                    \"seq\",\n                    sig_chain,\n                    [\n                        \"if\",\n                        0,  # can only be jumped into\n                        [\n                            \"seq\",\n                            [\"label\", function_routine],\n                            [\"seq\"]\n                            + nonreentrant_pre\n                            + clampers\n                            + [parse_body(c, context) for c in code.body]\n                            + nonreentrant_post\n                            + [[\"stop\"]],\n                        ],\n                    ],\n                ],\n                typ=None,\n                pos=getpos(code),\n            )\n\n        else:\n            # Function without default parameters.\n            sig_compare, _ = get_sig_statements(sig, getpos(code))\n            o = LLLnode.from_list(\n                [\n                    \"if\",\n                    sig_compare,\n                    [\"seq\"]\n                    + nonreentrant_pre\n                    + clampers\n                    + [parse_body(c, context) for c in code.body]\n                    + nonreentrant_post\n                    + [[\"stop\"]],\n                ],\n                typ=None,\n                pos=getpos(code),\n            )\n    return o\n", "path": "vyper/parser/function_definitions/parse_external_function.py"}]}