Repository: taichi-dev/taichi (language: python)

Issue:
Calculate with copy of struct member raise error
<!-- We've collected some common issue solutions in https://docs.taichi-lang.org/docs/install. Make sure you've check them out first. Hopefully they could address your problem. -->

**Describe the bug**
running `e ** -1` or any negative number will raise error, which e is a copy of struct member.

**To Reproduce**
```py
import taichi as ti

ti.init()

@ti.dataclass
class Particle:
    epsilon: ti.f64

@ti.kernel
def test():
    p1 = Particle()
    p1.epsilon = 1.
    e = p1.epsilon
    print(e ** -1)

if __name__ == '__main__':
    test()
```

**Log/Screenshots**
```
python3.10 test.py 
[Taichi] version 1.6.0, llvm 15.0.4, commit f1c6fbbd, linux, python 3.10.9
[Taichi] Starting on arch=x64

[E 07/09/23 18:36:54.102 79155] [type.h:TypedConstant@605] Not supported.
[E 07/09/23 18:36:54.102 79155] [ir.cpp:~DelayedIRModifier@408] Assertion failure: to_insert_before_.empty()
terminate called after throwing an instance of 'std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >'

Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
```
**Additional comments**
BTW, if init struct member like `p1 = Particle(epsilon=1.)`, it wonnt raise error.



Discussion / hints:

Fix patch:
diff --git a/taichi/transforms/alg_simp.cpp b/taichi/transforms/alg_simp.cpp
index 2594767e44b3a..2ad9bee429d03 100644
--- a/taichi/transforms/alg_simp.cpp
+++ b/taichi/transforms/alg_simp.cpp
@@ -279,11 +279,13 @@ class AlgSimp : public BasicStmtVisitor {
 
     cast_to_result_type(one, stmt);
     auto new_exponent = Stmt::make<UnaryOpStmt>(UnaryOpType::neg, stmt->rhs);
+    new_exponent->ret_type = stmt->rhs->ret_type;
     auto a_to_n = Stmt::make<BinaryOpStmt>(BinaryOpType::pow, stmt->lhs,
                                            new_exponent.get());
     a_to_n->ret_type = stmt->ret_type;
     auto result =
         Stmt::make<BinaryOpStmt>(BinaryOpType::div, one, a_to_n.get());
+    result->ret_type = stmt->ret_type;
     stmt->replace_usages_with(result.get());
     modifier.insert_before(stmt, std::move(new_exponent));
     modifier.insert_before(stmt, std::move(a_to_n));


Test patch:
diff --git a/tests/python/test_optimization.py b/tests/python/test_optimization.py
index c966464647da4..1500663e75f44 100644
--- a/tests/python/test_optimization.py
+++ b/tests/python/test_optimization.py
@@ -153,3 +153,19 @@ def my_cast(x: ti.f32) -> ti.u32:
         return ti.cast(y, ti.u32)
 
     assert my_cast(-1) == 4294967295
+
+
+@test_utils.test()
+def test_negative_exp():
+    @ti.dataclass
+    class Particle:
+        epsilon: ti.f32
+
+    @ti.kernel
+    def test() -> ti.f32:
+        p1 = Particle()
+        p1.epsilon = 1.0
+        e = p1.epsilon
+        return e**-1
+
+    assert test() == 1.0