Repository: vyperlang/vyper

Issue:
VIP: Specify behavior of uninitialized variables
## Simple Summary
Require newly declared variables to be initialized.

## Abstract

## Motivation
Uninitialized variables can currently refer to garbage memory (https://github.com/ethereum/vyper/issues/1476#issuecomment-503619359). Probably not what people expect.

## Specification
option 1) Require variables to be set by the programmer
option 2) if the programmer declares a new variable without setting it, auto set it to a default value of 0

EDIT: the eventual consensus was to choose option 1. See https://github.com/ethereum/vyper/issues/1493#issuecomment-505672915 for the rationale.

## Backwards Compatibility
Programs which don't initialize variables will no longer compile.

## Dependencies
Modifies existing behavior of creating new memory variables

## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/)



Discussion:
This shouldn't be happening. I assume this is happening after calls to private functions? (ie. a variable get defined after a private call) :/
Even if it shouldn't be happening, IMO (1) is the best way to mitigate a mistake in calling code or whatever.
Yes, the compiler should have a flag that adds mstore <var_pos> 0 to memory after a variable is created, the flag is only set after a self call to private occurs.
That... Seems way more complicated then just enforcing you set a local on definition if it is not set before it's read.
My 2¢: Also seems to me that (1) makes it the most explicit as to what is going on / less error prone.
I feel like there are two separate problems here, one is changing how vyper currently works to be more explicit about initial values. 
The other is that currently vyper has default assignment of initial values, but after changing to `CALL` the default values of the EVM are not zero by default in memory, as it was before.


I am leaning towards having the programmer explicitly set it. Then they don't have to depend on what the language decides as the default value. Also, there isn't much reason to not initialize a variable - most of the time, the programmer wants to set it at some point in the function. The main use case I can think of is when a programmer defines a variable, and then the value assigned to it is branch dependent. That's a kind of 'edge case' that we could discuss separately (maybe worth implementing something like the balanced return checker but for setting variables) but in any case it is still clearer to set it to a sentinel value at declaration! As a secondary concern, since declared variables are usually assigned to, it's better performance to skip the compiler generated mstore 0 and go straight to assigning whatever the programmer was planning to assign to it.
Yeah definitely are two problems at play @jacqueswww, so we may want to update the issues to more accurately reflect that. 

On the note of the first problem though, I think I'd be in favor of a VIP that makes Vyper more explicit about initial values. 

That may warrant more discussion though that just fixing the currently broken behavior of how the initial values are _supposed_ to behave.
Thinking about this more, fixing the current broken behavior seems higher priority change than removing default initial values, as the later would be non backwards compatible. 

Especially given this is explicitly marked to be the case in the docs: https://vyper.readthedocs.io/en/v0.1.0-beta.10/types.html#initial-values

Still, I'd be in favor of a VIP that removes default initial values and requires them to be set by the programmer. 😅 
One thing to note about the suggestion to require the developer to set a variable before reading it: it doesn't _have_ to be at creation of the variable, but it should be set before it's read (aka write once before read). That would allow the use case @charlescooper was describing with dependent settings.
@fubuloubu Re: Setting var values before read.  That would waste gas in the case that the variable is set to zero intially since all memory is well-defined initially as zero.  Also, as @jacqueswww described it to me, if the internal call context storage is working correctly, even uninitialized zero values will be explicitly copied to memory and then restored later when the internal call returns.  So maybe it's actually the case that there's a bug in the context storage mechanism for internal calls?

It's a bit hard to tell if anyone is suggesting this, but I wouldn't want to insert extra ops meant to zero-out memory when, as far as we know, the internal call context storage mechanism should be preserving variable values across calls, even if those values were uninitialized zero values.  We should instead try to figure out why our mental model of what should be happening isn't matching up with what actually happens.

However, I'm all in favor of requiring that variables syntactically have an initial value.  But if that initial value is zero, we shouldn't do any extra work that doesn't need to happen.  Having new memory set to zero is a detail of the EVM spec (it's not a Vyper language feature) and is not likely to change.
@davesque Yeah that's a good point that if we make a VIP around values needing initial values to be explicitly set by the programmer when implementing we are sure to have a compile-time optimization that doesn't add extra ops if the default value is just 0.
@davesque it has to do with when a private function has a larger frame than the caller, and a variable is declared after the private function call.

```python
@private
def priv(): # frame is > 30 words
    xs: uint256[30]
    for i in range(0, 30):
        xs[i] = 7 # write values to memory

@public
def caller() -> uint256: # frame is < 10 words
    self.priv()
    x: uint256 # looks like should be zero, but it's occupying space that was written to by priv()
    return x # not 0
```
@charles-cooper @jacqueswww 

Okay, yeah that seems correct.

I've been looking into this for an hour or two and here's my current understanding of this:

Variable records are only created as assignment statements are encountered in the code.  However, the private call builder just uses whatever variables it finds in the context to copy local vars to the stack and pop them off.  For variable assignments with explicit values that occur after private calls, this isn't a problem since the value will always be set at the appropriate location in memory.  However, for uninitialized variable assignments, it will just use whatever memory was not written over by the frame recovery which will be junk values from the callee's frame if that frame was larger than the caller's frame.

