Repository: sympy/sympy

Issue:
Differentiation of general functions
```
In [1]:
from sympy import *
var('x, y')
f = Function('f')

In [2]:
f(x + y, x).diff(x)

Out[2]:
Derivative(f(x + y, x), x) + Subs(Derivative(f(_xi_1, x), _xi_1), (_xi_1,), (x + y,))

In [3]:
f(x, x).diff(x)

Out[3]:
2*Derivative(f(x, x), x)
```

For `In [2]`, instead of the result, I would expect, 
`Subs(Derivative(f(x+y, _xi_2), _xi_2), (_xi_2,), (x,)) + Subs(Derivative(f(_xi_1, x), _xi_1), (_xi_1,), (x + y,))`

Discussion:

Patch:
diff --git a/sympy/core/function.py b/sympy/core/function.py
index ab14b62089..2ca570cbc4 100644
--- a/sympy/core/function.py
+++ b/sympy/core/function.py
@@ -646,14 +646,23 @@ def fdiff(self, argindex=1):
         """
         if not (1 <= argindex <= len(self.args)):
             raise ArgumentIndexError(self, argindex)
-        if not self.args[argindex - 1].is_Symbol:
-            # See issue 4624 and issue 4719 and issue 5600
-            arg_dummy = Dummy('xi_%i' % argindex)
-            arg_dummy.dummy_index = hash(self.args[argindex - 1])
-            return Subs(Derivative(
-                self.subs(self.args[argindex - 1], arg_dummy),
-                arg_dummy), arg_dummy, self.args[argindex - 1])
-        return Derivative(self, self.args[argindex - 1], evaluate=False)
+
+        if self.args[argindex - 1].is_Symbol:
+            for i in range(len(self.args)):
+                if i == argindex - 1:
+                    continue
+                # See issue 8510
+                if self.args[argindex - 1] in self.args[i].free_symbols:
+                    break
+            else:
+                return Derivative(self, self.args[argindex - 1], evaluate=False)
+        # See issue 4624 and issue 4719 and issue 5600
+        arg_dummy = Dummy('xi_%i' % argindex)
+        arg_dummy.dummy_index = hash(self.args[argindex - 1])
+        new_args = [arg for arg in self.args]
+        new_args[argindex-1] = arg_dummy
+        return Subs(Derivative(self.func(*new_args), arg_dummy),
+            arg_dummy, self.args[argindex - 1])
 
     def _eval_as_leading_term(self, x):
         """Stub that should be overridden by new Functions to return


Test patch:
diff --git a/sympy/core/tests/test_function.py b/sympy/core/tests/test_function.py
index 86c0b6a723..96a9514932 100644
--- a/sympy/core/tests/test_function.py
+++ b/sympy/core/tests/test_function.py
@@ -289,6 +289,12 @@ def test_deriv1():
     assert f(3*sin(x)).diff(x) == 3*cos(x)*Subs(Derivative(f(x), x),
             Tuple(x), Tuple(3*sin(x)))
 
+    # See issue 8510
+    assert f(x, x + z).diff(x) == Subs(Derivative(f(y, x + z), y), Tuple(y), Tuple(x)) \
+            + Subs(Derivative(f(x, y), y), Tuple(y), Tuple(x + z))
+    assert f(x, x**2).diff(x) == Subs(Derivative(f(y, x**2), y), Tuple(y), Tuple(x)) \
+            + 2*x*Subs(Derivative(f(x, y), y), Tuple(y), Tuple(x**2))
+
 
 def test_deriv2():
     assert (x**3).diff(x) == 3*x**2