Fully functional std::complex specializations and overloads

I’m reading your code more closely today before swapping out my implementation for yours in my application at work.

Right now, the inheritance structure I’m reading is:
std::complex<stan::math::var> inherits from stan::math::complex_base<stan::math::var>. The operations of stan::math::complex_base statically downcast their return references back to std::complex<stan::math::var>.

For reference, my inheritance structure is:
std::complex<stan::math::var> inherits from stan::math::complex<stan::math::var>, which in turn inherits from std::complex<stan::math::zeroing<stan::math::var>>>. There is also an operator std::complex() defined on stan::math::complex, which implicitly statically downcasts to std::complex for both base classes. (The extra level of inheritance together with the implicit downcasting delegates all operations back to the standard library as if they were operating on a zeroing version of stan’s types. This is why there is so little code, excluding the Jenkins autoformat misconfiguration that had touched a lot of files.)

While trying to test your code:
I was trying to build the libraries. I ended up partially following a page I wrote in the math wiki a while back, along with an example Jenkins test run. make test-headers fails with the error below. ./runTests.py fails because due to a missing Google Test library. I’m on commit 2c746c2cc9d19feb036dae474444b86d940be210 (HEAD → feature/0123-complex-var, origin/feature/0123-complex-var). Edit: Forgot to add that I’m on Windows with MSYS2 x86_64 using GCC 9.1.

g++ -std=c++1y -m64 -D_REENTRANT -Wall -Wno-unused-function -Wno-uninitialized -Wno-unused-but-set-variable -Wno-unused-variable -Wno-sign-compare -Wno-unused-local-typedefs      -I lib/tbb_2019_U8/include -O3  -I . -I lib/eigen_3.3.3 -I lib/boost_1.69.0 -I lib/sundials_4.1.0/include  -D_USE_MATH_DEFINES  -DBOOST_DISABLE_ASSERTS      -c -std=c++1y -m64 -D_REENTRANT -Wall -Wno-unused-function -Wno-uninitialized -Wno-unused-but-set-variable -Wno-unused-variable -Wno-sign-compare -Wno-unused-local-typedefs      -I lib/tbb_2019_U8/include -O3  -I . -I lib/eigen_3.3.3 -I lib/boost_1.69.0 -I lib/sundials_4.1.0/include -O0 -include stan/math/mix/mat/fun/typedefs.hpp test/dummy.cpp -o nul
In file included from ./stan/math/rev/core.hpp:49,
                 from ./stan/math/mix/mat/fun/typedefs.hpp:6,
                 from <command-line>:
./stan/math/rev/core/std_complex.hpp: In instantiation of 'std::complex<double> stan::math::value_of_rec(const std::complex<_Tp>&) [with T = stan::math::var]':
./stan/math/rev/core/std_complex.hpp:693:48:   required from 'std::complex<_Tp> stan::math::complex_asinh(const std::complex<_Tp>&) [with V = stan::math::var]'
./stan/math/rev/core/std_complex.hpp:1537:25:   required from here
./stan/math/rev/core/std_complex.hpp:229:23: error: no matching function for call to 'value_of_rec(stan::math::complex_base<stan::math::var>::value_type)'
  229 |   return {value_of_rec(z.real()), value_of_rec(z.imag())};
      |           ~~~~~~~~~~~~^~~~~~~~~~
./stan/math/rev/core/std_complex.hpp:228:29: note: candidate: 'template<class T> std::complex<double> stan::math::value_of_rec(const std::complex<_Tp>&)'
  228 | inline std::complex<double> value_of_rec(const std::complex<T>& z) {
      |                             ^~~~~~~~~~~~
./stan/math/rev/core/std_complex.hpp:228:29: note:   template argument deduction/substitution failed:
./stan/math/rev/core/std_complex.hpp:229:23: note:   'stan::math::complex_base<stan::math::var>::value_type' {aka 'stan::math::var'} is not derived from 'const std::complex<_Tp>'
  229 |   return {value_of_rec(z.real()), value_of_rec(z.imag())};
      |           ~~~~~~~~~~~~^~~~~~~~~~
./stan/math/rev/core/std_complex.hpp:229:47: error: no matching function for call to 'value_of_rec(stan::math::complex_base<stan::math::var>::value_type)'
  229 |   return {value_of_rec(z.real()), value_of_rec(z.imag())};
      |                                   ~~~~~~~~~~~~^~~~~~~~~~
./stan/math/rev/core/std_complex.hpp:228:29: note: candidate: 'template<class T> std::complex<double> stan::math::value_of_rec(const std::complex<_Tp>&)'
  228 | inline std::complex<double> value_of_rec(const std::complex<T>& z) {
      |                             ^~~~~~~~~~~~
./stan/math/rev/core/std_complex.hpp:228:29: note:   template argument deduction/substitution failed:
./stan/math/rev/core/std_complex.hpp:229:47: note:   'stan::math::complex_base<stan::math::var>::value_type' {aka 'stan::math::var'} is not derived from 'const std::complex<_Tp>'
  229 |   return {value_of_rec(z.real()), value_of_rec(z.imag())};
      |                                   ~~~~~~~~~~~~^~~~~~~~~~
./stan/math/rev/core/std_complex.hpp:229:57: error: could not convert '{<expression error>, <expression error>}' from '<brace-enclosed initializer list>' to 'std::complex<double>'
  229 |   return {value_of_rec(z.real()), value_of_rec(z.imag())};
      |                                                         ^
      |                                                         |
      |                                                         <brace-enclosed initializer list>