[flang] Remove some needless operations in expr rewriting

Expressions emitted to module files and error messages
sometimes contain conversions of integer results of inquiry
intrinsics; these are usually not needed, and can conflict
with "int" in the user's namespace.  Improve folding so that
these conversions don't appear, and do some other clean-up
in adjacent code.

Differential Revision: https://reviews.llvm.org/D95172

GitOrigin-RevId: 59bf9a89d825c1f23b249e0ce43d8bf7b486a203
diff --git a/lib/Evaluate/fold-implementation.h b/lib/Evaluate/fold-implementation.h
index 7232715..37116bb 100644
--- a/lib/Evaluate/fold-implementation.h
+++ b/lib/Evaluate/fold-implementation.h
@@ -1105,12 +1105,13 @@
         // This variable is a workaround for msvc which emits an error when
         // using the FROMCAT template parameter below.
         TypeCategory constexpr FromCat{FROMCAT};
+        static_assert(FromCat == Operand::category);
         auto &convert{msvcWorkaround.convert};
         char buffer[64];
         if (auto value{GetScalarConstantValue<Operand>(kindExpr)}) {
           FoldingContext &ctx{msvcWorkaround.context};
           if constexpr (TO::category == TypeCategory::Integer) {
-            if constexpr (Operand::category == TypeCategory::Integer) {
+            if constexpr (FromCat == TypeCategory::Integer) {
               auto converted{Scalar<TO>::ConvertSigned(*value)};
               if (converted.overflow) {
                 ctx.messages().Say(
@@ -1118,7 +1119,7 @@
                     Operand::kind, TO::kind);
               }
               return ScalarConstantToExpr(std::move(converted.value));
-            } else if constexpr (Operand::category == TypeCategory::Real) {
+            } else if constexpr (FromCat == TypeCategory::Real) {
               auto converted{value->template ToInteger<Scalar<TO>>()};
               if (converted.flags.test(RealFlag::InvalidArgument)) {
                 ctx.messages().Say(
@@ -1132,7 +1133,7 @@
               return ScalarConstantToExpr(std::move(converted.value));
             }
           } else if constexpr (TO::category == TypeCategory::Real) {
-            if constexpr (Operand::category == TypeCategory::Integer) {
+            if constexpr (FromCat == TypeCategory::Integer) {
               auto converted{Scalar<TO>::FromInteger(*value)};
               if (!converted.flags.empty()) {
                 std::snprintf(buffer, sizeof buffer,
@@ -1141,7 +1142,7 @@
                 RealFlagWarnings(ctx, converted.flags, buffer);
               }
               return ScalarConstantToExpr(std::move(converted.value));
-            } else if constexpr (Operand::category == TypeCategory::Real) {
+            } else if constexpr (FromCat == TypeCategory::Real) {
               auto converted{Scalar<TO>::Convert(*value)};
               if (!converted.flags.empty()) {
                 std::snprintf(buffer, sizeof buffer,
@@ -1154,7 +1155,7 @@
               return ScalarConstantToExpr(std::move(converted.value));
             }
           } else if constexpr (TO::category == TypeCategory::Complex) {
-            if constexpr (Operand::category == TypeCategory::Complex) {
+            if constexpr (FromCat == TypeCategory::Complex) {
               return FoldOperation(ctx,
                   ComplexConstructor<TO::kind>{
                       AsExpr(Convert<typename TO::Part>{AsCategoryExpr(
@@ -1163,17 +1164,31 @@
                           Constant<typename Operand::Part>{value->AIMAG()})})});
             }
           } else if constexpr (TO::category == TypeCategory::Character &&
-              Operand::category == TypeCategory::Character) {
+              FromCat == TypeCategory::Character) {
             if (auto converted{ConvertString<Scalar<TO>>(std::move(*value))}) {
               return ScalarConstantToExpr(std::move(*converted));
             }
           } else if constexpr (TO::category == TypeCategory::Logical &&
-              Operand::category == TypeCategory::Logical) {
+              FromCat == TypeCategory::Logical) {
             return Expr<TO>{value->IsTrue()};
           }
-        } else if constexpr (std::is_same_v<Operand, TO> &&
+        } else if constexpr (TO::category == FromCat &&
             FromCat != TypeCategory::Character) {
-          return std::move(kindExpr); // remove needless conversion
+          // Conversion of non-constant in same type category
+          if constexpr (std::is_same_v<Operand, TO>) {
+            return std::move(kindExpr); // remove needless conversion
+          } else if constexpr (std::is_same_v<TO, DescriptorInquiry::Result>) {
+            if (auto *innerConv{
+                    std::get_if<Convert<Operand, TypeCategory::Integer>>(
+                        &kindExpr.u)}) {
+              if (auto *x{std::get_if<Expr<TO>>(&innerConv->left().u)}) {
+                if (std::holds_alternative<DescriptorInquiry>(x->u)) {
+                  // int(int(size(...),kind=k),kind=8) -> size(...)
+                  return std::move(*x);
+                }
+              }
+            }
+          }
         }
         return Expr<TO>{std::move(convert)};
       },
@@ -1201,7 +1216,9 @@
     return *array;
   }
   auto &operand{x.left()};
-  if (auto value{GetScalarConstantValue<T>(operand)}) {
+  if (auto *nn{std::get_if<Negate<T>>(&x.left().u)}) {
+    return std::move(nn->left()); // -(-x) -> x
+  } else if (auto value{GetScalarConstantValue<T>(operand)}) {
     if constexpr (T::category == TypeCategory::Integer) {
       auto negated{value->Negate()};
       if (negated.overflow) {
@@ -1308,6 +1325,20 @@
       }
       return Expr<T>{Constant<T>{product.value}};
     }
+  } else if constexpr (T::category == TypeCategory::Integer) {
+    if (auto c{GetScalarConstantValue<T>(x.right())}) {
+      x.right() = std::move(x.left());
+      x.left() = Expr<T>{std::move(*c)};
+    }
+    if (auto c{GetScalarConstantValue<T>(x.left())}) {
+      if (c->IsZero()) {
+        return std::move(x.left());
+      } else if (c->CompareSigned(Scalar<T>{1}) == Ordering::Equal) {
+        return std::move(x.right());
+      } else if (c->CompareSigned(Scalar<T>{-1}) == Ordering::Equal) {
+        return Expr<T>{Negate<T>{std::move(x.right())}};
+      }
+    }
   }
   return Expr<T>{std::move(x)};
 }
diff --git a/test/Semantics/modfile17.f90 b/test/Semantics/modfile17.f90
index 414043c..3c7361b 100644
--- a/test/Semantics/modfile17.f90
+++ b/test/Semantics/modfile17.f90
@@ -98,7 +98,7 @@
 !end type
 !type::defaulted(n1,n2,n4,n8)
 !integer(1),kind::n1=1_1
-!integer(2),kind::n2=int(int(int(n1,kind=1),kind=4)*2_4,kind=2)
+!integer(2),kind::n2=int(2_4*int(int(n1,kind=1),kind=4),kind=2)
 !integer(4),kind::n4=2_4*int(int(n2,kind=2),kind=4)
 !integer(8),kind::n8=int(12_4-int(n4,kind=4),kind=8)
 !type(capture(k1=int(n1,kind=1),k2=int(n2,kind=2),k4=int(n4,kind=4),k8=n8))::cap
diff --git a/test/Semantics/modfile30.f90 b/test/Semantics/modfile30.f90
index dba950c..275f72c 100644
--- a/test/Semantics/modfile30.f90
+++ b/test/Semantics/modfile30.f90
@@ -19,11 +19,11 @@
 !contains
 ! function f1(x) result(y)
 !  integer(4)::x(:)
-!  integer(4)::y(1_8:int(int(1_8*size(x,dim=1),kind=4),kind=8))
+!  integer(4)::y(1_8:size(x,dim=1))
 ! end
 ! function f2(x)
 !  integer(4)::x(:)
-!  integer(4)::f2(1_8:int(int(1_8*size(x,dim=1),kind=4),kind=8))
+!  integer(4)::f2(1_8:size(x,dim=1))
 ! end
 !end