Repository: vyperlang/vyper

Issue:
Returning multiple values in a function
### Version Information

* vyper Version: 0.1.0
* OS: 18.04


### What's your issue about?
Unable to set tuples aka #605 

Please include information like:

* full output of the error you received
test_a remains as 100

* what command you ran
checking events emitted using truffle
truffle test

* the code that caused the failure 
```
Creation: event({
    _test_a: uint256
})
test_a : uint256
test_b : uint256
test_c : uint256
test_x : uint256


@public
def __init__():
    self.test_a = 100
    
@public
def test1() -> (uint256, uint256):
    log.Creation(self.test_x)
    return (1,2)

@public
def test():
    (self.test_b, self.test_a) = self.test1()
    log.Creation(self.test_a)
    log.Creation(self.test_b)
```

Test Code:
```
const test = artifacts.require("test");
const assert = require("chai").assert;
const truffleAssert = require('truffle-assertions');

contract("test", (accounts) => {
    let test1;
    const fundingAccount = accounts[0];

    beforeEach(async () => {
        test1 = await test.new({from: fundingAccount});
    });
    
    it("should receive event", async() => {
        let tx = await test1.test();
        truffleAssert.eventEmitted(tx, 'Creation', (ev) => {
            return ev._test_a == 2;
        });
    });
});
```

I am not sure whether I did it wrong but the goal would be to set 2 variables at once.

