prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  can't declare variable `public` but can define custom getter
  ### Version Information
  
  * vyper Version:  0.3.4+commit.f31f0ec
  * OS: osx
  * Python Version: 3.8.9
  
  ### What's your issue about?
  
  This code fails to compile:
  
  ```
  slates : public(HashMap[bytes32, DynArray[address, 15]])
  ```
  
  but I can define my own getter for that type just fine:
  
  ```
  slates : HashMap[bytes32, DynArray[address, 15]]
  
  @external
  def slate(sid :bytes32) -> DynArray[address, 15]:
     return self.slates[sid]
  ```
  
  
  --- 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/ast/expansion.py`
  Content:
  ```
  1 import copy
  2 
  3 from vyper import ast as vy_ast
  4 from vyper.exceptions import CompilerPanic
  5 
  6 
  7 def expand_annotated_ast(vyper_module: vy_ast.Module) -> None:
  8     """
  9     Perform expansion / simplification operations on an annotated Vyper AST.
  10 
  11     This pass uses annotated type information to modify the AST, simplifying
  12     logic and expanding subtrees to reduce the compexity during codegen.
  13 
  14     Arguments
  15     ---------
  16     vyper_module : Module
  17         Top-level Vyper AST node that has been type-checked and annotated.
  18     """
  19     generate_public_variable_getters(vyper_module)
  20     remove_unused_statements(vyper_module)
  21 
  22 
  23 def generate_public_variable_getters(vyper_module: vy_ast.Module) -> None:
  24     """
  25     Create getter functions for public variables.
  26 
  27     Arguments
  28     ---------
  29     vyper_module : Module
  30         Top-level Vyper AST node.
  31     """
  32 
  33     for node in vyper_module.get_children(vy_ast.VariableDecl, {"annotation.func.id": "public"}):
  34         func_type = node._metadata["func_type"]
  35         input_types, return_type = func_type.get_signature()
  36         input_nodes = []
  37 
  38         # use the annotation node as a base to build the input args and return type
  39         # starting with `args[0]` to remove the surrounding `public()` call`
  40         annotation = copy.copy(node.annotation.args[0])
  41 
  42         # the base return statement is an `Attribute` node, e.g. `self.<var_name>`
  43         # for each input type we wrap it in a `Subscript` to access a specific member
  44         return_stmt: vy_ast.VyperNode = vy_ast.Attribute(
  45             value=vy_ast.Name(id="self"), attr=func_type.name
  46         )
  47         return_stmt._metadata["type"] = node._metadata["type"]
  48 
  49         for i, type_ in enumerate(input_types):
  50             if not isinstance(annotation, vy_ast.Subscript):
  51                 # if we get here something has failed in type checking
  52                 raise CompilerPanic("Mismatch between node and input type while building getter")
  53             if annotation.value.get("id") == "HashMap":  # type: ignore
  54                 # for a HashMap, split the key/value types and use the key type as the next arg
  55                 arg, annotation = annotation.slice.value.elements  # type: ignore
  56             else:
  57                 # for other types, build an input arg node from the expected type
  58                 # and remove the outer `Subscript` from the annotation
  59                 arg = vy_ast.Name(id=type_._id)
  60                 annotation = annotation.value
  61             input_nodes.append(vy_ast.arg(arg=f"arg{i}", annotation=arg))
  62 
  63             # wrap the return statement in a `Subscript`
  64             return_stmt = vy_ast.Subscript(
  65                 value=return_stmt, slice=vy_ast.Index(value=vy_ast.Name(id=f"arg{i}"))
  66             )
  67 
  68         # after iterating the input types, the remaining annotation node is our return type
  69         return_node = annotation
  70 
  71         # join everything together as a new `FunctionDef` node, annotate it
  72         # with the type, and append it to the existing `Module` node
  73         expanded = vy_ast.FunctionDef.from_node(
  74             node.annotation,
  75             name=func_type.name,
  76             args=vy_ast.arguments(args=input_nodes, defaults=[]),
  77             body=[vy_ast.Return(value=return_stmt)],
  78             decorator_list=[vy_ast.Name(id="external"), vy_ast.Name(id="view")],
  79             returns=return_node,
  80         )
  81         expanded._metadata["type"] = func_type
  82         return_node.set_parent(expanded)
  83         vyper_module.add_to_body(expanded)
  84 
  85 
  86 def remove_unused_statements(vyper_module: vy_ast.Module) -> None:
  87     """
  88     Remove statement nodes that are unused after type checking.
  89 
  90     Once type checking is complete, we can remove now-meaningless statements to
  91     simplify the AST prior to IR generation.
  92 
  93     Arguments
  94     ---------
  95     vyper_module : Module
  96         Top-level Vyper AST node.
  97     """
  98 
  99     # constant declarations - values were substituted within the AST during folding
  100     for node in vyper_module.get_children(vy_ast.VariableDecl, {"annotation.func.id": "constant"}):
  101         vyper_module.remove_from_body(node)
  102 
  103     # `implements: interface` statements - validated during type checking
  104     for node in vyper_module.get_children(vy_ast.AnnAssign, {"target.id": "implements"}):
  105         vyper_module.remove_from_body(node)
  106
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/vyper/ast/expansion.py b/vyper/ast/expansion.py
  --- a/vyper/ast/expansion.py
  +++ b/vyper/ast/expansion.py
  @@ -53,6 +53,9 @@
               if annotation.value.get("id") == "HashMap":  # type: ignore
                   # for a HashMap, split the key/value types and use the key type as the next arg
                   arg, annotation = annotation.slice.value.elements  # type: ignore
  +            elif annotation.value.get("id") == "DynArray":
  +                arg = vy_ast.Name(id=type_._id)
  +                annotation = annotation.slice.value.elements[0]  # type: ignore
               else:
                   # for other types, build an input arg node from the expected type
                   # and remove the outer `Subscript` from the annotation
  @@ -66,7 +69,7 @@
               )
   
           # after iterating the input types, the remaining annotation node is our return type
  -        return_node = annotation
  +        return_node = copy.copy(annotation)
   
           # join everything together as a new `FunctionDef` node, annotate it
           # with the type, and append it to the existing `Module` node
  
