Repository: vyperlang/vyper

Issue:
Return tuple with fixed array fails to compile
### Version Information

* vyper Version (output of `vyper --version`): 0.1.0b9
* Python Version (output of `python --version`): 3.6.0


### What's your issue about?
Trying to return a fixed-size byte array and uint together in a tuple fails to compile.

```python
def getAllPackageIds(
    offset: uint256, limit: uint256
) -> (bytes32[5], uint256):
```

Results in following error:
`Can't return type bytes32[5] as part of tuple`

### How can it be fixed?
Not sure exactly, happy to try it out if someone points me in the right direction. 
According to @fubuloubu ...
> Return tuples should accept static arrays

Functions, Exception: ("Can't return type %s as part of tuple", <class 'vyper.types.types.ListType'>)
I'm working on a sample game to demonstrate some proof of concepts. Including, showing both versions of the contract (Solidity & Vyper) so i can show a comparison of building and usage. 

### What's your issue about?
I'm trying to convert a solidity contract into Vyper. 

Can't seem to return the same bag of values. 

For the following vyper function : 

```
@public
@constant
def getStoryNode(id: uint256) -> (uint256, bytes[256], bytes[256], address, uint256[256]):
    return (self.stories_nodes[id].id, self.stories_nodes[id].title, self.stories_nodes[id].body, self.stories_nodes[id].owner, self.stories_nodes[id].childNodesIds)
```

I get the following error when compiling the contract: 
`Exception: ("Can't return type %s as part of tuple", <class 'vyper.types.types.ListType'>)`


Solidity Version : 
```
  /**
  * Returns node's id, title, body, owner's address
  */
  function getStoryNode(uint id) public view returns(uint, string, string, address, uint[]) {
      StoryNode storage node = storiesNodes[id];
      return (node.id, node.title, node.body, node.owner, node.childNodesIds);
  }
```

### How can it be fixed?

Can stmt.py::parse_return be improved to handle this? Maybe i can do do this myself and submit PR. 

### Extra related questions:

Unless i missed something in the docs... strings & dynamically sized mappings aren't a thing, right? 

#### Cute Animal Picture

![lmgsz8bj28a11](https://user-images.githubusercontent.com/1436105/42762314-edd0fc56-8907-11e8-9891-38add85cf89a.jpg)




Discussion:
### Quick Suggestion
 First of all, from the looks of it there are ongoing issues with settling on a proper representation for the `bytes32` type, see [this issue here](https://github.com/ethereum/vyper/issues/1088). For your use, have you considered switching types to `bytes[32][5]` or something similar as a workaround?

### In-Depth Look
Looking through src and experimenting with this myself, there are a few things that stand out:

The following code snippets compile:
```Python
def dummy(valA: bytes32, valB: bytes32) -> (bytes32, bytes32):
  return (valA, valB)
```
```Python
def dummy(valA: string[5], valB: bytes32) -> (string[5], bytes32):
  return (valA, valB)
```
```Python
def dummy(valA: bytes[32], valB: bytes32) -> (bytes[32], bytes32):
  return (valA, valB)
```

However, the following code:
```Python
def dummy(valA: bytes32, valB: bytes32) -> (bytes32[5], bytes32):
  return (valA, valB)
```
Produces:
```Shell
vyper.exceptions.TypeMismatchException: line _: Trying to return tuple type (bytes32, bytes32), output expecting bytes32
  return (valA, valB)
----------^
```

It seems to me like this is something that should be caught in the function header. The author also has a similar thought [here](https://github.com/ethereum/vyper/blob/master/vyper/parser/parser_utils.py#L1024), from `vyper/parser/parser_utils.py` L1024:
```Python
# Maybe this should panic because the type error should be
# caught at an earlier type-checking stage.
raise TypeMismatchException("Can't return type %s as part of tuple" % arg.typ, stmt)
```
### Other Issues
It seems strange that `def dummy(val: bytes32) -> (bytes32):` evaluated to a return type of `bytes32`. I don't think single-item tuples should be allowed but this is an issue for a different time.
Also, the following snippet:
```Python
def dummy(valA: bytes32, valB: bytes32) -> (bytes32[5], bytes32):
  return (valA, valB)
```
Produces the following error:
```Python
Tuple return type does not match annotated return. <class 'vyper.types.types.BaseType'> != <class 'vyper.types.types.ListType'>
```
It does not seem correct that `bytes32[5]` should be classified as a `ListType`, when there is a perfectly good [`ByteArrayType`](https://github.com/ethereum/vyper/blob/master/vyper/types/types.py#L165) to use. This seems to be an issue with `types.py` L458 [here](https://github.com/ethereum/vyper/blob/master/vyper/types/types.py#L458). I am also not sure whether `bytes32` is meant to be a `BaseType`. FYI `bytes[5]` is (correctly) classified as a `ByteArrayType`.
I think this is a dup of https://github.com/ethereum/vyper/issues/955 (also related: https://github.com/ethereum/vyper/issues/1200).

Note that `bytes[32]` and `bytes32` are different types. The former is a dynamic(-length) type, and the latter corresponds to a native EVM word. By the same token, `bytes32[5]` is not the same as `bytes[160]`.

> This seems to be an issue with types.py L458 here.

That's a good catch, that should probably be a specific case, and then the catch-all case should panic.
> That's a good catch, that should probably be a specific case, and then the catch-all case should panic.

On second look actually I think the code is correct. ListType is the most general type that can describe `foo_type[N]`.
Thanks for the suggestion @nzoghb - Tried it out and received `Exception: List of byte arrays not allowed`
Just tried this:
```python
b: bytes32[5] 
@public 
def getAllPackageIds( 
    offset: uint256, limit: uint256 
) -> (bytes32[5], uint256): 
    return (self.b, 1) 
```
This returns (confusingly):
```
TypeMismatchException: line 7:4 Invalid type for array index: None
```
Hey looks like this should have been fixed in the ABI refactoring I did but the problem was moved instead of fixed. Looking into this now.
As long as it's a fixed size list this should be do-able yes. :+1: Tagging as a bug.
@ehanoc could you please test this again, I believe this has been fixed with additional tuple work.
@jacqueswww I wrote a couple small tests to check. 

The string vs bytes[] fixes the issues with string types.

Although there could be an issue with int [] as part of the tuple.

```
@public
def foo() -> (uint256, uint256[2]):
    return (0, [0, 1])

```

Output:

```
            else:
                # Maybe this should panic because the type error should be
                # caught at an earlier type-checking stage.
>               raise TypeMismatchException("Can't return type %s as part of tuple" % arg.typ, stmt)
E               vyper.exceptions.TypeMismatchException: line 15: Can't return type int128[2] as part of tuple
E                   return (0, [0, 1])
E               ----^

vyper/parser/parser_utils.py:681: TypeMismatchException
```

Is this an issue? I might be missing something
Thanks for testing, will have a look ;)
Related to #1019.

Resolving patch:
diff --git a/vyper/codegen/abi.py b/vyper/codegen/abi.py
--- a/vyper/codegen/abi.py
+++ b/vyper/codegen/abi.py
@@ -301,7 +301,7 @@ def o_list(lll_node, pos=None):
             ret = lll_node.args
         else:
             ks = lll_t.tuple_keys() if isinstance(lll_t, TupleLike) else \
-                    [LLLnode.from_list(i) for i in range(lll_t.count)]
+                    [LLLnode.from_list(i, 'uint256') for i in range(lll_t.count)]
 
             ret = [add_variable_offset(lll_node, k, pos, array_bounds_check=False)
                    for k in ks]


Test patch: