From 7cfb78228f815637963877d6517123ae820455ad Mon Sep 17 00:00:00 2001
From: Hadrian Tang <hadrianwttang@outlook.com>
Date: Fri, 28 Jul 2023 17:22:37 +0800
Subject: [PATCH 1/7] (^^^), (~~~) and (**) should also be valid arithmetic
 operators in literals

---
 src/Compiler/TypedTree/TcGlobals.fs           |  4 +-
 src/Compiler/TypedTree/TypedTreeOps.fs        | 42 +++++++++++++++++--
 .../EmittedIL/Literals.fs                     |  6 +++
 3 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs
index 563add19a67..f8e27c8da0d 100755
--- a/src/Compiler/TypedTree/TcGlobals.fs
+++ b/src/Compiler/TypedTree/TcGlobals.fs
@@ -737,6 +737,7 @@ type TcGlobals(
   let v_bitwise_unary_not_info     = makeIntrinsicValRef(fslib_MFOperators_nleref,                             "op_LogicalNot"                        , None                 , None          , [vara],     mk_unop_ty varaTy)
   let v_bitwise_shift_left_info    = makeIntrinsicValRef(fslib_MFOperators_nleref,                             "op_LeftShift"                         , None                 , None          , [vara],     mk_shiftop_ty varaTy)
   let v_bitwise_shift_right_info   = makeIntrinsicValRef(fslib_MFOperators_nleref,                             "op_RightShift"                        , None                 , None          , [vara],     mk_shiftop_ty varaTy)
+  let v_exponentiation_info        = makeIntrinsicValRef(fslib_MFOperators_nleref,                             "op_Exponentiation"                    , None                 , None          , [vara;varb],     ([[varaTy];[varbTy]], varaTy))
   let v_unchecked_addition_info    = makeIntrinsicValRef(fslib_MFOperators_nleref,                             "op_Addition"                          , None                 , None          , [vara;varb;varc],     mk_binop_ty3 varaTy varbTy  varcTy)
   let v_unchecked_subtraction_info = makeIntrinsicValRef(fslib_MFOperators_nleref,                             "op_Subtraction"                       , None                 , None          , [vara;varb;varc],     mk_binop_ty3 varaTy varbTy  varcTy)
   let v_unchecked_multiply_info    = makeIntrinsicValRef(fslib_MFOperators_nleref,                             "op_Multiply"                          , None                 , None          , [vara;varb;varc],     mk_binop_ty3 varaTy varbTy  varcTy)
@@ -1550,6 +1551,7 @@ type TcGlobals(
   member val bitwise_unary_not_vref     = ValRefForIntrinsic v_bitwise_unary_not_info
   member val bitwise_shift_left_vref    = ValRefForIntrinsic v_bitwise_shift_left_info
   member val bitwise_shift_right_vref   = ValRefForIntrinsic v_bitwise_shift_right_info
+  member val exponentiation_vref        = ValRefForIntrinsic v_exponentiation_info
   member val unchecked_addition_vref    = ValRefForIntrinsic v_unchecked_addition_info
   member val unchecked_unary_plus_vref  = ValRefForIntrinsic v_unchecked_unary_plus_info
   member val unchecked_unary_minus_vref = ValRefForIntrinsic v_unchecked_unary_minus_info
@@ -1894,7 +1896,7 @@ type TcGlobals(
         Some (info, tyargs, argExprs)
     | "Pow", [aty;bty], _, [_;_] ->
         // Call Operators.(**)
-        let info = makeOtherIntrinsicValRef (fslib_MFOperators_nleref, "op_Exponentiation", None, None, [vara; varb], ([[varaTy]; [varbTy]], varaTy))
+        let info = v_exponentiation_info
         let tyargs = [aty;bty]
         Some (info, tyargs, argExprs)
     | "Atan2", [aty;_], Some bty, [_;_] ->
diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs
index 8d555ba3ec7..ba2d72a8fc8 100644
--- a/src/Compiler/TypedTree/TypedTreeOps.fs
+++ b/src/Compiler/TypedTree/TypedTreeOps.fs
@@ -3767,6 +3767,12 @@ let (|IntegerConstExpr|_|) expr =
     | Expr.Const (Const.UInt64 _, _, _) -> Some ()
     | _ -> None
 
+let (|FloatConstExpr|_|) expr =
+    match expr with
+    | Expr.Const (Const.Single _, _, _)
+    | Expr.Const (Const.Double _, _, _) -> Some ()
+    | _ -> None
+
 let (|SpecificBinopExpr|_|) g vrefReqd expr = 
     match expr with 
     | BinopExpr g (vref, arg1, arg2) when valRefEq g vref vrefReqd -> Some (arg1, arg2)
@@ -9582,7 +9588,7 @@ let IsSimpleSyntacticConstantExpr g inputExpr =
                    valRefEq g vref g.bitwise_unary_not_vref ||
                    valRefEq g vref g.enum_vref)
              -> checkExpr vrefs arg
-        // compare, =, <>, +, -, <, >, <=, >=, <<<, >>>, &&&
+        // compare, =, <>, +, -, <, >, <=, >=, <<<, >>>, &&&, |||, ^^^
         | BinopExpr g (vref, arg1, arg2) 
              when (valRefEq g vref g.equals_operator_vref ||
                    valRefEq g vref g.compare_operator_vref ||
@@ -9595,12 +9601,13 @@ let IsSimpleSyntacticConstantExpr g inputExpr =
                    valRefEq g vref g.unchecked_addition_vref ||
                    valRefEq g vref g.unchecked_multiply_vref ||
                    valRefEq g vref g.unchecked_subtraction_vref ||
-        // Note: division and modulus can raise exceptions, so are not included
+                   // Note: division and modulus can raise exceptions, so are not included
                    valRefEq g vref g.bitwise_shift_left_vref ||
                    valRefEq g vref g.bitwise_shift_right_vref ||
                    valRefEq g vref g.bitwise_xor_vref ||
                    valRefEq g vref g.bitwise_and_vref ||
-                   valRefEq g vref g.bitwise_or_vref) &&
+                   valRefEq g vref g.bitwise_or_vref ||
+                   valRefEq g vref g.exponentiation_vref) &&
                    (not (typeEquiv g (tyOfExpr g arg1) g.string_ty) && not (typeEquiv g (tyOfExpr g arg1) g.decimal_ty) )
                 -> checkExpr vrefs arg1 && checkExpr vrefs arg2 
         | Expr.Val (vref, _, _) -> vref.Deref.IsCompiledAsStaticPropertyWithoutField || vrefs.Contains vref.Stamp
@@ -9789,6 +9796,35 @@ let rec EvalAttribArgExpr suppressLangFeatureCheck (g: TcGlobals) (x: Expr) =
         | _ ->
             errorR (Error ( FSComp.SR.tastNotAConstantExpression(), x.Range))
             x
+    | SpecificBinopExpr g g.bitwise_xor_vref (arg1, arg2) ->
+        checkFeature()
+        let v1 = EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1
+
+        match v1 with
+        | IntegerConstExpr ->
+            EvalArithBinOp ((^^^), (^^^), (^^^), (^^^), (^^^), (^^^), (^^^), (^^^), ignore2, ignore2) v1 (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg2)
+        | _ ->
+            errorR (Error (FSComp.SR.tastNotAConstantExpression(), x.Range))
+            x
+    | SpecificBinopExpr g g.exponentiation_vref (arg1, arg2) ->
+        checkFeature()
+        let v1 = EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1
+
+        match v1 with
+        | FloatConstExpr ->
+            EvalArithBinOp (ignore2, ignore2, ignore2, ignore2, ignore2, ignore2, ignore2, ignore2, ( ** ), ( ** )) v1 (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg2)
+        | _ ->
+            errorR (Error (FSComp.SR.tastNotAConstantExpression(), x.Range))
+            x
+    | SpecificUnopExpr g g.bitwise_unary_not_vref arg1 ->
+        checkFeature()
+        
+        match v1 with
+        | IntegerConstExpr ->
+            EvalArithUnOp ((~~~), (~~~), (~~~), (~~~), (~~~), (~~~), (~~~), (~~~), ignore2, ignore2) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1)
+        | _ ->
+            errorR (Error ( FSComp.SR.tastNotAConstantExpression(), x.Range))
+            x
     | SpecificUnopExpr g g.unchecked_unary_minus_vref arg1 ->
         checkFeature()
         let v1 = EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