verification_info: {"golden_diff": "diff --git a/vyper/ast/expansion.py b/vyper/ast/expansion.py\n--- a/vyper/ast/expansion.py\n+++ b/vyper/ast/expansion.py\n@@ -53,6 +53,9 @@\n             if annotation.value.get(\"id\") == \"HashMap\":  # type: ignore\n                 # for a HashMap, split the key/value types and use the key type as the next arg\n                 arg, annotation = annotation.slice.value.elements  # type: ignore\n+            elif annotation.value.get(\"id\") == \"DynArray\":\n+                arg = vy_ast.Name(id=type_._id)\n+                annotation = annotation.slice.value.elements[0]  # type: ignore\n             else:\n                 # for other types, build an input arg node from the expected type\n                 # and remove the outer `Subscript` from the annotation\n@@ -66,7 +69,7 @@\n             )\n \n         # after iterating the input types, the remaining annotation node is our return type\n-        return_node = annotation\n+        return_node = copy.copy(annotation)\n \n         # join everything together as a new `FunctionDef` node, annotate it\n         # with the type, and append it to the existing `Module` node\n", "issue": "can't declare variable `public` but can define custom getter\n### Version Information\r\n\r\n* vyper Version:  0.3.4+commit.f31f0ec\r\n* OS: osx\r\n* Python Version: 3.8.9\r\n\r\n### What's your issue about?\r\n\r\nThis code fails to compile:\r\n\r\n```\r\nslates : public(HashMap[bytes32, DynArray[address, 15]])\r\n```\r\n\r\nbut I can define my own getter for that type just fine:\r\n\r\n```\r\nslates : HashMap[bytes32, DynArray[address, 15]]\r\n\r\n@external\r\ndef slate(sid :bytes32) -> DynArray[address, 15]:\r\n   return self.slates[sid]\r\n```\r\n\n", "before_files": [{"content": "import copy\n\nfrom vyper import ast as vy_ast\nfrom vyper.exceptions import CompilerPanic\n\n\ndef expand_annotated_ast(vyper_module: vy_ast.Module) -> None:\n    \"\"\"\n    Perform expansion / simplification operations on an annotated Vyper AST.\n\n    This pass uses annotated type information to modify the AST, simplifying\n    logic and expanding subtrees to reduce the compexity during codegen.\n\n    Arguments\n    ---------\n    vyper_module : Module\n        Top-level Vyper AST node that has been type-checked and annotated.\n    \"\"\"\n    generate_public_variable_getters(vyper_module)\n    remove_unused_statements(vyper_module)\n\n\ndef generate_public_variable_getters(vyper_module: vy_ast.Module) -> None:\n    \"\"\"\n    Create getter functions for public variables.\n\n    Arguments\n    ---------\n    vyper_module : Module\n        Top-level Vyper AST node.\n    \"\"\"\n\n    for node in vyper_module.get_children(vy_ast.VariableDecl, {\"annotation.func.id\": \"public\"}):\n        func_type = node._metadata[\"func_type\"]\n        input_types, return_type = func_type.get_signature()\n        input_nodes = []\n\n        # use the annotation node as a base to build the input args and return type\n        # starting with `args[0]` to remove the surrounding `public()` call`\n        annotation = copy.copy(node.annotation.args[0])\n\n        # the base return statement is an `Attribute` node, e.g. `self.<var_name>`\n        # for each input type we wrap it in a `Subscript` to access a specific member\n        return_stmt: vy_ast.VyperNode = vy_ast.Attribute(\n            value=vy_ast.Name(id=\"self\"), attr=func_type.name\n        )\n        return_stmt._metadata[\"type\"] = node._metadata[\"type\"]\n\n        for i, type_ in enumerate(input_types):\n            if not isinstance(annotation, vy_ast.Subscript):\n                # if we get here something has failed in type checking\n                raise CompilerPanic(\"Mismatch between node and input type while building getter\")\n            if annotation.value.get(\"id\") == \"HashMap\":  # type: ignore\n                # for a HashMap, split the key/value types and use the key type as the next arg\n                arg, annotation = annotation.slice.value.elements  # type: ignore\n            else:\n                # for other types, build an input arg node from the expected type\n                # and remove the outer `Subscript` from the annotation\n                arg = vy_ast.Name(id=type_._id)\n                annotation = annotation.value\n            input_nodes.append(vy_ast.arg(arg=f\"arg{i}\", annotation=arg))\n\n            # wrap the return statement in a `Subscript`\n            return_stmt = vy_ast.Subscript(\n                value=return_stmt, slice=vy_ast.Index(value=vy_ast.Name(id=f\"arg{i}\"))\n            )\n\n        # after iterating the input types, the remaining annotation node is our return type\n        return_node = annotation\n\n        # join everything together as a new `FunctionDef` node, annotate it\n        # with the type, and append it to the existing `Module` node\n        expanded = vy_ast.FunctionDef.from_node(\n            node.annotation,\n            name=func_type.name,\n            args=vy_ast.arguments(args=input_nodes, defaults=[]),\n            body=[vy_ast.Return(value=return_stmt)],\n            decorator_list=[vy_ast.Name(id=\"external\"), vy_ast.Name(id=\"view\")],\n            returns=return_node,\n        )\n        expanded._metadata[\"type\"] = func_type\n        return_node.set_parent(expanded)\n        vyper_module.add_to_body(expanded)\n\n\ndef remove_unused_statements(vyper_module: vy_ast.Module) -> None:\n    \"\"\"\n    Remove statement nodes that are unused after type checking.\n\n    Once type checking is complete, we can remove now-meaningless statements to\n    simplify the AST prior to IR generation.\n\n    Arguments\n    ---------\n    vyper_module : Module\n        Top-level Vyper AST node.\n    \"\"\"\n\n    # constant declarations - values were substituted within the AST during folding\n    for node in vyper_module.get_children(vy_ast.VariableDecl, {\"annotation.func.id\": \"constant\"}):\n        vyper_module.remove_from_body(node)\n\n    # `implements: interface` statements - validated during type checking\n    for node in vyper_module.get_children(vy_ast.AnnAssign, {\"target.id\": \"implements\"}):\n        vyper_module.remove_from_body(node)\n", "path": "vyper/ast/expansion.py"}], "after_files": [{"content": "import copy\n\nfrom vyper import ast as vy_ast\nfrom vyper.exceptions import CompilerPanic\n\n\ndef expand_annotated_ast(vyper_module: vy_ast.Module) -> None:\n    \"\"\"\n    Perform expansion / simplification operations on an annotated Vyper AST.\n\n    This pass uses annotated type information to modify the AST, simplifying\n    logic and expanding subtrees to reduce the compexity during codegen.\n\n    Arguments\n    ---------\n    vyper_module : Module\n        Top-level Vyper AST node that has been type-checked and annotated.\n    \"\"\"\n    generate_public_variable_getters(vyper_module)\n    remove_unused_statements(vyper_module)\n\n\ndef generate_public_variable_getters(vyper_module: vy_ast.Module) -> None:\n    \"\"\"\n    Create getter functions for public variables.\n\n    Arguments\n    ---------\n    vyper_module : Module\n        Top-level Vyper AST node.\n    \"\"\"\n\n    for node in vyper_module.get_children(vy_ast.VariableDecl, {\"annotation.func.id\": \"public\"}):\n        func_type = node._metadata[\"func_type\"]\n        input_types, return_type = func_type.get_signature()\n        input_nodes = []\n\n        # use the annotation node as a base to build the input args and return type\n        # starting with `args[0]` to remove the surrounding `public()` call`\n        annotation = copy.copy(node.annotation.args[0])\n\n        # the base return statement is an `Attribute` node, e.g. `self.<var_name>`\n        # for each input type we wrap it in a `Subscript` to access a specific member\n        return_stmt: vy_ast.VyperNode = vy_ast.Attribute(\n            value=vy_ast.Name(id=\"self\"), attr=func_type.name\n        )\n        return_stmt._metadata[\"type\"] = node._metadata[\"type\"]\n\n        for i, type_ in enumerate(input_types):\n            if not isinstance(annotation, vy_ast.Subscript):\n                # if we get here something has failed in type checking\n                raise CompilerPanic(\"Mismatch between node and input type while building getter\")\n            if annotation.value.get(\"id\") == \"HashMap\":  # type: ignore\n                # for a HashMap, split the key/value types and use the key type as the next arg\n                arg, annotation = annotation.slice.value.elements  # type: ignore\n            elif annotation.value.get(\"id\") == \"DynArray\":\n                arg = vy_ast.Name(id=type_._id)\n                annotation = annotation.slice.value.elements[0]  # type: ignore\n            else:\n                # for other types, build an input arg node from the expected type\n                # and remove the outer `Subscript` from the annotation\n                arg = vy_ast.Name(id=type_._id)\n                annotation = annotation.value\n            input_nodes.append(vy_ast.arg(arg=f\"arg{i}\", annotation=arg))\n\n            # wrap the return statement in a `Subscript`\n            return_stmt = vy_ast.Subscript(\n                value=return_stmt, slice=vy_ast.Index(value=vy_ast.Name(id=f\"arg{i}\"))\n            )\n\n        # after iterating the input types, the remaining annotation node is our return type\n        return_node = copy.copy(annotation)\n\n        # join everything together as a new `FunctionDef` node, annotate it\n        # with the type, and append it to the existing `Module` node\n        expanded = vy_ast.FunctionDef.from_node(\n            node.annotation,\n            name=func_type.name,\n            args=vy_ast.arguments(args=input_nodes, defaults=[]),\n            body=[vy_ast.Return(value=return_stmt)],\n            decorator_list=[vy_ast.Name(id=\"external\"), vy_ast.Name(id=\"view\")],\n            returns=return_node,\n        )\n        expanded._metadata[\"type\"] = func_type\n        return_node.set_parent(expanded)\n        vyper_module.add_to_body(expanded)\n\n\ndef remove_unused_statements(vyper_module: vy_ast.Module) -> None:\n    \"\"\"\n    Remove statement nodes that are unused after type checking.\n\n    Once type checking is complete, we can remove now-meaningless statements to\n    simplify the AST prior to IR generation.\n\n    Arguments\n    ---------\n    vyper_module : Module\n        Top-level Vyper AST node.\n    \"\"\"\n\n    # constant declarations - values were substituted within the AST during folding\n    for node in vyper_module.get_children(vy_ast.VariableDecl, {\"annotation.func.id\": \"constant\"}):\n        vyper_module.remove_from_body(node)\n\n    # `implements: interface` statements - validated during type checking\n    for node in vyper_module.get_children(vy_ast.AnnAssign, {\"target.id\": \"implements\"}):\n        vyper_module.remove_from_body(node)\n", "path": "vyper/ast/expansion.py"}]}