We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
External Call to Struct not working
### Version Information

* vyper Version (output of `vyper --version`): 0.1.0b8
* OS: osx
* Python Version (output of `python --version`): 3.7.1

### What's your issue about?

I am unable to interact with structs in 1 contract (let’s call it contract A) that I get as a return value from a function in another contract (let’s call it contract B).

For example, I’m defining the struct in both contract A and B as follows:

```
struct Model:
    x: timedelta
    y: uint256
```

The function (in contract B) that returns the struct is this:

```
@public
@constant
def getModel(_model: address) -> Model:
    return self.models[_model]
```

I can pull it into contract A like this and have it compile successfully:

```
contract B:
    def getModel(_model: address) -> Model: constant
```

But when I try to interact with the members of the struct (i.e. x and y), like this:

```
m: uint256 = B(self.b).getModel(self.model).y
```

I get a compilation error saying `Invalid output type: struct`. Any idea why this would be happening (why it would compile fine when declaring the contract at the top but failing in the function body)?


--- 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/external_call.py`
Content:
```
1 import ast
2 
3 from vyper.exceptions import (
4     FunctionDeclarationException,
5     StructureException,
6     TypeMismatchException,
7     VariableDeclarationException,
8 )
9 from vyper.parser.lll_node import (
10     LLLnode,
11 )
12 from vyper.parser.parser_utils import (
13     getpos,
14     pack_arguments,
15     unwrap_location,
16 )
17 from vyper.types import (
18     BaseType,
19     ByteArrayLike,
20     TupleType,
21     get_size_of_type,
22 )
23 
24 
25 def external_contract_call(node,
26                            context,
27                            contract_name,
28                            contract_address,
29                            pos,
30                            value=None,
31                            gas=None):
32     from vyper.parser.parser import parse_expr
33     if value is None:
34         value = 0
35     if gas is None:
36         gas = 'gas'
37     if not contract_name:
38         raise StructureException(
39             f'Invalid external contract call "{node.func.attr}".',
40             node
41         )
42     if contract_name not in context.sigs:
43         raise VariableDeclarationException(
44             f'Contract "{contract_name}" not declared yet',
45             node
46         )
47     method_name = node.func.attr
48     if method_name not in context.sigs[contract_name]:
49         raise FunctionDeclarationException(
50             (
51                 "Function not declared yet: %s (reminder: "
52                 "function must be declared in the correct contract)"
53                 " The available methods are: %s"
54             ) % (method_name, ",".join(context.sigs[contract_name].keys())),
55             node.func
56         )
57     sig = context.sigs[contract_name][method_name]
58     inargs, inargsize, _ = pack_arguments(
59         sig,
60         [parse_expr(arg, context) for arg in node.args],
61         context,
62         pos=pos,
63     )
64     output_placeholder, output_size, returner = get_external_contract_call_output(sig, context)
65     sub = [
66         'seq',
67         ['assert', ['extcodesize', contract_address]],
68         ['assert', ['ne', 'address', contract_address]],
69     ]
70     if context.is_constant() or sig.const:
71         sub.append([
72             'assert',
73             [
74                 'staticcall',
75                 gas, contract_address, inargs, inargsize, output_placeholder, output_size,
76             ]
77         ])
78     else:
79         sub.append([
80             'assert',
81             [
82                 'call',
83                 gas, contract_address, value, inargs, inargsize, output_placeholder, output_size,
84             ]
85         ])
86     sub.extend(returner)
87     o = LLLnode.from_list(sub, typ=sig.output_type, location='memory', pos=getpos(node))
88     return o
89 
90 
91 def get_external_contract_call_output(sig, context):
92     if not sig.output_type:
93         return 0, 0, []
94     output_placeholder = context.new_placeholder(typ=sig.output_type)
95     output_size = get_size_of_type(sig.output_type) * 32
96     if isinstance(sig.output_type, BaseType):
97         returner = [0, output_placeholder]
98     elif isinstance(sig.output_type, ByteArrayLike):
99         returner = [0, output_placeholder + 32]
100     elif isinstance(sig.output_type, TupleType):
101         returner = [0, output_placeholder]
102     else:
103         raise TypeMismatchException("Invalid output type: %s" % sig.output_type)
104     return output_placeholder, output_size, returner
105 
106 
107 def get_external_contract_keywords(stmt_expr, context):
108     from vyper.parser.expr import Expr
109     value, gas = None, None
110     for kw in stmt_expr.keywords:
111         if kw.arg not in ('value', 'gas'):
112             raise TypeMismatchException(
113                 'Invalid keyword argument, only "gas" and "value" supported.',
114                 stmt_expr,
115             )
116         elif kw.arg == 'gas':
117             gas = Expr.parse_value_expr(kw.value, context)
118         elif kw.arg == 'value':
119             value = Expr.parse_value_expr(kw.value, context)
120     return value, gas
121 
122 
123 def make_external_call(stmt_expr, context):
124     from vyper.parser.expr import Expr
125     value, gas = get_external_contract_keywords(stmt_expr, context)
126 
127     if isinstance(stmt_expr.func, ast.Attribute) and isinstance(stmt_expr.func.value, ast.Call):
128         contract_name = stmt_expr.func.value.func.id
129         contract_address = Expr.parse_value_expr(stmt_expr.func.value.args[0], context)
130 
131         return external_contract_call(
132             stmt_expr,
133             context,
134             contract_name,
135             contract_address,
136             pos=getpos(stmt_expr),
137             value=value,
138             gas=gas,
139         )
140 
141     elif isinstance(stmt_expr.func.value, ast.Attribute) and stmt_expr.func.value.attr in context.sigs:  # noqa: E501
142         contract_name = stmt_expr.func.value.attr
143         var = context.globals[stmt_expr.func.value.attr]
144         contract_address = unwrap_location(LLLnode.from_list(
145             var.pos,
146             typ=var.typ,
147             location='storage',
148             pos=getpos(stmt_expr),
149             annotation='self.' + stmt_expr.func.value.attr,
150         ))
151 
152         return external_contract_call(
153             stmt_expr,
154             context,
155             contract_name,
156             contract_address,
157             pos=getpos(stmt_expr),
158             value=value,
159             gas=gas,
160         )
161 
162     elif isinstance(stmt_expr.func.value, ast.Attribute) and stmt_expr.func.value.attr in context.globals:  # noqa: E501
163         contract_name = context.globals[stmt_expr.func.value.attr].typ.unit
164         var = context.globals[stmt_expr.func.value.attr]
165         contract_address = unwrap_location(LLLnode.from_list(
166             var.pos,
167             typ=var.typ,
168             location='storage',
169             pos=getpos(stmt_expr),
170             annotation='self.' + stmt_expr.func.value.attr,
171         ))
172 
173         return external_contract_call(
174             stmt_expr,
175             context,
176             contract_name,
177             contract_address,
178             pos=getpos(stmt_expr),
179             value=value,
180             gas=gas,
181         )
182 
183     else:
184         raise StructureException("Unsupported operator: %r" % ast.dump(stmt_expr), stmt_expr)
185
```
--- 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/external_call.py b/vyper/parser/external_call.py
--- a/vyper/parser/external_call.py
+++ b/vyper/parser/external_call.py
@@ -17,7 +17,7 @@
 from vyper.types import (
     BaseType,
     ByteArrayLike,
-    TupleType,
+    TupleLike,
     get_size_of_type,
 )
 
@@ -97,7 +97,7 @@
         returner = [0, output_placeholder]
     elif isinstance(sig.output_type, ByteArrayLike):
         returner = [0, output_placeholder + 32]
-    elif isinstance(sig.output_type, TupleType):
+    elif isinstance(sig.output_type, TupleLike):
         returner = [0, output_placeholder]
     else:
         raise TypeMismatchException("Invalid output type: %s" % sig.output_type)

{"golden_diff": "diff --git a/vyper/parser/external_call.py b/vyper/parser/external_call.py\n--- a/vyper/parser/external_call.py\n+++ b/vyper/parser/external_call.py\n@@ -17,7 +17,7 @@\n from vyper.types import (\n     BaseType,\n     ByteArrayLike,\n-    TupleType,\n+    TupleLike,\n     get_size_of_type,\n )\n \n@@ -97,7 +97,7 @@\n         returner = [0, output_placeholder]\n     elif isinstance(sig.output_type, ByteArrayLike):\n         returner = [0, output_placeholder + 32]\n-    elif isinstance(sig.output_type, TupleType):\n+    elif isinstance(sig.output_type, TupleLike):\n         returner = [0, output_placeholder]\n     else:\n         raise TypeMismatchException(\"Invalid output type: %s\" % sig.output_type)\n", "issue": "External Call to Struct not working\n### Version Information\r\n\r\n* vyper Version (output of `vyper --version`): 0.1.0b8\r\n* OS: osx\r\n* Python Version (output of `python --version`): 3.7.1\r\n\r\n### What's your issue about?\r\n\r\nI am unable to interact with structs in 1 contract (let\u2019s call it contract A) that I get as a return value from a function in another contract (let\u2019s call it contract B).\r\n\r\nFor example, I\u2019m defining the struct in both contract A and B as follows:\r\n\r\n```\r\nstruct Model:\r\n    x: timedelta\r\n    y: uint256\r\n```\r\n\r\nThe function (in contract B) that returns the struct is this:\r\n\r\n```\r\n@public\r\n@constant\r\ndef getModel(_model: address) -> Model:\r\n    return self.models[_model]\r\n```\r\n\r\nI can pull it into contract A like this and have it compile successfully:\r\n\r\n```\r\ncontract B:\r\n    def getModel(_model: address) -> Model: constant\r\n```\r\n\r\nBut when I try to interact with the members of the struct (i.e. x and y), like this:\r\n\r\n```\r\nm: uint256 = B(self.b).getModel(self.model).y\r\n```\r\n\r\nI get a compilation error saying `Invalid output type: struct`. Any idea why this would be happening (why it would compile fine when declaring the contract at the top but failing in the function body)?\r\n\n", "before_files": [{"content": "import ast\n\nfrom vyper.exceptions import (\n    FunctionDeclarationException,\n    StructureException,\n    TypeMismatchException,\n    VariableDeclarationException,\n)\nfrom vyper.parser.lll_node import (\n    LLLnode,\n)\nfrom vyper.parser.parser_utils import (\n    getpos,\n    pack_arguments,\n    unwrap_location,\n)\nfrom vyper.types import (\n    BaseType,\n    ByteArrayLike,\n    TupleType,\n    get_size_of_type,\n)\n\n\ndef external_contract_call(node,\n                           context,\n                           contract_name,\n                           contract_address,\n                           pos,\n                           value=None,\n                           gas=None):\n    from vyper.parser.parser import parse_expr\n    if value is None:\n        value = 0\n    if gas is None:\n        gas = 'gas'\n    if not contract_name:\n        raise StructureException(\n            f'Invalid external contract call \"{node.func.attr}\".',\n            node\n        )\n    if contract_name not in context.sigs:\n        raise VariableDeclarationException(\n            f'Contract \"{contract_name}\" not declared yet',\n            node\n        )\n    method_name = node.func.attr\n    if method_name not in context.sigs[contract_name]:\n        raise FunctionDeclarationException(\n            (\n                \"Function not declared yet: %s (reminder: \"\n                \"function must be declared in the correct contract)\"\n                \" The available methods are: %s\"\n            ) % (method_name, \",\".join(context.sigs[contract_name].keys())),\n            node.func\n        )\n    sig = context.sigs[contract_name][method_name]\n    inargs, inargsize, _ = pack_arguments(\n        sig,\n        [parse_expr(arg, context) for arg in node.args],\n        context,\n        pos=pos,\n    )\n    output_placeholder, output_size, returner = get_external_contract_call_output(sig, context)\n    sub = [\n        'seq',\n        ['assert', ['extcodesize', contract_address]],\n        ['assert', ['ne', 'address', contract_address]],\n    ]\n    if context.is_constant() or sig.const:\n        sub.append([\n            'assert',\n            [\n                'staticcall',\n                gas, contract_address, inargs, inargsize, output_placeholder, output_size,\n            ]\n        ])\n    else:\n        sub.append([\n            'assert',\n            [\n                'call',\n                gas, contract_address, value, inargs, inargsize, output_placeholder, output_size,\n            ]\n        ])\n    sub.extend(returner)\n    o = LLLnode.from_list(sub, typ=sig.output_type, location='memory', pos=getpos(node))\n    return o\n\n\ndef get_external_contract_call_output(sig, context):\n    if not sig.output_type:\n        return 0, 0, []\n    output_placeholder = context.new_placeholder(typ=sig.output_type)\n    output_size = get_size_of_type(sig.output_type) * 32\n    if isinstance(sig.output_type, BaseType):\n        returner = [0, output_placeholder]\n    elif isinstance(sig.output_type, ByteArrayLike):\n        returner = [0, output_placeholder + 32]\n    elif isinstance(sig.output_type, TupleType):\n        returner = [0, output_placeholder]\n    else:\n        raise TypeMismatchException(\"Invalid output type: %s\" % sig.output_type)\n    return output_placeholder, output_size, returner\n\n\ndef get_external_contract_keywords(stmt_expr, context):\n    from vyper.parser.expr import Expr\n    value, gas = None, None\n    for kw in stmt_expr.keywords:\n        if kw.arg not in ('value', 'gas'):\n            raise TypeMismatchException(\n                'Invalid keyword argument, only \"gas\" and \"value\" supported.',\n                stmt_expr,\n            )\n        elif kw.arg == 'gas':\n            gas = Expr.parse_value_expr(kw.value, context)\n        elif kw.arg == 'value':\n            value = Expr.parse_value_expr(kw.value, context)\n    return value, gas\n\n\ndef make_external_call(stmt_expr, context):\n    from vyper.parser.expr import Expr\n    value, gas = get_external_contract_keywords(stmt_expr, context)\n\n    if isinstance(stmt_expr.func, ast.Attribute) and isinstance(stmt_expr.func.value, ast.Call):\n        contract_name = stmt_expr.func.value.func.id\n        contract_address = Expr.parse_value_expr(stmt_expr.func.value.args[0], context)\n\n        return external_contract_call(\n            stmt_expr,\n            context,\n            contract_name,\n            contract_address,\n            pos=getpos(stmt_expr),\n            value=value,\n            gas=gas,\n        )\n\n    elif isinstance(stmt_expr.func.value, ast.Attribute) and stmt_expr.func.value.attr in context.sigs:  # noqa: E501\n        contract_name = stmt_expr.func.value.attr\n        var = context.globals[stmt_expr.func.value.attr]\n        contract_address = unwrap_location(LLLnode.from_list(\n            var.pos,\n            typ=var.typ,\n            location='storage',\n            pos=getpos(stmt_expr),\n            annotation='self.' + stmt_expr.func.value.attr,\n        ))\n\n        return external_contract_call(\n            stmt_expr,\n            context,\n            contract_name,\n            contract_address,\n            pos=getpos(stmt_expr),\n            value=value,\n            gas=gas,\n        )\n\n    elif isinstance(stmt_expr.func.value, ast.Attribute) and stmt_expr.func.value.attr in context.globals:  # noqa: E501\n        contract_name = context.globals[stmt_expr.func.value.attr].typ.unit\n        var = context.globals[stmt_expr.func.value.attr]\n        contract_address = unwrap_location(LLLnode.from_list(\n            var.pos,\n            typ=var.typ,\n            location='storage',\n            pos=getpos(stmt_expr),\n            annotation='self.' + stmt_expr.func.value.attr,\n        ))\n\n        return external_contract_call(\n            stmt_expr,\n            context,\n            contract_name,\n            contract_address,\n            pos=getpos(stmt_expr),\n            value=value,\n            gas=gas,\n        )\n\n    else:\n        raise StructureException(\"Unsupported operator: %r\" % ast.dump(stmt_expr), stmt_expr)\n", "path": "vyper/parser/external_call.py"}], "after_files": [{"content": "import ast\n\nfrom vyper.exceptions import (\n    FunctionDeclarationException,\n    StructureException,\n    TypeMismatchException,\n    VariableDeclarationException,\n)\nfrom vyper.parser.lll_node import (\n    LLLnode,\n)\nfrom vyper.parser.parser_utils import (\n    getpos,\n    pack_arguments,\n    unwrap_location,\n)\nfrom vyper.types import (\n    BaseType,\n    ByteArrayLike,\n    TupleLike,\n    get_size_of_type,\n)\n\n\ndef external_contract_call(node,\n                           context,\n                           contract_name,\n                           contract_address,\n                           pos,\n                           value=None,\n                           gas=None):\n    from vyper.parser.parser import parse_expr\n    if value is None:\n        value = 0\n    if gas is None:\n        gas = 'gas'\n    if not contract_name:\n        raise StructureException(\n            f'Invalid external contract call \"{node.func.attr}\".',\n            node\n        )\n    if contract_name not in context.sigs:\n        raise VariableDeclarationException(\n            f'Contract \"{contract_name}\" not declared yet',\n            node\n        )\n    method_name = node.func.attr\n    if method_name not in context.sigs[contract_name]:\n        raise FunctionDeclarationException(\n            (\n                \"Function not declared yet: %s (reminder: \"\n                \"function must be declared in the correct contract)\"\n                \" The available methods are: %s\"\n            ) % (method_name, \",\".join(context.sigs[contract_name].keys())),\n            node.func\n        )\n    sig = context.sigs[contract_name][method_name]\n    inargs, inargsize, _ = pack_arguments(\n        sig,\n        [parse_expr(arg, context) for arg in node.args],\n        context,\n        pos=pos,\n    )\n    output_placeholder, output_size, returner = get_external_contract_call_output(sig, context)\n    sub = [\n        'seq',\n        ['assert', ['extcodesize', contract_address]],\n        ['assert', ['ne', 'address', contract_address]],\n    ]\n    if context.is_constant() or sig.const:\n        sub.append([\n            'assert',\n            [\n                'staticcall',\n                gas, contract_address, inargs, inargsize, output_placeholder, output_size,\n            ]\n        ])\n    else:\n        sub.append([\n            'assert',\n            [\n                'call',\n                gas, contract_address, value, inargs, inargsize, output_placeholder, output_size,\n            ]\n        ])\n    sub.extend(returner)\n    o = LLLnode.from_list(sub, typ=sig.output_type, location='memory', pos=getpos(node))\n    return o\n\n\ndef get_external_contract_call_output(sig, context):\n    if not sig.output_type:\n        return 0, 0, []\n    output_placeholder = context.new_placeholder(typ=sig.output_type)\n    output_size = get_size_of_type(sig.output_type) * 32\n    if isinstance(sig.output_type, BaseType):\n        returner = [0, output_placeholder]\n    elif isinstance(sig.output_type, ByteArrayLike):\n        returner = [0, output_placeholder + 32]\n    elif isinstance(sig.output_type, TupleLike):\n        returner = [0, output_placeholder]\n    else:\n        raise TypeMismatchException(\"Invalid output type: %s\" % sig.output_type)\n    return output_placeholder, output_size, returner\n\n\ndef get_external_contract_keywords(stmt_expr, context):\n    from vyper.parser.expr import Expr\n    value, gas = None, None\n    for kw in stmt_expr.keywords:\n        if kw.arg not in ('value', 'gas'):\n            raise TypeMismatchException(\n                'Invalid keyword argument, only \"gas\" and \"value\" supported.',\n                stmt_expr,\n            )\n        elif kw.arg == 'gas':\n            gas = Expr.parse_value_expr(kw.value, context)\n        elif kw.arg == 'value':\n            value = Expr.parse_value_expr(kw.value, context)\n    return value, gas\n\n\ndef make_external_call(stmt_expr, context):\n    from vyper.parser.expr import Expr\n    value, gas = get_external_contract_keywords(stmt_expr, context)\n\n    if isinstance(stmt_expr.func, ast.Attribute) and isinstance(stmt_expr.func.value, ast.Call):\n        contract_name = stmt_expr.func.value.func.id\n        contract_address = Expr.parse_value_expr(stmt_expr.func.value.args[0], context)\n\n        return external_contract_call(\n            stmt_expr,\n            context,\n            contract_name,\n            contract_address,\n            pos=getpos(stmt_expr),\n            value=value,\n            gas=gas,\n        )\n\n    elif isinstance(stmt_expr.func.value, ast.Attribute) and stmt_expr.func.value.attr in context.sigs:  # noqa: E501\n        contract_name = stmt_expr.func.value.attr\n        var = context.globals[stmt_expr.func.value.attr]\n        contract_address = unwrap_location(LLLnode.from_list(\n            var.pos,\n            typ=var.typ,\n            location='storage',\n            pos=getpos(stmt_expr),\n            annotation='self.' + stmt_expr.func.value.attr,\n        ))\n\n        return external_contract_call(\n            stmt_expr,\n            context,\n            contract_name,\n            contract_address,\n            pos=getpos(stmt_expr),\n            value=value,\n            gas=gas,\n        )\n\n    elif isinstance(stmt_expr.func.value, ast.Attribute) and stmt_expr.func.value.attr in context.globals:  # noqa: E501\n        contract_name = context.globals[stmt_expr.func.value.attr].typ.unit\n        var = context.globals[stmt_expr.func.value.attr]\n        contract_address = unwrap_location(LLLnode.from_list(\n            var.pos,\n            typ=var.typ,\n            location='storage',\n            pos=getpos(stmt_expr),\n            annotation='self.' + stmt_expr.func.value.attr,\n        ))\n\n        return external_contract_call(\n            stmt_expr,\n            context,\n            contract_name,\n            contract_address,\n            pos=getpos(stmt_expr),\n            value=value,\n            gas=gas,\n        )\n\n    else:\n        raise StructureException(\"Unsupported operator: %r\" % ast.dump(stmt_expr), stmt_expr)\n", "path": "vyper/parser/external_call.py"}]}