index 5c0d3211aea..1b1d5bb3ec4 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
@@ -41,6 +41,8 @@ let [<Literal>] bytesInKilobyte2 = bytesInMegabyte / 1024L
 let [<Literal>] secondsInDayPlusThree = 3 + (60 * 60 * 24)
 
 let [<Literal>] bitwise = 1us &&& (3us ||| 4us)
+
+let [<Literal>] bitwise2 = 1y ^^^ (3y + ~~~4y)
         """
         |> withLangVersionPreview
         |> compile
@@ -51,6 +53,7 @@ let [<Literal>] bitwise = 1us &&& (3us ||| 4us)
             """.field public static literal int64 bytesInKilobyte2 = int64(0x400)"""
             """.field public static literal int32 secondsInDayPlusThree = int32(0x00015183)"""
             """.field public static literal uint16 bitwise = uint16(0x0001)"""
+            """.field public static literal int8 bitwise2 = int8(0x0009)"""
         ]
 
     [<Fact>]
@@ -62,6 +65,8 @@ module LiteralArithmetic
 
 let [<Literal>] bytesInMegabyte = 1024. * 1024. + 0.1
 
+let [<Literal>] bytesInMegabyte' = 1024f ** 2f
+
 let [<Literal>] bytesInKilobyte = bytesInMegabyte / 1024. + 0.1
 
 let [<Literal>] secondsInDayPlusThree = 3.1f + (60f * 60f * 24f)
@@ -73,6 +78,7 @@ let [<Literal>] chars = 'a' + 'b' - 'a'
         |> shouldSucceed
         |> verifyIL [
             """.field public static literal float64 bytesInMegabyte = float64(1048576.1000000001)"""
+            """.field public static literal float32 'bytesInMegabyte\'' = float32(1048576)"""
             """.field public static literal float64 bytesInKilobyte = float64(1024.10009765625)"""
             """.field public static literal float32 secondsInDayPlusThree = float32(86403.102)"""
             """.field public static literal char chars = char(0x0062)"""

From 35acb412c6c90ded2feb2a5643ef985a434eedfb Mon Sep 17 00:00:00 2001
From: Hadrian Tang <hadrianwttang@outlook.com>
Date: Fri, 28 Jul 2023 17:30:46 +0800
Subject: [PATCH 2/7] oops (object oriented programmings)

---
 src/Compiler/TypedTree/TypedTreeOps.fs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs
index ba2d72a8fc8..bbffa878f97 100644
--- a/src/Compiler/TypedTree/TypedTreeOps.fs
+++ b/src/Compiler/TypedTree/TypedTreeOps.fs
@@ -9818,6 +9818,7 @@ let rec EvalAttribArgExpr suppressLangFeatureCheck (g: TcGlobals) (x: Expr) =
             x
     | SpecificUnopExpr g g.bitwise_unary_not_vref arg1 ->
         checkFeature()
+        let v1 = EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1
         
         match v1 with
         | IntegerConstExpr ->

From e89c4076ed1f7d4b571bc0fb38aa840489f45068 Mon Sep 17 00:00:00 2001
From: Hadrian Tang <hadrianwttang@outlook.com>
Date: Fri, 28 Jul 2023 20:47:33 +0800
Subject: [PATCH 3/7] object oriented programmings again

---
 src/Compiler/TypedTree/TypedTreeOps.fs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs
index bbffa878f97..774f994aaa1 100644
--- a/src/Compiler/TypedTree/TypedTreeOps.fs
+++ b/src/Compiler/TypedTree/TypedTreeOps.fs
@@ -9822,7 +9822,7 @@ let rec EvalAttribArgExpr suppressLangFeatureCheck (g: TcGlobals) (x: Expr) =
         
         match v1 with
         | IntegerConstExpr ->
-            EvalArithUnOp ((~~~), (~~~), (~~~), (~~~), (~~~), (~~~), (~~~), (~~~), ignore2, ignore2) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1)
+            EvalArithUnOp ((~~~), (~~~), (~~~), (~~~), (~~~), (~~~), (~~~), (~~~), ignore, ignore) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1)
         | _ ->
             errorR (Error ( FSComp.SR.tastNotAConstantExpression(), x.Range))
             x

From bc284eedf9ec73fe2d66f1993bc579b7849fd0d5 Mon Sep 17 00:00:00 2001
From: Hadrian Tang <hadrianwttang@outlook.com>
Date: Fri, 28 Jul 2023 23:14:15 +0800
Subject: [PATCH 4/7] Update test

---
 tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
index 1b1d5bb3ec4..27378905c2d 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
@@ -53,7 +53,7 @@ let [<Literal>] bitwise2 = 1y ^^^ (3y + ~~~4y)
             """.field public static literal int64 bytesInKilobyte2 = int64(0x400)"""
             """.field public static literal int32 secondsInDayPlusThree = int32(0x00015183)"""
             """.field public static literal uint16 bitwise = uint16(0x0001)"""
-            """.field public static literal int8 bitwise2 = int8(0x0009)"""
+            """.field public static literal int8 bitwise2 = int8(0xFF)"""
         ]
 
     [<Fact>]

From 0ad7fa77de6636914f2ee77d6891579b9407cdcd Mon Sep 17 00:00:00 2001
From: Hadrian Tang <hadrianwttang@outlook.com>
Date: Sat, 29 Jul 2023 00:59:12 +0800
Subject: [PATCH 5/7] Update test 2

---
 tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
index 27378905c2d..68957ef2aee 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
@@ -78,7 +78,7 @@ let [<Literal>] chars = 'a' + 'b' - 'a'
         |> shouldSucceed
         |> verifyIL [
             """.field public static literal float64 bytesInMegabyte = float64(1048576.1000000001)"""
-            """.field public static literal float32 'bytesInMegabyte\'' = float32(1048576)"""
+            """.field public static literal float32 'bytesInMegabyte\'' = float32(1048576.)"""
             """.field public static literal float64 bytesInKilobyte = float64(1024.10009765625)"""
             """.field public static literal float32 secondsInDayPlusThree = float32(86403.102)"""
             """.field public static literal char chars = char(0x0062)"""

From 269670c1006ad11ed0db2481e943a600ab7dfa65 Mon Sep 17 00:00:00 2001
From: Hadrian Tang <hadrianwttang@outlook.com>
Date: Sat, 29 Jul 2023 01:47:42 +0800
Subject: [PATCH 6/7] Update test 3

---
 tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
index 68957ef2aee..32309bbe517 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
@@ -78,7 +78,10 @@ let [<Literal>] chars = 'a' + 'b' - 'a'
         |> shouldSucceed
         |> verifyIL [
             """.field public static literal float64 bytesInMegabyte = float64(1048576.1000000001)"""
-            """.field public static literal float32 'bytesInMegabyte\'' = float32(1048576.)"""
+            if System.OperatingSystem.IsWindows() then
+                """.field public static literal float32 'bytesInMegabyte\'' = float32(1048576.)"""
+            else
+                """.field public static literal float32 'bytesInMegabyte\'' = float32(1048576)"""
             """.field public static literal float64 bytesInKilobyte = float64(1024.10009765625)"""
             """.field public static literal float32 secondsInDayPlusThree = float32(86403.102)"""
             """.field public static literal char chars = char(0x0062)"""

From a81e4fbd201abcd5b46efaf1b850b4ec41b737ba Mon Sep 17 00:00:00 2001
From: Hadrian Tang <hadrianwttang@outlook.com>
Date: Sat, 29 Jul 2023 01:53:15 +0800
Subject: [PATCH 7/7] Update test 4

---
 tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
index 32309bbe517..77a3e8786f9 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
@@ -78,7 +78,7 @@ let [<Literal>] chars = 'a' + 'b' - 'a'
         |> shouldSucceed
         |> verifyIL [
             """.field public static literal float64 bytesInMegabyte = float64(1048576.1000000001)"""
-            if System.OperatingSystem.IsWindows() then
+            if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then
                 """.field public static literal float32 'bytesInMegabyte\'' = float32(1048576.)"""
             else
                 """.field public static literal float32 'bytesInMegabyte\'' = float32(1048576)"""
