prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Can't import interface using structs
  ### Version Information
  
  * vyper Version (output of `vyper --version`): 0.2.12+commit.2c6842c
  * OS: linux
  * Python Version (output of `python --version`): 3.8.5
  * Environment (output of `pip freeze`):
  ```
  asttokens==2.0.4
  pycryptodome==3.10.1
  semantic-version==2.8.5
  six==1.15.0
  vyper==0.2.12
  ```
  
  ### What's your issue about?
  
  Can't import an interface if it uses structs. Simple example:
  
  foo.vy:
  ```
  struct Widget:
          name: String[8]
          count: uint256
  
  widget: Widget
  
  @external
  def show() -> (String[8], uint256):
          return (self.widget.name, self.widget.count)
  
  @external
  def __init__():
          self.widget = Widget({
                  name: "thing",
                  count: 1
          })
  ```
  bar.vy
  ```
  import foo as Foo
  
  @external
  def __init__():
          pass
  ```
  
  Throw both in the same dir.
  
  `vyper foo.vy` results in a successful compilation
  
  `vyper bar.vy` results in:
  ```
  Error compiling: bar.vy
  vyper.exceptions.InvalidType: Invalid base type: Widget
    contract "Foo", line 5:8 
         4
    ---> 5 widget: Widget
    ---------------^
         6
  ```
  
  ### How can it be fixed?
  
  Haven't spent time fixing yet
  
  --- 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/signatures/interface.py`
  Content:
  ```
  1 # TODO does this module not get imported?
  2 
  3 import importlib
  4 import pkgutil
  5 
  6 import vyper.builtin_interfaces
  7 from vyper import ast as vy_ast
  8 from vyper.ast.signatures import sig_utils
  9 from vyper.ast.signatures.function_signature import FunctionSignature
  10 from vyper.exceptions import StructureException
  11 from vyper.old_codegen.global_context import GlobalContext
  12 
  13 
  14 # Populate built-in interfaces.
  15 def get_builtin_interfaces():
  16     interface_names = [x.name for x in pkgutil.iter_modules(vyper.builtin_interfaces.__path__)]
  17     return {
  18         name: extract_sigs(
  19             {
  20                 "type": "vyper",
  21                 "code": importlib.import_module(f"vyper.builtin_interfaces.{name}",).interface_code,
  22             },
  23             name,
  24         )
  25         for name in interface_names
  26     }
  27 
  28 
  29 def abi_type_to_ast(atype, expected_size):
  30     if atype in ("int128", "uint256", "bool", "address", "bytes32"):
  31         return vy_ast.Name(id=atype)
  32     elif atype == "fixed168x10":
  33         return vy_ast.Name(id="decimal")
  34     elif atype in ("bytes", "string"):
  35         # expected_size is the maximum length for inputs, minimum length for outputs
  36         return vy_ast.Subscript(
  37             value=vy_ast.Name(id=atype.capitalize()),
  38             slice=vy_ast.Index(value=vy_ast.Int(value=expected_size)),
  39         )
  40     else:
  41         raise StructureException(f"Type {atype} not supported by vyper.")
  42 
  43 
  44 # Vyper defines a maximum length for bytes and string types, but Solidity does not.
  45 # To maximize interoperability, we internally considers these types to have a
  46 # a length of 1Mb (1024 * 1024 * 1 byte) for inputs, and 1 for outputs.
  47 # Ths approach solves the issue because Vyper allows for an implicit casting
  48 # from a lower length into a higher one.  (@iamdefinitelyahuman)
  49 def mk_full_signature_from_json(abi):
  50     funcs = [func for func in abi if func["type"] == "function"]
  51     sigs = []
  52 
  53     for func in funcs:
  54         args = []
  55         returns = None
  56         for a in func["inputs"]:
  57             arg = vy_ast.arg(
  58                 arg=a["name"],
  59                 annotation=abi_type_to_ast(a["type"], 1048576),
  60                 lineno=0,
  61                 col_offset=0,
  62             )
  63             args.append(arg)
  64 
  65         if len(func["outputs"]) == 1:
  66             returns = abi_type_to_ast(func["outputs"][0]["type"], 1)
  67         elif len(func["outputs"]) > 1:
  68             returns = vy_ast.Tuple(
  69                 elements=[abi_type_to_ast(a["type"], 1) for a in func["outputs"]]
  70             )
  71 
  72         decorator_list = [vy_ast.Name(id="external")]
  73         # Handle either constant/payable or stateMutability field
  74         if ("constant" in func and func["constant"]) or (
  75             "stateMutability" in func and func["stateMutability"] == "view"
  76         ):
  77             decorator_list.append(vy_ast.Name(id="view"))
  78         if ("payable" in func and func["payable"]) or (
  79             "stateMutability" in func and func["stateMutability"] == "payable"
  80         ):
  81             decorator_list.append(vy_ast.Name(id="payable"))
  82 
  83         sig = FunctionSignature.from_definition(
  84             code=vy_ast.FunctionDef(
  85                 name=func["name"],
  86                 args=vy_ast.arguments(args=args),
  87                 decorator_list=decorator_list,
  88                 returns=returns,
  89             ),
  90             custom_structs=dict(),
  91             is_from_json=True,
  92         )
  93         sigs.append(sig)
  94     return sigs
  95 
  96 
  97 def extract_sigs(sig_code, interface_name=None):
  98     if sig_code["type"] == "vyper":
  99         interface_ast = [
  100             i
  101             for i in vy_ast.parse_to_ast(sig_code["code"], contract_name=interface_name)
  102             if isinstance(i, vy_ast.FunctionDef)
  103             or isinstance(i, vy_ast.EventDef)
  104             or (isinstance(i, vy_ast.AnnAssign) and i.target.id != "implements")
  105         ]
  106         global_ctx = GlobalContext.get_global_context(interface_ast)
  107         return sig_utils.mk_full_signature(global_ctx, sig_formatter=lambda x: x)
  108     elif sig_code["type"] == "json":
  109         return mk_full_signature_from_json(sig_code["code"])
  110     else:
  111         raise Exception(
  112             (
  113                 f"Unknown interface signature type '{sig_code['type']}' supplied. "
  114                 "'vyper' & 'json' are supported"
  115             )
  116         )
  117
  ```
  --- 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/signatures/interface.py b/vyper/ast/signatures/interface.py
  --- a/vyper/ast/signatures/interface.py
  +++ b/vyper/ast/signatures/interface.py
  @@ -99,8 +99,20 @@
           interface_ast = [
               i
               for i in vy_ast.parse_to_ast(sig_code["code"], contract_name=interface_name)
  -            if isinstance(i, vy_ast.FunctionDef)
  -            or isinstance(i, vy_ast.EventDef)
  +            # all the nodes visited by ModuleNodeVisitor.
  +            if isinstance(
  +                i,
  +                (
  +                    vy_ast.FunctionDef,
  +                    vy_ast.EventDef,
  +                    vy_ast.StructDef,
  +                    vy_ast.InterfaceDef,
  +                    # parsing import statements at this stage
  +                    # causes issues with recursive imports
  +                    # vy_ast.Import,
  +                    # vy_ast.ImportFrom,
  +                ),
  +            )
               or (isinstance(i, vy_ast.AnnAssign) and i.target.id != "implements")
           ]
           global_ctx = GlobalContext.get_global_context(interface_ast)
  
verification_info: {"golden_diff": "diff --git a/vyper/ast/signatures/interface.py b/vyper/ast/signatures/interface.py\n--- a/vyper/ast/signatures/interface.py\n+++ b/vyper/ast/signatures/interface.py\n@@ -99,8 +99,20 @@\n         interface_ast = [\n             i\n             for i in vy_ast.parse_to_ast(sig_code[\"code\"], contract_name=interface_name)\n-            if isinstance(i, vy_ast.FunctionDef)\n-            or isinstance(i, vy_ast.EventDef)\n+            # all the nodes visited by ModuleNodeVisitor.\n+            if isinstance(\n+                i,\n+                (\n+                    vy_ast.FunctionDef,\n+                    vy_ast.EventDef,\n+                    vy_ast.StructDef,\n+                    vy_ast.InterfaceDef,\n+                    # parsing import statements at this stage\n+                    # causes issues with recursive imports\n+                    # vy_ast.Import,\n+                    # vy_ast.ImportFrom,\n+                ),\n+            )\n             or (isinstance(i, vy_ast.AnnAssign) and i.target.id != \"implements\")\n         ]\n         global_ctx = GlobalContext.get_global_context(interface_ast)\n", "issue": "Can't import interface using structs\n### Version Information\r\n\r\n* vyper Version (output of `vyper --version`): 0.2.12+commit.2c6842c\r\n* OS: linux\r\n* Python Version (output of `python --version`): 3.8.5\r\n* Environment (output of `pip freeze`):\r\n```\r\nasttokens==2.0.4\r\npycryptodome==3.10.1\r\nsemantic-version==2.8.5\r\nsix==1.15.0\r\nvyper==0.2.12\r\n```\r\n\r\n### What's your issue about?\r\n\r\nCan't import an interface if it uses structs. Simple example:\r\n\r\nfoo.vy:\r\n```\r\nstruct Widget:\r\n        name: String[8]\r\n        count: uint256\r\n\r\nwidget: Widget\r\n\r\n@external\r\ndef show() -> (String[8], uint256):\r\n        return (self.widget.name, self.widget.count)\r\n\r\n@external\r\ndef __init__():\r\n        self.widget = Widget({\r\n                name: \"thing\",\r\n                count: 1\r\n        })\r\n```\r\nbar.vy\r\n```\r\nimport foo as Foo\r\n\r\n@external\r\ndef __init__():\r\n        pass\r\n```\r\n\r\nThrow both in the same dir.\r\n\r\n`vyper foo.vy` results in a successful compilation\r\n\r\n`vyper bar.vy` results in:\r\n```\r\nError compiling: bar.vy\r\nvyper.exceptions.InvalidType: Invalid base type: Widget\r\n  contract \"Foo\", line 5:8 \r\n       4\r\n  ---> 5 widget: Widget\r\n  ---------------^\r\n       6\r\n```\r\n\r\n### How can it be fixed?\r\n\r\nHaven't spent time fixing yet\n", "before_files": [{"content": "# TODO does this module not get imported?\n\nimport importlib\nimport pkgutil\n\nimport vyper.builtin_interfaces\nfrom vyper import ast as vy_ast\nfrom vyper.ast.signatures import sig_utils\nfrom vyper.ast.signatures.function_signature import FunctionSignature\nfrom vyper.exceptions import StructureException\nfrom vyper.old_codegen.global_context import GlobalContext\n\n\n# Populate built-in interfaces.\ndef get_builtin_interfaces():\n    interface_names = [x.name for x in pkgutil.iter_modules(vyper.builtin_interfaces.__path__)]\n    return {\n        name: extract_sigs(\n            {\n                \"type\": \"vyper\",\n                \"code\": importlib.import_module(f\"vyper.builtin_interfaces.{name}\",).interface_code,\n            },\n            name,\n        )\n        for name in interface_names\n    }\n\n\ndef abi_type_to_ast(atype, expected_size):\n    if atype in (\"int128\", \"uint256\", \"bool\", \"address\", \"bytes32\"):\n        return vy_ast.Name(id=atype)\n    elif atype == \"fixed168x10\":\n        return vy_ast.Name(id=\"decimal\")\n    elif atype in (\"bytes\", \"string\"):\n        # expected_size is the maximum length for inputs, minimum length for outputs\n        return vy_ast.Subscript(\n            value=vy_ast.Name(id=atype.capitalize()),\n            slice=vy_ast.Index(value=vy_ast.Int(value=expected_size)),\n        )\n    else:\n        raise StructureException(f\"Type {atype} not supported by vyper.\")\n\n\n# Vyper defines a maximum length for bytes and string types, but Solidity does not.\n# To maximize interoperability, we internally considers these types to have a\n# a length of 1Mb (1024 * 1024 * 1 byte) for inputs, and 1 for outputs.\n# Ths approach solves the issue because Vyper allows for an implicit casting\n# from a lower length into a higher one.  (@iamdefinitelyahuman)\ndef mk_full_signature_from_json(abi):\n    funcs = [func for func in abi if func[\"type\"] == \"function\"]\n    sigs = []\n\n    for func in funcs:\n        args = []\n        returns = None\n        for a in func[\"inputs\"]:\n            arg = vy_ast.arg(\n                arg=a[\"name\"],\n                annotation=abi_type_to_ast(a[\"type\"], 1048576),\n                lineno=0,\n                col_offset=0,\n            )\n            args.append(arg)\n\n        if len(func[\"outputs\"]) == 1:\n            returns = abi_type_to_ast(func[\"outputs\"][0][\"type\"], 1)\n        elif len(func[\"outputs\"]) > 1:\n            returns = vy_ast.Tuple(\n                elements=[abi_type_to_ast(a[\"type\"], 1) for a in func[\"outputs\"]]\n            )\n\n        decorator_list = [vy_ast.Name(id=\"external\")]\n        # Handle either constant/payable or stateMutability field\n        if (\"constant\" in func and func[\"constant\"]) or (\n            \"stateMutability\" in func and func[\"stateMutability\"] == \"view\"\n        ):\n            decorator_list.append(vy_ast.Name(id=\"view\"))\n        if (\"payable\" in func and func[\"payable\"]) or (\n            \"stateMutability\" in func and func[\"stateMutability\"] == \"payable\"\n        ):\n            decorator_list.append(vy_ast.Name(id=\"payable\"))\n\n        sig = FunctionSignature.from_definition(\n            code=vy_ast.FunctionDef(\n                name=func[\"name\"],\n                args=vy_ast.arguments(args=args),\n                decorator_list=decorator_list,\n                returns=returns,\n            ),\n            custom_structs=dict(),\n            is_from_json=True,\n        )\n        sigs.append(sig)\n    return sigs\n\n\ndef extract_sigs(sig_code, interface_name=None):\n    if sig_code[\"type\"] == \"vyper\":\n        interface_ast = [\n            i\n            for i in vy_ast.parse_to_ast(sig_code[\"code\"], contract_name=interface_name)\n            if isinstance(i, vy_ast.FunctionDef)\n            or isinstance(i, vy_ast.EventDef)\n            or (isinstance(i, vy_ast.AnnAssign) and i.target.id != \"implements\")\n        ]\n        global_ctx = GlobalContext.get_global_context(interface_ast)\n        return sig_utils.mk_full_signature(global_ctx, sig_formatter=lambda x: x)\n    elif sig_code[\"type\"] == \"json\":\n        return mk_full_signature_from_json(sig_code[\"code\"])\n    else:\n        raise Exception(\n            (\n                f\"Unknown interface signature type '{sig_code['type']}' supplied. \"\n                \"'vyper' & 'json' are supported\"\n            )\n        )\n", "path": "vyper/ast/signatures/interface.py"}], "after_files": [{"content": "# TODO does this module not get imported?\n\nimport importlib\nimport pkgutil\n\nimport vyper.builtin_interfaces\nfrom vyper import ast as vy_ast\nfrom vyper.ast.signatures import sig_utils\nfrom vyper.ast.signatures.function_signature import FunctionSignature\nfrom vyper.exceptions import StructureException\nfrom vyper.old_codegen.global_context import GlobalContext\n\n\n# Populate built-in interfaces.\ndef get_builtin_interfaces():\n    interface_names = [x.name for x in pkgutil.iter_modules(vyper.builtin_interfaces.__path__)]\n    return {\n        name: extract_sigs(\n            {\n                \"type\": \"vyper\",\n                \"code\": importlib.import_module(f\"vyper.builtin_interfaces.{name}\",).interface_code,\n            },\n            name,\n        )\n        for name in interface_names\n    }\n\n\ndef abi_type_to_ast(atype, expected_size):\n    if atype in (\"int128\", \"uint256\", \"bool\", \"address\", \"bytes32\"):\n        return vy_ast.Name(id=atype)\n    elif atype == \"fixed168x10\":\n        return vy_ast.Name(id=\"decimal\")\n    elif atype in (\"bytes\", \"string\"):\n        # expected_size is the maximum length for inputs, minimum length for outputs\n        return vy_ast.Subscript(\n            value=vy_ast.Name(id=atype.capitalize()),\n            slice=vy_ast.Index(value=vy_ast.Int(value=expected_size)),\n        )\n    else:\n        raise StructureException(f\"Type {atype} not supported by vyper.\")\n\n\n# Vyper defines a maximum length for bytes and string types, but Solidity does not.\n# To maximize interoperability, we internally considers these types to have a\n# a length of 1Mb (1024 * 1024 * 1 byte) for inputs, and 1 for outputs.\n# Ths approach solves the issue because Vyper allows for an implicit casting\n# from a lower length into a higher one.  (@iamdefinitelyahuman)\ndef mk_full_signature_from_json(abi):\n    funcs = [func for func in abi if func[\"type\"] == \"function\"]\n    sigs = []\n\n    for func in funcs:\n        args = []\n        returns = None\n        for a in func[\"inputs\"]:\n            arg = vy_ast.arg(\n                arg=a[\"name\"],\n                annotation=abi_type_to_ast(a[\"type\"], 1048576),\n                lineno=0,\n                col_offset=0,\n            )\n            args.append(arg)\n\n        if len(func[\"outputs\"]) == 1:\n            returns = abi_type_to_ast(func[\"outputs\"][0][\"type\"], 1)\n        elif len(func[\"outputs\"]) > 1:\n            returns = vy_ast.Tuple(\n                elements=[abi_type_to_ast(a[\"type\"], 1) for a in func[\"outputs\"]]\n            )\n\n        decorator_list = [vy_ast.Name(id=\"external\")]\n        # Handle either constant/payable or stateMutability field\n        if (\"constant\" in func and func[\"constant\"]) or (\n            \"stateMutability\" in func and func[\"stateMutability\"] == \"view\"\n        ):\n            decorator_list.append(vy_ast.Name(id=\"view\"))\n        if (\"payable\" in func and func[\"payable\"]) or (\n            \"stateMutability\" in func and func[\"stateMutability\"] == \"payable\"\n        ):\n            decorator_list.append(vy_ast.Name(id=\"payable\"))\n\n        sig = FunctionSignature.from_definition(\n            code=vy_ast.FunctionDef(\n                name=func[\"name\"],\n                args=vy_ast.arguments(args=args),\n                decorator_list=decorator_list,\n                returns=returns,\n            ),\n            custom_structs=dict(),\n            is_from_json=True,\n        )\n        sigs.append(sig)\n    return sigs\n\n\ndef extract_sigs(sig_code, interface_name=None):\n    if sig_code[\"type\"] == \"vyper\":\n        interface_ast = [\n            i\n            for i in vy_ast.parse_to_ast(sig_code[\"code\"], contract_name=interface_name)\n            # all the nodes visited by ModuleNodeVisitor.\n            if isinstance(\n                i,\n                (\n                    vy_ast.FunctionDef,\n                    vy_ast.EventDef,\n                    vy_ast.StructDef,\n                    vy_ast.InterfaceDef,\n                    # parsing import statements at this stage\n                    # causes issues with recursive imports\n                    # vy_ast.Import,\n                    # vy_ast.ImportFrom,\n                ),\n            )\n            or (isinstance(i, vy_ast.AnnAssign) and i.target.id != \"implements\")\n        ]\n        global_ctx = GlobalContext.get_global_context(interface_ast)\n        return sig_utils.mk_full_signature(global_ctx, sig_formatter=lambda x: x)\n    elif sig_code[\"type\"] == \"json\":\n        return mk_full_signature_from_json(sig_code[\"code\"])\n    else:\n        raise Exception(\n            (\n                f\"Unknown interface signature type '{sig_code['type']}' supplied. \"\n                \"'vyper' & 'json' are supported\"\n            )\n        )\n", "path": "vyper/ast/signatures/interface.py"}]}