Repository: chainer/chainer

Issue:
VariableNode's dtype mismatch if Variable.data is manually assigned
If `Variable.data` is assigned manually, `node.dtype` and `node.data.dtype` can indicate different values.
This has caused "Dtype of data and grad mismatch" error in `gradient_check.check_double_backward`.
### Code
```
import chainer
import numpy
from chainer import functions as F

x = chainer.Variable(numpy.array([3, 2], dtype=numpy.float32))
y = F.sin(x)
x.data = numpy.array([4, 2], dtype=numpy.float64)

print(x.node.dtype)
print(x.node.data.dtype)
```

### Output
```
float64                                             
float32
```

Current master: 5683281c854fd2e47b68a3461b8e3e7e3c69f227


Discussion:

Resolving patch:
diff --git a/chainer/variable.py b/chainer/variable.py
--- a/chainer/variable.py
+++ b/chainer/variable.py
@@ -166,7 +166,7 @@ def __init__(self, variable, name, **kwargs):
         self._requires_grad = variable.requires_grad
 
         vdata = variable.data
-        self._set_data_type(vdata)
+        self._update_data_info(vdata)
 
     @property
     def creator(self):
@@ -258,7 +258,7 @@ def data(self):
     @data.setter
     def data(self, d):
         self._data = d
-        self._set_data_type(d)
+        self._update_data_info(d)
 
     @property
     def grad(self):
@@ -381,7 +381,7 @@ def retain_data(self):
             raise RuntimeError('cannot retain variable data: the variable has '
                                'been already released')
 
-    def _set_data_type(self, d):
+    def _update_data_info(self, d):
         if d is None:
             self.dtype = None
             self.shape = None
@@ -389,6 +389,10 @@ def _set_data_type(self, d):
             self.dtype = d.dtype
             self.shape = d.shape
 
+        # If the node has a reference to data, update it as well.
+        if self._data is not None:
+            self._data = d
+
     def _check_old_style_gradient(self):
         if self._old_style_grad_generator is not None:
             raise RuntimeError(
@@ -604,7 +608,7 @@ def array(self):
     @array.setter
     def array(self, d):
         self._data[0] = d
-        self._node._set_data_type(d)
+        self._node._update_data_info(d)
 
     @property
     def data(self):
@@ -622,7 +626,7 @@ def data(self):
     @data.setter
     def data(self, d):
         self._data[0] = d
-        self._node._set_data_type(d)
+        self._node._update_data_info(d)
 
     @property
     def grad(self):


Test patch:
diff --git a/tests/chainer_tests/test_variable.py b/tests/chainer_tests/test_variable.py
--- a/tests/chainer_tests/test_variable.py
+++ b/tests/chainer_tests/test_variable.py
@@ -722,6 +722,22 @@ def test_bool_inconvertible(self):
                 pass
 
 
+class TestVariableDataAssign(unittest.TestCase):
+
+    def test_variable_data_assign(self):
+        x = chainer.Variable(np.ones((3, 2), np.float32))
+        chainer.functions.sin(x)
+        x.data = np.ones((2, 4), np.float64)
+        assert x.data.shape == (2, 4)
+        assert x.data.dtype == np.float64
+        assert x.shape == (2, 4)
+        assert x.dtype == np.float64
+        assert x.node.shape == (2, 4)
+        assert x.node.dtype == np.float64
+        assert x.node.data.shape == (2, 4)
+        assert x.node.data.dtype == np.float64
+
+
 class TestParameter(unittest.TestCase):
 
     def setUp(self):