Raise an error in Derivative when expr.free_symbols is not a set
Raise an error in Derivative when expr.free_symbols is not a set

The __new__ method of `Derivative(expr, *symbols)` assumes that
`expr.free_symbols` is a set without checking it. As a result,
the user trying to construct the derivative of an undefined function
is faced with uninformative TypeError messages shown below.
A check and an informative message are added. Closes #13802.

New SymPy users sometimes try to differentiate an undefined
function f in order to express the concept of f'. A typical example:
```
from sympy import *
x = Symbol('x')
f = Function('f')
diff(f, x) # TypeError: 'property' object is not iterable
diff(f)    # TypeError: object of type 'property' has no len()
Derivative(f, x)  # no error but the returned object is useless
```
To see how bad that last object is, try for example
```
Derivative(f, x).subs(f, sin(x)) # TypeError: _subs() missing 1 required positional argument: 'new'
Derivative(sin, x).doit() # doit() missing 1 required positional argument: 'self'
```

There is a longstanding issue #4787 but this PR is independent of it;
all that's changed here is that errors are raised with a custom message
instead of being thrown later. Even if unknown functions become objects,
it would still make sense to check if `free_symbols` is a set before
treating it as such. Basic objects don't have this property, so its
existence is not guaranteed.

kaushik94/sympy,kaushik94/sympy,kaushik94/sympy