So it seems like, ideally, the compiler would be aware of all assignment statements in the caller's scope and include them all (including implicit, uninitialized zero values) when copying the caller's frame to the stack.  Or, it would have to zero-out memory for uninitialized variables after any private call, because how could it otherwise know whether or not the private call had written beyond the caller's frame in memory?  I guess it's a question of whether copying all local vars to the stack (including ones that haven't even been used yet) would be more expensive than zeroing out memory for uninitialized vars that occur after private calls.  My guess is that zeroing-out memory would be less expensive.

Sorry if any of this is redundant.  Partially, I'm writing this all down here so you guys can tell me if I'm on the right track with my thinking and also just in case any of this is novel to the discussion.
@jacqueswww Is there any point in time at which we would start asking whether or not doing private calls with our own stack discipline is worth it over just using an EVM opcode?  I'm not keenly aware of the gas costs involved but just though I'd pose the question.
@davesque there is an issue on this, basically vyper used to use CALL to self but that was too expensive. There might be a couple more options if EIPs 615 or 1380 are merged in the next fork so we want to keep from making too large of an overhaul right now before we have all options at our disposal.
FWIW I really think the best course of action at this stage is to get rid of declaring variables without initialization. Technically it's not fixing the bug but it's simpler for the compiler and cleaner for the user for the reasons detailed above. 
@charles-cooper Yeah, I was aware that we used to do it that way.  I was more asking if we should ever revert back to using that approach.  But I forgot about those EIPs.  Thanks!

And yeah I think you're right about requiring explicit assignment.  I'm not sure there's a viable alternative.  The one exception I can think of is if the assignment is the default value for a type and it occurs in a public call, before any private calls.  Then we should be able to safely optimize out the `mstore <pos> 0`.  Otherwise, I'm not sure we can make that assumption.
@davesque @charles-cooper thanks for the elaboration/conversation here, it's helped me understand the underlying issue a lot more

Given the above, I agree with your approach @charles-cooper that the faster path to implementation is likely just removing uninitialized variables + making them explicit.
Given how unexpected & potentially critical this behaviour is, I'd like to just add a reminder that it is still not reflected in the documentation (https://vyper.readthedocs.io/en/latest/types.html#initial-values). I think a short note would already help a lot

Resolving patch:
diff --git a/vyper/functions/functions.py b/vyper/functions/functions.py
--- a/vyper/functions/functions.py
+++ b/vyper/functions/functions.py
@@ -1201,7 +1201,7 @@ def sqrt(expr, args, kwargs, context):
     arg = args[0]
     sqrt_code = """
 assert x >= 0.0
-z: decimal
+z: decimal = 0.0
 
 if x == 0.0:
     z = 0.0
diff --git a/vyper/parser/expr.py b/vyper/parser/expr.py
--- a/vyper/parser/expr.py
+++ b/vyper/parser/expr.py
@@ -55,13 +55,14 @@
 
 # var name: (lllnode, type)
 BUILTIN_CONSTANTS = {
-    'EMPTY_BYTES32': (0, 'bytes32'),
-    'ZERO_ADDRESS': (0, 'address'),
-    'MAX_INT128': (SizeLimits.MAXNUM, 'int128'),
-    'MIN_INT128': (SizeLimits.MINNUM, 'int128'),
-    'MAX_DECIMAL': (SizeLimits.MAXDECIMAL, 'decimal'),
-    'MIN_DECIMAL': (SizeLimits.MINDECIMAL, 'decimal'),
-    'MAX_UINT256': (SizeLimits.MAX_UINT256, 'uint256'),
+    'EMPTY_BYTES32': (0, 'bytes32', None),
+    'ZERO_ADDRESS': (0, 'address', None),
+    'MAX_INT128': (SizeLimits.MAXNUM, 'int128', None),
+    'MIN_INT128': (SizeLimits.MINNUM, 'int128', None),
+    'MAX_DECIMAL': (SizeLimits.MAXDECIMAL, 'decimal', None),
+    'MIN_DECIMAL': (SizeLimits.MINDECIMAL, 'decimal', None),
+    'MAX_UINT256': (SizeLimits.MAX_UINT256, 'uint256', None),
+    'ZERO_WEI': (0, 'uint256', {'wei': 1}),
 }
 
 ENVIRONMENT_VARIABLES = (
@@ -257,10 +258,10 @@ def variables(self):
             )
 
         elif self.expr.id in BUILTIN_CONSTANTS:
-            obj, typ = BUILTIN_CONSTANTS[self.expr.id]
+            obj, typ, unit = BUILTIN_CONSTANTS[self.expr.id]
             return LLLnode.from_list(
                 [obj],
-                typ=BaseType(typ, None, is_literal=True),
+                typ=BaseType(typ, unit, is_literal=True),
                 pos=getpos(self.expr))
         elif self.context.constants.ast_is_constant(self.expr):
             return self.context.constants.get_constant(self.expr.id, self.context)
diff --git a/vyper/parser/stmt.py b/vyper/parser/stmt.py
--- a/vyper/parser/stmt.py
+++ b/vyper/parser/stmt.py
@@ -203,41 +203,45 @@ def ann_assign(self):
             varname = self.stmt.target.id
             pos = self.context.new_variable(varname, typ)
             o = LLLnode.from_list('pass', typ=None, pos=pos)
-            if self.stmt.value is not None:
-                sub = Expr(self.stmt.value, self.context).lll_node
+            if self.stmt.value is None:
+                raise StructureException(
+                    'New variables must be initialized explicitly',
+                    self.stmt)
 
-                # Disallow assignment to None
-                if isinstance(sub.typ, NullType):
-                    raise InvalidLiteralException(
-                        (
-                            'Assignment to None is not allowed, use a default '
-                            'value or built-in `clear()`.'
-                        ),
-                        self.stmt
-                    )
+            sub = Expr(self.stmt.value, self.context).lll_node
 
-                is_valid_bytes32_assign = (
-                    isinstance(sub.typ, ByteArrayType) and sub.typ.maxlen == 32
-                ) and isinstance(typ, BaseType) and typ.typ == 'bytes32'
+            # Disallow assignment to None
+            if isinstance(sub.typ, NullType):
+                raise InvalidLiteralException(
+                    (
+                        'Assignment to None is not allowed, use a default '
+                        'value or built-in `clear()`.'
+                    ),
+                    self.stmt
+                )
 
-                # If bytes[32] to bytes32 assignment rewrite sub as bytes32.
-                if is_valid_bytes32_assign:
-                    sub = LLLnode(
-                        bytes_to_int(self.stmt.value.s),
-                        typ=BaseType('bytes32'),
-                        pos=getpos(self.stmt),
-                    )
+            is_valid_bytes32_assign = (
+                isinstance(sub.typ, ByteArrayType) and sub.typ.maxlen == 32
+            ) and isinstance(typ, BaseType) and typ.typ == 'bytes32'
 
-                self._check_valid_assign(sub)
-                self._check_same_variable_assign(sub)
-                variable_loc = LLLnode.from_list(
-                    pos,
-                    typ=typ,
-                    location='memory',
+            # If bytes[32] to bytes32 assignment rewrite sub as bytes32.
+            if is_valid_bytes32_assign:
+                sub = LLLnode(
+                    bytes_to_int(self.stmt.value.s),
+                    typ=BaseType('bytes32'),
                     pos=getpos(self.stmt),
                 )
-                o = make_setter(variable_loc, sub, 'memory', pos=getpos(self.stmt))
-                # o.pos = getpos(self.stmt) # TODO: Should this be here like in assign()?
+
+            self._check_valid_assign(sub)
+            self._check_same_variable_assign(sub)
+            variable_loc = LLLnode.from_list(
+                pos,
+                typ=typ,
+                location='memory',
+                pos=getpos(self.stmt),
+            )
+            o = make_setter(variable_loc, sub, 'memory', pos=getpos(self.stmt))
+            # o.pos = getpos(self.stmt) # TODO: Should this be here like in assign()?
 
             return o
 


Test patch:
diff --git a/tests/parser/exceptions/test_variable_declaration_exception.py b/tests/parser/exceptions/test_variable_declaration_exception.py
--- a/tests/parser/exceptions/test_variable_declaration_exception.py
+++ b/tests/parser/exceptions/test_variable_declaration_exception.py
@@ -45,13 +45,13 @@ def foo():
 @public
 def foo():
     x = 5
-    x: int128
+    x: int128 = 0
     """,
     """
 @public
 def foo():
-    x: int128
-    x: int128
+    x: int128 = 0
+    x: int128 = 0
     """,
     """
 @public
diff --git a/tests/parser/features/decorators/test_private.py b/tests/parser/features/decorators/test_private.py
--- a/tests/parser/features/decorators/test_private.py
+++ b/tests/parser/features/decorators/test_private.py
@@ -249,7 +249,7 @@ def get_msg() -> (bytes[100]):
 
 @public
 def test() -> (bytes[100]):
-    d: bytes[100]
+    d: bytes[100] = b""
     d = self._test()
     return d
 
@@ -318,7 +318,7 @@ def test(a: bytes32) -> (bytes32, uint256, int128):
     b: uint256 = 1
     c: int128 = 1
     d: int128 = 123
-    f: bytes32
+    f: bytes32 = EMPTY_BYTES32
     f, b, c = self._test(a)
     assert d == 123
     return f, b, c
@@ -349,7 +349,7 @@ def _test_combined(a: bytes[50], x: int128, c:bytes[50]) -> (int128, bytes[100],
 def test(a: int128, b: bytes[40]) -> (int128, bytes[100], bytes[50]):
     c: int128 = 1
     x: bytes[50] = concat(b, b"_one")
-    d: bytes[100]
+    d: bytes[100] = b""
     c, d = self._test(a + c, x)
     return c, d, x
 
@@ -357,7 +357,7 @@ def test(a: int128, b: bytes[40]) -> (int128, bytes[100], bytes[50]):
 def test2(b: bytes[40]) -> (int128, bytes[100]):
     a: int128 = 4
     x: bytes[50] = concat(b, b"_one")
-    d: bytes[100]
+    d: bytes[100] = b""
     return self._test(a, x)
 
 @public
@@ -540,7 +540,7 @@ def change_arr(arr: int128[2]):
     pass
 @public
 def call_arr() -> int128:
-    a: int128[2] # test with zeroed arg
+    a: int128[2] = [0, 0] # test with zeroed arg
     self.change_arr(a)
     return 42
     """
diff --git a/tests/parser/features/decorators/test_public.py b/tests/parser/features/decorators/test_public.py
--- a/tests/parser/features/decorators/test_public.py
+++ b/tests/parser/features/decorators/test_public.py
@@ -9,7 +9,7 @@ def test_invalid_if_both_public_and_internal(assert_compile_failed,
 @public
 @private
 def foo():
-    x = 1
+    x: uint256 = 1
 """
 
     assert_compile_failed(lambda: get_contract_with_gas_estimation(code), StructureException)
@@ -19,7 +19,7 @@ def test_invalid_if_visibility_isnt_declared(assert_compile_failed,
                                              get_contract_with_gas_estimation):
     code = """
 def foo():
-    x = 1
+    x: uint256 = 1
 """
 
     assert_compile_failed(lambda: get_contract_with_gas_estimation(code), StructureException)
diff --git a/tests/parser/features/external_contracts/test_external_contract_calls.py b/tests/parser/features/external_contracts/test_external_contract_calls.py
--- a/tests/parser/features/external_contracts/test_external_contract_calls.py
+++ b/tests/parser/features/external_contracts/test_external_contract_calls.py
@@ -783,9 +783,9 @@ def out_literals() -> (int128, address, bytes[10]) : constant
 
 @public
 def test(addr: address) -> (int128, address, bytes[10]):
-    a: int128
-    b: address
-    c: bytes[10]
+    a: int128 = 0
+    b: address = ZERO_ADDRESS
+    c: bytes[10] = b""
     (a, b, c) = Test(addr).out_literals()
     return a, b,c
 
diff --git a/tests/parser/features/iteration/test_repeater.py b/tests/parser/features/iteration/test_repeater.py
--- a/tests/parser/features/iteration/test_repeater.py
+++ b/tests/parser/features/iteration/test_repeater.py
@@ -16,7 +16,7 @@ def test_digit_reverser(get_contract_with_gas_estimation):
     digit_reverser = """
 @public
 def reverse_digits(x: int128) -> int128:
-    dig: int128[6]
+    dig: int128[6] = [0, 0, 0, 0, 0, 0]
     z: int128 = x
     for i in range(6):
         dig[i] = z % 10
diff --git a/tests/parser/features/test_assignment.py b/tests/parser/features/test_assignment.py
--- a/tests/parser/features/test_assignment.py
+++ b/tests/parser/features/test_assignment.py
@@ -112,7 +112,7 @@ def test_invalid_uin256_assignment_calculate_literals(get_contract_with_gas_esti
 
 @public
 def foo2() -> uint256:
-    x: uint256
+    x: uint256 = 0
     x = 3 * 4 / 2 + 1 - 2
     return x
 """
@@ -125,7 +125,7 @@ def test_calculate_literals_invalid(assert_compile_failed, get_contract_with_gas
     code = """
 @public
 def foo2() -> uint256:
-    x: uint256
+    x: uint256 = 0
     x = 3 ^ 3  # invalid operator
     return x
 """
@@ -198,7 +198,7 @@ def foo():
 @public
 def foo():
     y: int128 = 1
-    z: decimal
+    z: decimal = 0.0
     z = y
 """,
 """
@@ -211,7 +211,7 @@ def foo():
 @public
 def foo():
     y: bool = False
-    z: decimal
+    z: decimal = 0.0
     z = y
 """,
 """
@@ -224,7 +224,7 @@ def foo():
 @public
 def foo():
     y: uint256 = 1
-    z: int128
+    z: int128 = 0
     z = y
 """,
 """
@@ -237,7 +237,7 @@ def foo():
 @public
 def foo():
     y: int128 = 1
-    z: bytes32
+    z: bytes32 = EMPTY_BYTES32
     z = y
 """,
 """
@@ -250,7 +250,7 @@ def foo():
 @public
 def foo():
     y: uint256 = 1
-    z: bytes32
+    z: bytes32 = EMPTY_BYTES32
     z = y
 """
     ]
diff --git a/tests/parser/features/test_internal_call.py b/tests/parser/features/test_internal_call.py
--- a/tests/parser/features/test_internal_call.py
+++ b/tests/parser/features/test_internal_call.py
@@ -191,7 +191,7 @@ def foo1(x: int128[2]) -> int128:
 
 @public
 def bar() -> int128:
-    x: int128[2]
+    x: int128[2] = [0, 0]
     return self._foo0(x)
 
 @public
@@ -272,7 +272,7 @@ def foo1(x: int128[2], y: decimal) -> int128:
 
 @public
 def bar() -> int128:
-    x: int128[2]
+    x: int128[2] = [0, 0]
     return self._foo0(0.3434, x)
 
 # list as second parameter
diff --git a/tests/parser/features/test_packing.py b/tests/parser/features/test_packing.py
--- a/tests/parser/features/test_packing.py
+++ b/tests/parser/features/test_packing.py
@@ -28,10 +28,10 @@ def foo() -> int128:
 
 @public
 def fop() -> int128:
-    _x: int128
-    _y: int128[5]
-    _z: Z
-    _a: int128
+    _x: int128 = 0
+    _y: int128[5] = [0, 0, 0, 0, 0]
+    _z: Z = Z({foo: [0, 0, 0], bar: [Bar({a: 0, b: 0}), Bar({a: 0, b: 0})]})
+    _a: int128 = 0
     _x = 1
     _y[0] = 2
     _y[4] = 4
diff --git a/tests/parser/functions/test_default_parameters.py b/tests/parser/functions/test_default_parameters.py
--- a/tests/parser/functions/test_default_parameters.py
+++ b/tests/parser/functions/test_default_parameters.py
@@ -147,9 +147,9 @@ def callMe() -> (bytes[100], uint256, bytes[20]):
 @public
 def callMeMaybe() -> (bytes[100], uint256, bytes[20]):
     # return self.fooBar(b'here is my number', 555123456, b'baby')
-    a: bytes[100]
-    b: uint256
-    c: bytes[20]
+    a: bytes[100] = b""
+    b: uint256 = 0
+    c: bytes[20] = b""
     a, b, c = self.fooBar(b'here is my number', 555123456, b'baby')
     return a, b, c
     """
diff --git a/tests/parser/functions/test_return_struct.py b/tests/parser/functions/test_return_struct.py
--- a/tests/parser/functions/test_return_struct.py
+++ b/tests/parser/functions/test_return_struct.py
@@ -43,7 +43,7 @@ def pub1() -> Foo:
 
 @private
 def priv2() -> Foo:
-    foo: Foo
+    foo: Foo = Foo({x: 0, y: 0})
     foo.x = 3
     foo.y = 4
     return foo
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
@@ -93,9 +93,9 @@ def out_literals() -> (int128, address, bytes[10]):
 
 @public
 def test() -> (int128, address, bytes[10]):
-    a: int128
-    b: address
-    c: bytes[10]
+    a: int128 = 0
+    b: address = ZERO_ADDRESS
+    c: bytes[10] = b""
     (a, b, c) = self._out_literals()
     return a, b, c
     """
@@ -127,13 +127,13 @@ def test1() -> (int128, bytes[20], address, bytes[20]):
 
 @public
 def test2() -> (int128, address):
-    x: int128
+    x: int128 = 0
     x, self.c, self.b, self.d = self._out_literals()
     return x, self.b
 
 @public
 def test3() -> (address, int128):
-    x: address
+    x: address = ZERO_ADDRESS
     self.a, self.c, x, self.d = self._out_literals()
     return x, self.a
     """
diff --git a/tests/parser/globals/test_setters.py b/tests/parser/globals/test_setters.py
--- a/tests/parser/globals/test_setters.py
+++ b/tests/parser/globals/test_setters.py
@@ -16,15 +16,12 @@ def fop() -> int128:
 
 @public
 def goo() -> int128:
-    goo: int128[3]
-    goo = [1, 2, 3]
+    goo: int128[3] = [1, 2, 3]
     return(goo[0] + goo[1] * 10 + goo[2] * 100)
 
 @public
 def gop() -> int128: # Following a standard naming scheme; nothing to do with the US republican party  # noqa: E501
-    gar: int128[3][3]
-    gar[0] = [1, 2, 3]
-    gar[1] = [4, 5, 6]
+    gar: int128[3][3] = [[1, 2, 3], [4, 5, 6], [0, 0, 0]]
     return gar[0][0] + gar[0][1] * 10 + gar[0][2] * 100 + \
         gar[1][0] * 1000 + gar[1][1] * 10000 + gar[1][2] * 100000
 
@@ -41,16 +38,13 @@ def hop() -> int128:
 
 @public
 def joo() -> int128:
-    goo: int128[3]
-    goo = [1, 2, 3]
+    goo: int128[3] = [1, 2, 3]
     clear(goo)
     return(goo[0] + goo[1] * 10 + goo[2] * 100)
 
 @public
 def jop() -> int128:
-    gar: int128[3][3]
-    gar[0] = [1, 2, 3]
-    gar[1] = [4, 5, 6]
+    gar: int128[3][3] = [[1, 2, 3], [4, 5, 6], [0, 0, 0]]
     clear(gar[1])
     return gar[0][0] + gar[0][1] * 10 + gar[0][2] * 100 + \
         gar[1][0] * 1000 + gar[1][1] * 10000 + gar[1][2] * 100000
@@ -119,10 +113,7 @@ def fop() -> int128:
 
 @public
 def goo() -> int128:
-    goo: Goo[3]
-    goo[0] = Goo({foo: 1, bar: 2})
-    goo[1] = Goo({foo: 3, bar: 4})
-    goo[2] = Goo({foo: 5, bar: 6})
+    goo: Goo[3] = [Goo({foo: 1, bar: 2}), Goo({foo: 3, bar: 4}), Goo({foo: 5, bar: 6})]
     return goo[0].foo + goo[0].bar * 10 + goo[1].foo * 100 + \
         goo[1].bar * 1000 + goo[2].foo * 10000 + goo[2].bar * 100000
 
diff --git a/tests/parser/syntax/test_bool.py b/tests/parser/syntax/test_bool.py
--- a/tests/parser/syntax/test_bool.py
+++ b/tests/parser/syntax/test_bool.py
@@ -46,7 +46,7 @@ def foo() -> bool:
     """
 @public
 def foo() -> bool:
-    a: address
+    a: address = ZERO_ADDRESS
     return a == 1
     """,
     """
@@ -57,19 +57,19 @@ def foo(a: address) -> bool:
     """
 @public
 def foo() -> bool:
-    b: int128
+    b: int128 = 0
     return not b
     """,
     """
 @public
 def foo() -> bool:
-    b: uint256
+    b: uint256 = 0
     return not b
     """,
     """
 @public
 def foo() -> bool:
-    b: uint256
+    b: uint256 = 0
     return not b
     """,
     """
diff --git a/tests/parser/syntax/test_bytes.py b/tests/parser/syntax/test_bytes.py
--- a/tests/parser/syntax/test_bytes.py
+++ b/tests/parser/syntax/test_bytes.py
@@ -15,29 +15,29 @@
     """
 @public
 def baa():
-    x: bytes[50]
-    y: bytes[50]
+    x: bytes[50] = b""
+    y: bytes[50] = b""
     z = x + y
     """,
     """
 @public
 def baa():
-    x: bytes[50]
-    y: int128
+    x: bytes[50] = b""
+    y: int128 = 0
     y = x
     """,
     """
 @public
 def baa():
-    x: bytes[50]
-    y: int128
+    x: bytes[50] = b""
+    y: int128 = 0
     x = y
     """,
     """
 @public
 def baa():
-    x: bytes[50]
-    y: bytes[60]
+    x: bytes[50] = b""
+    y: bytes[60] = b""
     x = y
     """,
     """
@@ -100,7 +100,7 @@ def foo(x: bytes[100]) -> bytes[150]:
     """
 @public
 def baa():
-    x: bytes[50]
+    x: bytes[50] = b""
     """
 ]
 
diff --git a/tests/parser/syntax/test_invalids.py b/tests/parser/syntax/test_invalids.py
--- a/tests/parser/syntax/test_invalids.py
+++ b/tests/parser/syntax/test_invalids.py
@@ -42,7 +42,7 @@ def foo(x: int128): pass
 must_succeed("""
 @public
 def foo():
-    x: int128
+    x: int128 = 0
     x = 5
 """)
 
@@ -153,7 +153,7 @@ def foo():
 must_succeed("""
 @public
 def foo():
-    x: int128[5]
+    x: int128[5] = [0, 0, 0, 0, 0]
     z: int128 = x[2]
 """)
 
diff --git a/tests/parser/syntax/test_list.py b/tests/parser/syntax/test_list.py
--- a/tests/parser/syntax/test_list.py
+++ b/tests/parser/syntax/test_list.py
@@ -118,14 +118,14 @@ def foo():
     """
 @public
 def foo()->bool[2]:
-    a: decimal[2]
+    a: decimal[2] = [0.0, 0.0]
     a[0] = 1
     return a
     """,
     """
 @public
 def foo()->bool[2]:
-    a: bool[1000]
+    a: bool[10] = [True, True, True, True, True, True, True, True, True, True]
     a[0] = 1
     return a
     """,
@@ -234,7 +234,7 @@ def foo():
 b: int128[5]
 @public
 def foo():
-    a: int128[5]
+    a: int128[5] = [0, 0, 0, 0, 0]
     self.b[0] = a[0]
     """,
     """
diff --git a/tests/parser/syntax/test_logging.py b/tests/parser/syntax/test_logging.py
--- a/tests/parser/syntax/test_logging.py
+++ b/tests/parser/syntax/test_logging.py
@@ -24,7 +24,7 @@ def foo():
 
 @public
 def foo():
-    x: decimal[4]
+    x: decimal[4] = [0.0, 0.0, 0.0, 0.0]
     log.Bar(x)
     """,
     """
diff --git a/tests/parser/syntax/test_no_none.py b/tests/parser/syntax/test_no_none.py
--- a/tests/parser/syntax/test_no_none.py
+++ b/tests/parser/syntax/test_no_none.py
@@ -9,37 +9,37 @@ def test_no_none_assign(assert_compile_failed, get_contract_with_gas_estimation)
     """
 @public
 def foo():
-    bar: int128
+    bar: int128 = 0
     bar = None
     """,
     """
 @public
 def foo():
-    bar: uint256
+    bar: uint256 = 0
     bar = None
     """,
     """
 @public
 def foo():
-    bar: bool
+    bar: bool = False
     bar = None
     """,
     """
 @public
 def foo():
-    bar: decimal
+    bar: decimal = 0.0
     bar = None
     """,
     """
 @public
 def foo():
-    bar: bytes32
+    bar: bytes32 = EMPTY_BYTES32
     bar = None
     """,
     """
 @public
 def foo():
-    bar: address
+    bar: address = ZERO_ADDRESS
     bar = None
     """,
     """
@@ -86,37 +86,37 @@ def test_no_is_none(assert_compile_failed, get_contract_with_gas_estimation):
     """
 @public
 def foo():
-    bar: int128
+    bar: int128 = 0
     assert bar is None
     """,
     """
 @public
 def foo():
-    bar: uint256
+    bar: uint256 = 0
     assert bar is None
     """,
     """
 @public
 def foo():
-    bar: bool
+    bar: bool = False
     assert bar is None
     """,
     """
 @public
 def foo():
-    bar: decimal
+    bar: decimal = 0.0
     assert bar is None
     """,
     """
 @public
 def foo():
-    bar: bytes32
+    bar: bytes32 = EMPTY_BYTES32
     assert bar is None
     """,
     """
 @public
 def foo():
-    bar: address
+    bar: address = ZERO_ADDRESS
     assert bar is None
     """
     ]
@@ -133,37 +133,37 @@ def test_no_eq_none(assert_compile_failed, get_contract_with_gas_estimation):
     """
 @public
 def foo():
-    bar: int128
+    bar: int128 = 0
     assert bar == None
     """,
     """
 @public
 def foo():
-    bar: uint256
+    bar: uint256 = 0
     assert bar == None
     """,
     """
 @public
 def foo():
-    bar: bool
+    bar: bool = False
     assert bar == None
     """,
     """
 @public
 def foo():
-    bar: decimal
+    bar: decimal = 0.0
     assert bar == None
     """,
     """
 @public
 def foo():
-    bar: bytes32
+    bar: bytes32 = EMPTY_BYTES32
     assert bar == None
     """,
     """
 @public
 def foo():
-    bar: address
+    bar: address = ZERO_ADDRESS
     assert bar == None
     """
     ]
diff --git a/tests/parser/syntax/test_structs.py b/tests/parser/syntax/test_structs.py
--- a/tests/parser/syntax/test_structs.py
+++ b/tests/parser/syntax/test_structs.py
@@ -439,7 +439,7 @@ def foo():
 nom: C[3]
 @public
 def foo():
-    mom: Mom
+    mom: Mom = Mom({a:[C({c:0}), C({c:0}), C({c:0})], b: 0})
     mom.a = self.nom
     """,
     """
@@ -475,7 +475,7 @@ def foo():
 mom: Mom
 @public
 def foo():
-    nom: C[3]
+    nom: C[3] = [C({c:0}), C({c:0}), C({c:0})]
     self.mom = Mom({a: nom, b: 5})
     """,
     """
diff --git a/tests/parser/syntax/test_timestamp_timedelta.py b/tests/parser/syntax/test_timestamp_timedelta.py
--- a/tests/parser/syntax/test_timestamp_timedelta.py
+++ b/tests/parser/syntax/test_timestamp_timedelta.py
@@ -48,9 +48,8 @@ def foo(x: timedelta, y: timedelta) -> timedelta:
     """,
     """
 @public
-def foo() -> timestamp:
+def foo(y: timestamp) -> timestamp:
     x: int128 = 30
-    y: timestamp
     return x + y
     """,
     """
@@ -139,8 +138,8 @@ def foo(x: timestamp) -> bool:
     """,
     """
 @public
-def foo() -> timestamp:
-    x: timestamp
+def foo(i: timestamp) -> timestamp:
+    x: timestamp = i
     x = 30
     return x
     """,
diff --git a/tests/parser/syntax/test_tuple_assign.py b/tests/parser/syntax/test_tuple_assign.py
--- a/tests/parser/syntax/test_tuple_assign.py
+++ b/tests/parser/syntax/test_tuple_assign.py
@@ -16,9 +16,9 @@
     ("""
 @public
 def test():
-    a: int128
-    b: int128
-    c: int128
+    a: int128 = 0
+    b: int128 = 0
+    c: int128 = 0
     a, b, c = 1, 2, 3
     """, VariableDeclarationException),
     """
@@ -28,8 +28,8 @@ def out_literals() -> (int128, int128, bytes[10]):
 
 @public
 def test() -> (int128, address, bytes[10]):
-    a: int128
-    b: int128
+    a: int128 = 0
+    b: int128 = 0
     a, b, b = self.out_literals()  # incorrect bytes type
     return a, b, c
     """,
@@ -40,8 +40,8 @@ def out_literals() -> (int128, int128, bytes[10]):
 
 @public
 def test() -> (int128, address, bytes[10]):
-    a: int128
-    b: address
+    a: int128 = 0
+    b: address = ZERO_ADDRESS
     a, b = self.out_literals()  # tuple count mismatch
     return
     """,
@@ -52,9 +52,9 @@ def out_literals() -> (int128, int128, int128):
 
 @public
 def test() -> (int128, int128, bytes[10]):
-    a: int128
-    b: int128
-    c: bytes[10]
+    a: int128 = 0
+    b: int128 = 0
+    c: bytes[10] = b""
     a, b, c = self.out_literals()
     return a, b, c
     """,
@@ -65,9 +65,9 @@ def out_literals() -> (int128, int128, bytes[100]):
 
 @public
 def test():
-    a: int128
-    b: int128
-    c: bytes[1]
+    a: int128 = 0
+    b: int128 = 0
+    c: bytes[1] = b""
     a, b, c = self.out_literals()
     """,
     ("""
diff --git a/tests/parser/syntax/test_unbalanced_return.py b/tests/parser/syntax/test_unbalanced_return.py
--- a/tests/parser/syntax/test_unbalanced_return.py
+++ b/tests/parser/syntax/test_unbalanced_return.py
@@ -103,7 +103,7 @@ def test() -> int128:
     """
 @public
 def test() -> int128:
-    x: bytes32
+    x: bytes32 = EMPTY_BYTES32
     if False:
         if False:
             return 0
diff --git a/tests/parser/syntax/test_unit_exponents.py b/tests/parser/syntax/test_unit_exponents.py
--- a/tests/parser/syntax/test_unit_exponents.py
+++ b/tests/parser/syntax/test_unit_exponents.py
@@ -19,8 +19,8 @@ def baa() -> decimal:
     """
 @public
 def foo(a: int128):
-    b:int128(sec)
-    c:int128(sec**2)
+    b:int128(sec) = 0
+    c:int128(sec**2) = 0
     c = b ** a
     """
 ]
@@ -37,8 +37,8 @@ def test_exponent_fail(bad_code):
     """
 @public
 def foo():
-    a : int128(wei)
-    b : int128(wei**2)
+    a : int128(wei) = 0
+    b : int128(wei**2) = 0
     a = 2
     b = a**2
     """,
diff --git a/tests/parser/types/numbers/test_custom_units.py b/tests/parser/types/numbers/test_custom_units.py
--- a/tests/parser/types/numbers/test_custom_units.py
+++ b/tests/parser/types/numbers/test_custom_units.py
@@ -16,8 +16,7 @@ def test_custom_units(get_contract_with_gas_estimation):
 
 @public
 def test() -> int128(km):
-    b: int128(km)
-    b = 100
+    b: int128(km) = 100
     return b
     """
 
diff --git a/tests/parser/types/numbers/test_int128.py b/tests/parser/types/numbers/test_int128.py
--- a/tests/parser/types/numbers/test_int128.py
+++ b/tests/parser/types/numbers/test_int128.py
@@ -77,9 +77,9 @@ def test_exponents_with_units(get_contract_with_gas_estimation):
     code = """
 @public
 def foo() -> int128(wei):
-    a: int128(wei)
-    b: int128
-    c: int128(wei)
+    a: int128(wei) = 0
+    b: int128 = 0
+    c: int128(wei) = 0
     a = 2
     b = 2
     c = a ** b
@@ -139,8 +139,8 @@ def test_invalid_unit_exponent(assert_compile_failed, get_contract_with_gas_esti
     code = """
 @public
 def foo():
-    a: int128(wei)
-    b: int128(wei)
+    a: int128(wei) = 0
+    b: int128(wei) = 0
     c = a ** b
 """
     assert_compile_failed(lambda: get_contract_with_gas_estimation(code), TypeMismatchException)
diff --git a/tests/parser/types/numbers/test_uint256.py b/tests/parser/types/numbers/test_uint256.py
--- a/tests/parser/types/numbers/test_uint256.py
+++ b/tests/parser/types/numbers/test_uint256.py
@@ -140,8 +140,7 @@ def test_uint256_literal(get_contract_with_gas_estimation):
     modexper = """
 @public
 def test() -> uint256:
-    o: uint256
-    o = 340282366920938463463374607431768211459
+    o: uint256 = 340282366920938463463374607431768211459
     return o
     """
 
diff --git a/tests/parser/types/test_lists.py b/tests/parser/types/test_lists.py
--- a/tests/parser/types/test_lists.py
+++ b/tests/parser/types/test_lists.py
@@ -125,7 +125,7 @@ def test_array_accessor(get_contract_with_gas_estimation):
     array_accessor = """
 @public
 def test_array(x: int128, y: int128, z: int128, w: int128) -> int128:
-    a: int128[4]
+    a: int128[4] = [0, 0, 0, 0]
     a[0] = x
     a[1] = y
     a[2] = z
@@ -142,7 +142,7 @@ def test_two_d_array_accessor(get_contract_with_gas_estimation):
     two_d_array_accessor = """
 @public
 def test_array(x: int128, y: int128, z: int128, w: int128) -> int128:
-    a: int128[2][2]
+    a: int128[2][2] = [[0, 0], [0, 0]]
     a[0][0] = x
     a[0][1] = y
     a[1][0] = z
diff --git a/tests/parser/types/test_string.py b/tests/parser/types/test_string.py
--- a/tests/parser/types/test_string.py
+++ b/tests/parser/types/test_string.py
@@ -131,9 +131,9 @@ def out_literals() -> (int128, address, string[10]) : constant
 
 @public
 def test(addr: address) -> (int128, address, string[10]):
-    a: int128
-    b: address
-    c: string[10]
+    a: int128 = 0
+    b: address = ZERO_ADDRESS
+    c: string[10] = ""
     (a, b, c) = Test(addr).out_literals()
     return a, b,c
     """