#### Cute Animal Picture
![image](https://user-images.githubusercontent.com/17759758/50438216-f88ee680-0927-11e9-877b-07fda2e4018b.png)


Returning multiple values in a function
### Version Information

* vyper Version: 0.1.0
* OS: 18.04


### What's your issue about?
Unable to set tuples aka #605 

Please include information like:

* full output of the error you received
test_a remains as 100

* what command you ran
checking events emitted using truffle
truffle test

* the code that caused the failure 
```
Creation: event({
    _test_a: uint256
})
test_a : uint256
test_b : uint256
test_c : uint256
test_x : uint256


@public
def __init__():
    self.test_a = 100
    
@public
def test1() -> (uint256, uint256):
    log.Creation(self.test_x)
    return (1,2)

@public
def test():
    (self.test_b, self.test_a) = self.test1()
    log.Creation(self.test_a)
    log.Creation(self.test_b)
```

Test Code:
```
const test = artifacts.require("test");
const assert = require("chai").assert;
const truffleAssert = require('truffle-assertions');

contract("test", (accounts) => {
    let test1;
    const fundingAccount = accounts[0];

    beforeEach(async () => {
        test1 = await test.new({from: fundingAccount});
    });
    
    it("should receive event", async() => {
        let tx = await test1.test();
        truffleAssert.eventEmitted(tx, 'Creation', (ev) => {
            return ev._test_a == 2;
        });
    });
});
```

I am not sure whether I did it wrong but the goal would be to set 2 variables at once.

#### Cute Animal Picture
![image](https://user-images.githubusercontent.com/17759758/50438216-f88ee680-0927-11e9-877b-07fda2e4018b.png)




Discussion:
Referenced #1113 .

Unable to work ONLY when setting global variables. In-function variables are able to be changed.

```
##...code before

@public
def test():
    c : uint256
    d : uint256
    e : uint256
    d , e = self.test1()
##more code after ....
```
Is able to work but my previous post is still unable to work
Referenced #1113 .

Unable to work ONLY when setting global variables. In-function variables are able to be changed.

```
##...code before

@public
def test():
    c : uint256
    d : uint256
    e : uint256
    d , e = self.test1()
##more code after ....
```
Is able to work but my previous post is still unable to work

Resolving patch:
diff --git a/vyper/parser/parser_utils.py b/vyper/parser/parser_utils.py
--- a/vyper/parser/parser_utils.py
+++ b/vyper/parser/parser_utils.py
@@ -447,6 +447,7 @@ def make_setter(left, right, location, pos, in_function_call=False):
             else:
                 if len(left.typ.members) != len(right.typ.members):
                     raise TypeMismatchException("Tuple lengths don't match, %d vs %d" % (len(left.typ.members), len(right.typ.members)), pos)
+
         left_token = LLLnode.from_list('_L', typ=left.typ, location=left.location)
         if left.location == "storage":
             left = LLLnode.from_list(['sha3_32', left], typ=left.typ, location="storage_prehashed")
@@ -455,26 +456,33 @@ def make_setter(left, right, location, pos, in_function_call=False):
             keyz = list(left.typ.members.keys())
         else:
             keyz = list(range(len(left.typ.members)))
+
+        # If the left side is a literal
+        if left.value == 'multi':
+            locations = [arg.location for arg in left.args]
+        else:
+            locations = [location for _ in keyz]
+
         # If the right side is a literal
         if right.value == "multi":
             if len(right.args) != len(keyz):
                 raise TypeMismatchException("Mismatched number of elements", pos)
             subs = []
-            for i, typ in enumerate(keyz):
-                subs.append(make_setter(add_variable_offset(left_token, typ, pos=pos), right.args[i], location, pos=pos))
+            for i, (typ, loc) in enumerate(zip(keyz, locations)):
+                subs.append(make_setter(add_variable_offset(left_token, typ, pos=pos), right.args[i], loc, pos=pos))
             return LLLnode.from_list(['with', '_L', left, ['seq'] + subs], typ=None)
         # If the right side is a null
         elif isinstance(right.typ, NullType):
             subs = []
-            for typ in keyz:
-                subs.append(make_setter(add_variable_offset(left_token, typ, pos=pos), LLLnode.from_list(None, typ=NullType()), location, pos=pos))
+            for typ, loc in zip(keyz, locations):
+                subs.append(make_setter(add_variable_offset(left_token, typ, pos=pos), LLLnode.from_list(None, typ=NullType()), loc, pos=pos))
             return LLLnode.from_list(['with', '_L', left, ['seq'] + subs], typ=None)
         # If tuple assign.
         elif isinstance(left.typ, TupleType) and isinstance(right.typ, TupleType):
             right_token = LLLnode.from_list('_R', typ=right.typ, location="memory")
             subs = []
             static_offset_counter = 0
-            for idx, (left_arg, right_arg) in enumerate(zip(left.args, right.typ.members)):
+            for idx, (left_arg, right_arg, loc) in enumerate(zip(left.args, right.typ.members, locations)):
                 if isinstance(right_arg, ByteArrayLike):
                     RType = ByteArrayType if isinstance(right_arg, ByteArrayType) else StringType
                     offset = LLLnode.from_list(
@@ -488,7 +496,7 @@ def make_setter(left, right, location, pos, in_function_call=False):
                     make_setter(
                         left_arg,
                         offset,
-                        location="memory",
+                        loc,
                         pos=pos
                     )
                 )
@@ -497,11 +505,11 @@ def make_setter(left, right, location, pos, in_function_call=False):
         else:
             subs = []
             right_token = LLLnode.from_list('_R', typ=right.typ, location=right.location)
-            for typ in keyz:
+            for typ, loc in zip(keyz, locations):
                 subs.append(make_setter(
                     add_variable_offset(left_token, typ, pos=pos),
                     add_variable_offset(right_token, typ, pos=pos),
-                    location,
+                    loc,
                     pos=pos
                 ))
             return LLLnode.from_list(['with', '_L', left, ['with', '_R', right, ['seq'] + subs]], typ=None)


Test patch:
diff --git a/tests/parser/functions/test_return_tuple.py b/tests/parser/functions/test_return_tuple.py
--- a/tests/parser/functions/test_return_tuple.py
+++ b/tests/parser/functions/test_return_tuple.py
@@ -104,18 +104,34 @@ def test_return_tuple_assign_storage(get_contract_with_gas_estimation):
 
 @public
 def out_literals() -> (int128, bytes[20], address, bytes[20]):
-    return 1, b"testtesttest", 0x0000000000000000000000000000000000000000, b"random"
+    return 1, b"testtesttest", 0x0000000000000000000000000000000000000023, b"random"
 
 
 @public
-def test() -> (int128, bytes[20], address, bytes[20]):
+def test1() -> (int128, bytes[20], address, bytes[20]):
     self.a, self.c, self.b, self.d = self.out_literals()
     return self.a, self.c, self.b, self.d
+
+@public
+def test2() -> (int128, address):
+    x: int128
+    x, self.c, self.b, self.d = self.out_literals()
+    return x, self.b
+
+@public
+def test3() -> (address, int128):
+    x: address
+    self.a, self.c, x, self.d = self.out_literals()
+    return x, self.a
     """
 
     c = get_contract_with_gas_estimation(code)
 
-    assert c.out_literals() == [1, b"testtesttest", None, b"random"]
+    addr = '0x' + '00' * 19 + '23'
+    assert c.out_literals() == [1, b"testtesttest", addr, b"random"]
+    assert c.out_literals() == c.test1()
+    assert c.test2() == [1, c.out_literals()[2]]
+    assert c.test3() == [c.out_literals()[2], 1]
 
 
 def test_tuple_return_typecheck(assert_tx_failed, get_contract_with_gas_estimation):