diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt
index 2fca7afeb60..d6033b8230f 100644
--- a/src/Compiler/FSComp.txt
+++ b/src/Compiler/FSComp.txt
@@ -1558,6 +1558,7 @@ featureLowercaseDUWhenRequireQualifiedAccess,"Allow lowercase DU when RequireQua
featureMatchNotAllowedForUnionCaseWithNoData,"Pattern match discard is not allowed for union case that takes no data."
featureCSharpExtensionAttributeNotRequired,"Allow implicit Extension attribute on declaring types, modules"
featureErrorForNonVirtualMembersOverrides,"Raises errors for non-virtual members overrides"
+featureArithmeticInLiterals,"Allow arithmetic and logical operations in literals"
3353,fsiInvalidDirective,"Invalid directive '#%s %s'"
3354,tcNotAFunctionButIndexerNamedIndexingNotYetEnabled,"This value supports indexing, e.g. '%s.[index]'. The syntax '%s[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation."
3354,tcNotAFunctionButIndexerIndexingNotYetEnabled,"This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation."
diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs
index 14302b05132..6b543bc9b64 100644
--- a/src/Compiler/Facilities/LanguageFeatures.fs
+++ b/src/Compiler/Facilities/LanguageFeatures.fs
@@ -57,6 +57,7 @@ type LanguageFeature =
| MatchNotAllowedForUnionCaseWithNoData
| CSharpExtensionAttributeNotRequired
| ErrorForNonVirtualMembersOverrides
+ | ArithmeticInLiterals
/// LanguageVersion management
type LanguageVersion(versionText) =
@@ -130,6 +131,7 @@ type LanguageVersion(versionText) =
LanguageFeature.MatchNotAllowedForUnionCaseWithNoData, previewVersion
LanguageFeature.CSharpExtensionAttributeNotRequired, previewVersion
LanguageFeature.ErrorForNonVirtualMembersOverrides, previewVersion
+ LanguageFeature.ArithmeticInLiterals, previewVersion
]
@@ -238,8 +240,9 @@ type LanguageVersion(versionText) =
| LanguageFeature.InterfacesWithAbstractStaticMembers -> FSComp.SR.featureInterfacesWithAbstractStaticMembers ()
| LanguageFeature.SelfTypeConstraints -> FSComp.SR.featureSelfTypeConstraints ()
| LanguageFeature.MatchNotAllowedForUnionCaseWithNoData -> FSComp.SR.featureMatchNotAllowedForUnionCaseWithNoData ()
- | LanguageFeature.CSharpExtensionAttributeNotRequired -> FSComp.SR.featureCSharpExtensionAttributeNotRequired ()
- | LanguageFeature.ErrorForNonVirtualMembersOverrides -> FSComp.SR.featureErrorForNonVirtualMembersOverrides ()
+ | LanguageFeature.CSharpExtensionAttributeNotRequired -> FSComp.SR.featureCSharpExtensionAttributeNotRequired ()
+ | LanguageFeature.ErrorForNonVirtualMembersOverrides -> FSComp.SR.featureErrorForNonVirtualMembersOverrides ()
+ | LanguageFeature.ArithmeticInLiterals -> FSComp.SR.featureArithmeticInLiterals ()
/// Get a version string associated with the given feature.
static member GetFeatureVersionString feature =
diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi
index f471f371b95..616093ecb30 100644
--- a/src/Compiler/Facilities/LanguageFeatures.fsi
+++ b/src/Compiler/Facilities/LanguageFeatures.fsi
@@ -47,6 +47,7 @@ type LanguageFeature =
| MatchNotAllowedForUnionCaseWithNoData
| CSharpExtensionAttributeNotRequired
| ErrorForNonVirtualMembersOverrides
+ | ArithmeticInLiterals
/// LanguageVersion management
type LanguageVersion =
diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs
index 96dc59428e2..7bef3ed71a5 100755
--- a/src/Compiler/TypedTree/TcGlobals.fs
+++ b/src/Compiler/TypedTree/TcGlobals.fs
@@ -1481,6 +1481,8 @@ type TcGlobals(
member val unchecked_unary_not_vref = ValRefForIntrinsic v_unchecked_unary_not_info
member val unchecked_subtraction_vref = ValRefForIntrinsic v_unchecked_subtraction_info
member val unchecked_multiply_vref = ValRefForIntrinsic v_unchecked_multiply_info
+ member val unchecked_division_vref = ValRefForIntrinsic v_unchecked_division_info
+ member val unchecked_modulus_vref = ValRefForIntrinsic v_unchecked_modulus_info
member val unchecked_defaultof_vref = ValRefForIntrinsic v_unchecked_defaultof_info
member val refcell_deref_vref = ValRefForIntrinsic v_refcell_deref_info
member val refcell_assign_vref = ValRefForIntrinsic v_refcell_assign_info
diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs
index 6fa70a5903e..1ff908d445a 100644
--- a/src/Compiler/TypedTree/TypedTreeOps.fs
+++ b/src/Compiler/TypedTree/TypedTreeOps.fs
@@ -3742,6 +3742,28 @@ let (|SpecificUnopExpr|_|) g vrefReqd expr =
| UnopExpr g (vref, arg1) when valRefEq g vref vrefReqd -> Some arg1
| _ -> None
+let (|SignedConstExpr|_|) expr =
+ match expr with
+ | Expr.Const (Const.Int32 _, _, _)
+ | Expr.Const (Const.SByte _, _, _)
+ | Expr.Const (Const.Int16 _, _, _)
+ | Expr.Const (Const.Int64 _, _, _)
+ | Expr.Const (Const.Single _, _, _)
+ | Expr.Const (Const.Double _, _, _) -> Some ()
+ | _ -> None
+
+let (|IntegerConstExpr|_|) expr =
+ match expr with
+ | Expr.Const (Const.Int32 _, _, _)
+ | Expr.Const (Const.SByte _, _, _)
+ | Expr.Const (Const.Int16 _, _, _)
+ | Expr.Const (Const.Int64 _, _, _)
+ | Expr.Const (Const.Byte _, _, _)
+ | Expr.Const (Const.UInt16 _, _, _)
+ | Expr.Const (Const.UInt32 _, _, _)
+ | Expr.Const (Const.UInt64 _, _, _) -> Some ()
+ | _ -> None
+
let (|SpecificBinopExpr|_|) g vrefReqd expr =
match expr with
| BinopExpr g (vref, arg1, arg2) when valRefEq g vref vrefReqd -> Some (arg1, arg2)
@@ -9647,12 +9669,46 @@ let IsSimpleSyntacticConstantExpr g inputExpr =
checkExpr vrefs e
checkExpr Set.empty inputExpr
-
-let EvalArithBinOp (opInt8, opInt16, opInt32, opInt64, opUInt8, opUInt16, opUInt32, opUInt64) (arg1: Expr) (arg2: Expr) =
- // At compile-time we check arithmetic
+
+let EvalArithShiftOp (opInt8, opInt16, opInt32, opInt64, opUInt8, opUInt16, opUInt32, opUInt64) (arg1: Expr) (arg2: Expr) =
+ // At compile-time we check arithmetic
+ let m = unionRanges arg1.Range arg2.Range
+ try
+ match arg1, arg2 with
+ | Expr.Const (Const.Int32 x1, _, ty), Expr.Const (Const.Int32 shift, _, _) -> Expr.Const (Const.Int32 (opInt32 x1 shift), m, ty)
+ | Expr.Const (Const.SByte x1, _, ty), Expr.Const (Const.Int32 shift, _, _) -> Expr.Const (Const.SByte (opInt8 x1 shift), m, ty)
+ | Expr.Const (Const.Int16 x1, _, ty), Expr.Const (Const.Int32 shift, _, _) -> Expr.Const (Const.Int16 (opInt16 x1 shift), m, ty)
+ | Expr.Const (Const.Int64 x1, _, ty), Expr.Const (Const.Int32 shift, _, _) -> Expr.Const (Const.Int64 (opInt64 x1 shift), m, ty)
+ | Expr.Const (Const.Byte x1, _, ty), Expr.Const (Const.Int32 shift, _, _) -> Expr.Const (Const.Byte (opUInt8 x1 shift), m, ty)
+ | Expr.Const (Const.UInt16 x1, _, ty), Expr.Const (Const.Int32 shift, _, _) -> Expr.Const (Const.UInt16 (opUInt16 x1 shift), m, ty)
+ | Expr.Const (Const.UInt32 x1, _, ty), Expr.Const (Const.Int32 shift, _, _) -> Expr.Const (Const.UInt32 (opUInt32 x1 shift), m, ty)
+ | Expr.Const (Const.UInt64 x1, _, ty), Expr.Const (Const.Int32 shift, _, _) -> Expr.Const (Const.UInt64 (opUInt64 x1 shift), m, ty)
+ | _ -> error (Error ( FSComp.SR.tastNotAConstantExpression(), m))
+ with :? System.OverflowException -> error (Error ( FSComp.SR.tastConstantExpressionOverflow(), m))
+
+let EvalArithUnOp (opInt8, opInt16, opInt32, opInt64, opUInt8, opUInt16, opUInt32, opUInt64, opSingle, opDouble) (arg1: Expr) =
+ // At compile-time we check arithmetic
+ let m = arg1.Range
+ try
+ match arg1 with
+ | Expr.Const (Const.Int32 x1, _, ty) -> Expr.Const (Const.Int32 (opInt32 x1), m, ty)
+ | Expr.Const (Const.SByte x1, _, ty) -> Expr.Const (Const.SByte (opInt8 x1), m, ty)
+ | Expr.Const (Const.Int16 x1, _, ty) -> Expr.Const (Const.Int16 (opInt16 x1), m, ty)
+ | Expr.Const (Const.Int64 x1, _, ty) -> Expr.Const (Const.Int64 (opInt64 x1), m, ty)
+ | Expr.Const (Const.Byte x1, _, ty) -> Expr.Const (Const.Byte (opUInt8 x1), m, ty)
+ | Expr.Const (Const.UInt16 x1, _, ty) -> Expr.Const (Const.UInt16 (opUInt16 x1), m, ty)
+ | Expr.Const (Const.UInt32 x1, _, ty) -> Expr.Const (Const.UInt32 (opUInt32 x1), m, ty)
+ | Expr.Const (Const.UInt64 x1, _, ty) -> Expr.Const (Const.UInt64 (opUInt64 x1), m, ty)
+ | Expr.Const (Const.Single x1, _, ty) -> Expr.Const (Const.Single (opSingle x1), m, ty)
+ | Expr.Const (Const.Double x1, _, ty) -> Expr.Const (Const.Double (opDouble x1), m, ty)
+ | _ -> error (Error ( FSComp.SR.tastNotAConstantExpression(), m))
+ with :? System.OverflowException -> error (Error ( FSComp.SR.tastConstantExpressionOverflow(), m))
+
+let EvalArithBinOp (opInt8, opInt16, opInt32, opInt64, opUInt8, opUInt16, opUInt32, opUInt64, opSingle, opDouble) (arg1: Expr) (arg2: Expr) =
+ // At compile-time we check arithmetic
let m = unionRanges arg1.Range arg2.Range
- try
- match arg1, arg2 with
+ try
+ match arg1, arg2 with
| Expr.Const (Const.Int32 x1, _, ty), Expr.Const (Const.Int32 x2, _, _) -> Expr.Const (Const.Int32 (opInt32 x1 x2), m, ty)
| Expr.Const (Const.SByte x1, _, ty), Expr.Const (Const.SByte x2, _, _) -> Expr.Const (Const.SByte (opInt8 x1 x2), m, ty)
| Expr.Const (Const.Int16 x1, _, ty), Expr.Const (Const.Int16 x2, _, _) -> Expr.Const (Const.Int16 (opInt16 x1 x2), m, ty)
@@ -9661,11 +9717,18 @@ let EvalArithBinOp (opInt8, opInt16, opInt32, opInt64, opUInt8, opUInt16, opUInt
| Expr.Const (Const.UInt16 x1, _, ty), Expr.Const (Const.UInt16 x2, _, _) -> Expr.Const (Const.UInt16 (opUInt16 x1 x2), m, ty)
| Expr.Const (Const.UInt32 x1, _, ty), Expr.Const (Const.UInt32 x2, _, _) -> Expr.Const (Const.UInt32 (opUInt32 x1 x2), m, ty)
| Expr.Const (Const.UInt64 x1, _, ty), Expr.Const (Const.UInt64 x2, _, _) -> Expr.Const (Const.UInt64 (opUInt64 x1 x2), m, ty)
+ | Expr.Const (Const.Single x1, _, ty), Expr.Const (Const.Single x2, _, _) -> Expr.Const (Const.Single (opSingle x1 x2), m, ty)
+ | Expr.Const (Const.Double x1, _, ty), Expr.Const (Const.Double x2, _, _) -> Expr.Const (Const.Double (opDouble x1 x2), m, ty)
| _ -> error (Error ( FSComp.SR.tastNotAConstantExpression(), m))
with :? System.OverflowException -> error (Error ( FSComp.SR.tastConstantExpressionOverflow(), m))
// See also PostTypeCheckSemanticChecks.CheckAttribArgExpr, which must match this precisely
-let rec EvalAttribArgExpr g x =
+let rec EvalAttribArgExpr (g: TcGlobals) x =
+ let ignore (_x: 'a) = Unchecked.defaultof<'a>
+ let ignore2 (_x: 'a) (_y: 'a) = Unchecked.defaultof<'a>
+
+ let arithmeticInLiteralsEnabled = g.langVersion.SupportsFeature LanguageFeature.ArithmeticInLiterals
+
match x with
// Detect standard constants
@@ -9699,30 +9762,93 @@ let rec EvalAttribArgExpr g x =
EvalAttribArgExpr g arg1
// Detect bitwise or of attribute flags
| AttribBitwiseOrExpr g (arg1, arg2) ->
- EvalArithBinOp ((|||), (|||), (|||), (|||), (|||), (|||), (|||), (|||)) (EvalAttribArgExpr g arg1) (EvalAttribArgExpr g arg2)
- | SpecificBinopExpr g g.unchecked_addition_vref (arg1, arg2) ->
- // At compile-time we check arithmetic
- let v1, v2 = EvalAttribArgExpr g arg1, EvalAttribArgExpr g arg2
- match v1, v2 with
- | Expr.Const (Const.String x1, m, ty), Expr.Const (Const.String x2, _, _) -> Expr.Const (Const.String (x1 + x2), m, ty)
- | _ ->
-#if ALLOW_ARITHMETIC_OPS_IN_LITERAL_EXPRESSIONS_AND_ATTRIBUTE_ARGS
- EvalArithBinOp (Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+)) g v1 v2
-#else
- errorR (Error ( FSComp.SR.tastNotAConstantExpression(), x.Range))
- x
-#endif
-#if ALLOW_ARITHMETIC_OPS_IN_LITERAL_EXPRESSIONS_AND_ATTRIBUTE_ARGS
- | SpecificBinopExpr g g.unchecked_subtraction_vref (arg1, arg2) ->
- EvalArithBinOp (Checked.(-), Checked.(-), Checked.(-), Checked.(-), Checked.(-), Checked.(-), Checked.(-), Checked.(-)) g (EvalAttribArgExpr g arg1) (EvalAttribArgExpr g arg2)
- | SpecificBinopExpr g g.unchecked_multiply_vref (arg1, arg2) ->
- EvalArithBinOp (Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*)) g (EvalAttribArgExpr g arg1) (EvalAttribArgExpr g arg2)
-#endif
+ let v1 = EvalAttribArgExpr g arg1
+
+ match v1 with
+ | IntegerConstExpr ->
+ EvalArithBinOp ((|||), (|||), (|||), (|||), (|||), (|||), (|||), (|||), ignore2, ignore2) v1 (EvalAttribArgExpr g arg2)
+ | _ ->
+ errorR (Error ( FSComp.SR.tastNotAConstantExpression(), x.Range))
+ x
+ | SpecificBinopExpr g g.unchecked_addition_vref (arg1, arg2) ->
+ // At compile-time we check arithmetic
+ let v1, v2 = EvalAttribArgExpr g arg1, EvalAttribArgExpr g arg2
+ match v1, v2 with
+ | Expr.Const (Const.String x1, m, ty), Expr.Const (Const.String x2, _, _) ->
+ Expr.Const (Const.String (x1 + x2), m, ty)
+ | Expr.Const (Const.Char x1, m, ty), Expr.Const (Const.Char x2, _, _) when arithmeticInLiteralsEnabled ->
+ Expr.Const (Const.Char (x1 + x2), m, ty)
+ | _ ->
+ if arithmeticInLiteralsEnabled then
+ EvalArithBinOp (Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+)) v1 v2
+ else
+ errorR (Error ( FSComp.SR.tastNotAConstantExpression(), x.Range))
+ x
+ | SpecificBinopExpr g g.unchecked_subtraction_vref (arg1, arg2) when arithmeticInLiteralsEnabled ->
+ let v1, v2 = EvalAttribArgExpr g arg1, EvalAttribArgExpr g arg2
+ match v1, v2 with
+ | Expr.Const (Const.Char x1, m, ty), Expr.Const (Const.Char x2, _, _) ->
+ Expr.Const (Const.Char (x1 - x2), m, ty)
+ | _ ->
+ EvalArithBinOp (Checked.(-), Checked.(-), Checked.(-), Checked.(-), Checked.(-), Checked.(-), Checked.(-), Checked.(-), Checked.(-), Checked.(-)) v1 v2
+ | SpecificBinopExpr g g.unchecked_multiply_vref (arg1, arg2) when arithmeticInLiteralsEnabled ->
+ EvalArithBinOp (Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*)) (EvalAttribArgExpr g arg1) (EvalAttribArgExpr g arg2)
+ | SpecificBinopExpr g g.unchecked_division_vref (arg1, arg2) when arithmeticInLiteralsEnabled ->
+ EvalArithBinOp ((/), (/), (/), (/), (/), (/), (/), (/), (/), (/)) (EvalAttribArgExpr g arg1) (EvalAttribArgExpr g arg2)
+ | SpecificBinopExpr g g.unchecked_modulus_vref (arg1, arg2) when arithmeticInLiteralsEnabled ->
+ EvalArithBinOp ((%), (%), (%), (%), (%), (%), (%), (%), (%), (%)) (EvalAttribArgExpr g arg1) (EvalAttribArgExpr g arg2)
+ | SpecificBinopExpr g g.bitwise_shift_left_vref (arg1, arg2) when arithmeticInLiteralsEnabled ->
+ EvalArithShiftOp ((<<<), (<<<), (<<<), (<<<), (<<<), (<<<), (<<<), (<<<)) (EvalAttribArgExpr g arg1) (EvalAttribArgExpr g arg2)
+ | SpecificBinopExpr g g.bitwise_shift_right_vref (arg1, arg2) when arithmeticInLiteralsEnabled ->
+ EvalArithShiftOp ((>>>), (>>>), (>>>), (>>>), (>>>), (>>>), (>>>), (>>>)) (EvalAttribArgExpr g arg1) (EvalAttribArgExpr g arg2)
+ | SpecificBinopExpr g g.bitwise_and_vref (arg1, arg2) when arithmeticInLiteralsEnabled ->
+ let v1 = EvalAttribArgExpr g arg1
+
+ match v1 with
+ | IntegerConstExpr ->
+ EvalArithBinOp ((&&&), (&&&), (&&&), (&&&), (&&&), (&&&), (&&&), (&&&), ignore2, ignore2) v1 (EvalAttribArgExpr g arg2)
+ | _ ->
+ errorR (Error ( FSComp.SR.tastNotAConstantExpression(), x.Range))
+ x
+ | SpecificUnopExpr g g.unchecked_unary_minus_vref arg1 when arithmeticInLiteralsEnabled ->
+ let v1 = EvalAttribArgExpr g arg1
+
+ match v1 with
+ | SignedConstExpr ->
+ EvalArithUnOp (Checked.(~-), Checked.(~-), Checked.(~-), Checked.(~-), ignore, ignore, ignore, ignore, Checked.(~-), Checked.(~-)) v1
+ | _ ->
+ errorR (Error ( FSComp.SR.tastNotAConstantExpression(), v1.Range))
+ x
+ | SpecificUnopExpr g g.unchecked_unary_plus_vref arg1 when arithmeticInLiteralsEnabled ->
+ EvalArithUnOp ((~+), (~+), (~+), (~+), (~+), (~+), (~+), (~+), (~+), (~+)) (EvalAttribArgExpr g arg1)
+ | SpecificUnopExpr g g.unchecked_unary_not_vref arg1 when arithmeticInLiteralsEnabled ->
+ match EvalAttribArgExpr g arg1 with
+ | Expr.Const (Const.Bool value, m, ty) ->
+ Expr.Const (Const.Bool (not value), m, ty)
+ | expr ->
+ errorR (Error ( FSComp.SR.tastNotAConstantExpression(), expr.Range))
+ x
+ // Detect logical operations on booleans, which are represented as a match expression
+ | Expr.Match (decision = TDSwitch (input = input; cases = [ TCase (DecisionTreeTest.Const (Const.Bool test), TDSuccess ([], targetNum)) ]); targets = [| TTarget (_, t0, _); TTarget (_, t1, _) |]) when arithmeticInLiteralsEnabled ->
+ match EvalAttribArgExpr g (stripDebugPoints input) with
+ | Expr.Const (Const.Bool value, _, _) ->
+ let pass, fail =
+ if targetNum = 0 then
+ t0, t1
+ else
+ t1, t0
+
+ if value = test then
+ EvalAttribArgExpr g (stripDebugPoints pass)
+ else
+ EvalAttribArgExpr g (stripDebugPoints fail)
+ | _ ->
+ errorR (Error ( FSComp.SR.tastNotAConstantExpression(), x.Range))
+ x
| _ ->
errorR (Error ( FSComp.SR.tastNotAConstantExpression(), x.Range))
x
-
and EvaledAttribExprEquality g e1 e2 =
match e1, e2 with
| Expr.Const (c1, _, _), Expr.Const (c2, _, _) -> c1 = c2
diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf
index 9f1b557acbe..8d85893b378 100644
--- a/src/Compiler/xlf/FSComp.txt.cs.xlf
+++ b/src/Compiler/xlf/FSComp.txt.cs.xlf
@@ -142,6 +142,11 @@
aplikativní výpočetní výrazy
+
+ Allow arithmetic and logical operations in literals
+ Allow arithmetic and logical operations in literals
+
+
attributes to the right of the 'module' keyword
atributy napravo od klíčového slova Module
diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf
index fad70824e36..e87c63bfcd0 100644
--- a/src/Compiler/xlf/FSComp.txt.de.xlf
+++ b/src/Compiler/xlf/FSComp.txt.de.xlf
@@ -142,6 +142,11 @@
applikative Berechnungsausdrücke
+
+ Allow arithmetic and logical operations in literals
+ Allow arithmetic and logical operations in literals
+
+
attributes to the right of the 'module' keyword
Attribute rechts vom "Module"-Schlüsselwort
diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf
index 5402a968afd..3a1456ea3d9 100644
--- a/src/Compiler/xlf/FSComp.txt.es.xlf
+++ b/src/Compiler/xlf/FSComp.txt.es.xlf
@@ -142,6 +142,11 @@
expresiones de cálculo aplicativas
+
+ Allow arithmetic and logical operations in literals
+ Allow arithmetic and logical operations in literals
+
+
attributes to the right of the 'module' keyword
atributos a la derecha de la palabra clave “módulo”
diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf
index aadf83ade0e..afb7f7f19a3 100644
--- a/src/Compiler/xlf/FSComp.txt.fr.xlf
+++ b/src/Compiler/xlf/FSComp.txt.fr.xlf
@@ -142,6 +142,11 @@
expressions de calcul applicatives
+
+ Allow arithmetic and logical operations in literals
+ Allow arithmetic and logical operations in literals
+
+
attributes to the right of the 'module' keyword
attributs à droite du mot clé 'module'
diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf
index 8b681eb4a16..740e6a00e52 100644
--- a/src/Compiler/xlf/FSComp.txt.it.xlf
+++ b/src/Compiler/xlf/FSComp.txt.it.xlf
@@ -142,6 +142,11 @@
espressioni di calcolo applicativo
+
+ Allow arithmetic and logical operations in literals
+ Allow arithmetic and logical operations in literals
+
+
attributes to the right of the 'module' keyword
attributi a destra della parola chiave 'module'
diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf
index 4b6c944481a..86cc15b831a 100644
--- a/src/Compiler/xlf/FSComp.txt.ja.xlf
+++ b/src/Compiler/xlf/FSComp.txt.ja.xlf
@@ -142,6 +142,11 @@
適用できる計算式
+
+ Allow arithmetic and logical operations in literals
+ Allow arithmetic and logical operations in literals
+
+
attributes to the right of the 'module' keyword
'module' キーワードの右側の属性
diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf
index 40973f9e1a9..8646d198ed0 100644
--- a/src/Compiler/xlf/FSComp.txt.ko.xlf
+++ b/src/Compiler/xlf/FSComp.txt.ko.xlf
@@ -142,6 +142,11 @@
적용 가능한 계산 식
+
+ Allow arithmetic and logical operations in literals
+ Allow arithmetic and logical operations in literals
+
+
attributes to the right of the 'module' keyword
'module' 키워드 오른쪽에 있는 특성
diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf
index 9b4b9dab2eb..dc3641eb63d 100644
--- a/src/Compiler/xlf/FSComp.txt.pl.xlf
+++ b/src/Compiler/xlf/FSComp.txt.pl.xlf
@@ -142,6 +142,11 @@
praktyczne wyrażenia obliczeniowe
+
+ Allow arithmetic and logical operations in literals
+ Allow arithmetic and logical operations in literals
+
+
attributes to the right of the 'module' keyword
atrybuty po prawej stronie słowa kluczowego "module"
diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf
index 3307d01761c..61a9f9ea4dc 100644
--- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf
+++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf
@@ -142,6 +142,11 @@
expressões de computação aplicáveis
+
+ Allow arithmetic and logical operations in literals
+ Allow arithmetic and logical operations in literals
+
+
attributes to the right of the 'module' keyword
atributos à direita da palavra-chave 'módulo'
diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf
index d9de5f772a1..1ba03c032df 100644
--- a/src/Compiler/xlf/FSComp.txt.ru.xlf
+++ b/src/Compiler/xlf/FSComp.txt.ru.xlf
@@ -142,6 +142,11 @@
применимые вычислительные выражения
+
+ Allow arithmetic and logical operations in literals
+ Allow arithmetic and logical operations in literals
+
+
attributes to the right of the 'module' keyword
атрибуты справа от ключевого слова "module"
diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf
index 3cd9f827dc1..0f032aabdc7 100644
--- a/src/Compiler/xlf/FSComp.txt.tr.xlf
+++ b/src/Compiler/xlf/FSComp.txt.tr.xlf
@@ -142,6 +142,11 @@
uygulama hesaplama ifadeleri
+
+ Allow arithmetic and logical operations in literals
+ Allow arithmetic and logical operations in literals
+
+
attributes to the right of the 'module' keyword
'modül' anahtar sözcüğünün sağındaki öznitelikler
diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf
index d733d0c1038..73811a9fe0a 100644
--- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf
+++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf
@@ -142,6 +142,11 @@
适用的计算表达式
+
+ Allow arithmetic and logical operations in literals
+ Allow arithmetic and logical operations in literals
+
+
attributes to the right of the 'module' keyword
"module" 关键字右侧的属性
diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf
index 1d7aec7be9d..9fef8008dff 100644
--- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf
+++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf
@@ -142,6 +142,11 @@
適用的計算運算式
+
+ Allow arithmetic and logical operations in literals
+ Allow arithmetic and logical operations in literals
+
+
attributes to the right of the 'module' keyword
'module' 關鍵字右邊的屬性
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/DeclarationElements/CustomAttributes/AttributeUsage/AttributeUsage.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/DeclarationElements/CustomAttributes/AttributeUsage/AttributeUsage.fs
index 0161db9cd6e..52c055d71a4 100644
--- a/tests/FSharp.Compiler.ComponentTests/Conformance/DeclarationElements/CustomAttributes/AttributeUsage/AttributeUsage.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/DeclarationElements/CustomAttributes/AttributeUsage/AttributeUsage.fs
@@ -127,17 +127,6 @@ module AttributeUsage =
(Error 685, Line 20, Col 5, Line 20, Col 10, "The generic function 'Foo' must be given explicit type argument(s)")
]
- // # SOURCE=E_WithBitwiseAnd01.fsx SCFLAGS="--test:ErrorRanges -a" # E_WithBitwiseAnd01.fsx
- []
- let ``E_WithBitwiseAnd01_fsx`` compilation =
- compilation
- |> verifyCompile
- |> shouldFail
- |> withDiagnostics [
- (Error 267, Line 7, Col 25, Line 7, Col 91, "This is not a valid constant expression or custom attribute value")
- (Warning 839, Line 12, Col 3, Line 12, Col 6, "Unexpected condition in imported assembly: failed to decode AttributeUsage attribute")
- ]
-
// SOURCE=E_WithBitwiseOr01.fsx SCFLAGS="--test:ErrorRanges -a" # E_WithBitwiseOr01.fsx
[]
let ``E_WithBitwiseOr01_fsx`` compilation =
diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/DeclarationElements/CustomAttributes/AttributeUsage/E_WithBitwiseAnd01.fsx b/tests/FSharp.Compiler.ComponentTests/Conformance/DeclarationElements/CustomAttributes/AttributeUsage/E_WithBitwiseAnd01.fsx
deleted file mode 100644
index 1d541b626e2..00000000000
--- a/tests/FSharp.Compiler.ComponentTests/Conformance/DeclarationElements/CustomAttributes/AttributeUsage/E_WithBitwiseAnd01.fsx
+++ /dev/null
@@ -1,13 +0,0 @@
-// #Regression #Conformance #DeclarationElements #Attributes
-// Regression test for FSHARP1.0:4035
-// Using bitwise AND (&&&) in AttributeUsage should give a reasonable error
-//Review when fixed
-#light
-
-[]
-[]
-type FooAttribute() =
- inherit System.Attribute()
-
-[]
-let x = 1
diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
index 40092066b38..570f22d1377 100644
--- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
+++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Literals.fs
@@ -24,3 +24,207 @@ let main _ =
|> verifyIL ["""
.field public static literal int32 x = int32(0x00000007)
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.LiteralAttribute::.ctor() = ( 01 00 00 00 )"""]
+
+
+ []
+ let ``Arithmetic in integer literals is evaluated at compile time``() =
+ FSharp """
+module LiteralArithmetic
+
+let [] bytesInMegabyte = 1024L * 1024L
+
+let [] bytesInKilobyte = bytesInMegabyte >>> 10
+
+let [] bytesInKilobyte2 = bytesInMegabyte / 1024L
+
+let [] secondsInDayPlusThree = 3 + (60 * 60 * 24)
+
+let [] bitwise = 1us &&& (3us ||| 4us)
+ """
+ |> withLangVersionPreview
+ |> compile
+ |> shouldSucceed
+ |> verifyIL [
+ """.field public static literal int64 bytesInMegabyte = int64(0x100000)"""
+ """.field public static literal int64 bytesInKilobyte = int64(0x400)"""
+ """.field public static literal int64 bytesInKilobyte2 = int64(0x400)"""
+ """.field public static literal int32 secondsInDayPlusThree = int32(0x00015183)"""
+ """.field public static literal uint16 bitwise = uint16(0x0001)"""
+ ]
+
+ []
+ let ``Arithmetic in char and floating point literals is evaluated at compile time``() =
+ // on Linux and Mac floats with no decimal parts are printed without the decimal point (unlike Windows)
+ // let's add some fractions so that the tests are consistent
+ FSharp """
+module LiteralArithmetic
+
+let [] bytesInMegabyte = 1024. * 1024. + 0.1
+
+let [] bytesInKilobyte = bytesInMegabyte / 1024. + 0.1
+
+let [] secondsInDayPlusThree = 3.1f + (60f * 60f * 24f)
+
+let [] chars = 'a' + 'b' - 'a'
+ """
+ |> withLangVersionPreview
+ |> compile
+ |> shouldSucceed
+ |> verifyIL [
+ """.field public static literal float64 bytesInMegabyte = float64(1048576.1000000001)"""
+ """.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)"""
+ ]
+
+ []
+ let ``Logical operations on booleans are evaluated at compile time``() =
+ FSharp """
+module LiteralArithmetic
+
+let [] flag = true
+
+let [] flippedFlag = not flag
+
+let [] simple1 = flippedFlag || false
+
+let [] simple2 = true && not true
+
+let [] complex1 = false || (flag && not flippedFlag)
+
+let [] complex2 = false || (flag && flippedFlag)
+
+let [] complex3 = true || (flag && not flippedFlag)
+ """
+ |> withLangVersionPreview
+ |> compile
+ |> shouldSucceed
+ |> verifyIL [
+ """.field public static literal bool flag = bool(true)"""
+ """.field public static literal bool flippedFlag = bool(false)"""
+ """.field public static literal bool simple1 = bool(false)"""
+ """.field public static literal bool simple2 = bool(false)"""
+ """.field public static literal bool complex1 = bool(true)"""
+ """.field public static literal bool complex2 = bool(false)"""
+ """.field public static literal bool complex3 = bool(true)"""
+ ]
+
+ []
+ let ``Arithmetic can be used for constructing enum literals``() =
+ FSharp """
+module LiteralArithmetic
+
+type E =
+ | A = 1
+ | B = 2
+
+let [] x = enum (1 + 1)
+ """
+ |> withLangVersionPreview
+ |> compile
+ |> shouldSucceed
+ |> verifyIL [
+ """.field public static literal valuetype LiteralArithmetic/E x = int32(0x00000002)"""
+ ]
+
+ []
+ let ``Arithmetic can be used for constructing literals in attributes``() =
+ FSharp """
+module LiteralArithmetic
+
+open System.Runtime.CompilerServices
+
+// 256 = AggressiveInlining
+[]
+let x () =
+ 3
+ """
+ |> withLangVersionPreview
+ |> compile
+ |> shouldSucceed
+ |> verifyIL [
+ """.method public static int32 x() cil managed aggressiveinlining"""
+ ]
+
+ []
+ let ``Compilation fails when addition in literal overflows``() =
+ FSharp """
+module LiteralArithmetic
+
+let [] x = System.Int32.MaxValue + 1
+ """
+ |> withLangVersionPreview
+ |> compile
+ |> shouldFail
+ |> withResult {
+ Error = Error 3177
+ Range = { StartLine = 4
+ StartColumn = 21
+ EndLine = 4
+ EndColumn = 46 }
+ Message = "This literal expression or attribute argument results in an arithmetic overflow."
+ }
+
+ []
+ let ``Compilation fails when using decimal arithmetic in literal``() =
+ FSharp """
+module LiteralArithmetic
+
+let [] x = 1m + 1m
+ """
+ |> withLangVersionPreview
+ |> compile
+ |> shouldFail
+ |> withResults [
+ { Error = Error 267
+ Range = { StartLine = 4
+ StartColumn = 21
+ EndLine = 4
+ EndColumn = 23 }
+ Message = "This is not a valid constant expression or custom attribute value" }
+ { Error = Error 267
+ Range = { StartLine = 4
+ StartColumn = 26
+ EndLine = 4
+ EndColumn = 28 }
+ Message = "This is not a valid constant expression or custom attribute value" }
+ { Error = Error 267
+ Range = { StartLine = 4
+ StartColumn = 21
+ EndLine = 4
+ EndColumn = 28 }
+ Message = "This is not a valid constant expression or custom attribute value" }
+ ]
+
+ []
+ let ``Compilation fails when using arithmetic with a non-literal in literal``() =
+ FSharp """
+module LiteralArithmetic
+
+let [] x = 1 + System.DateTime.Now.Hour
+ """
+ |> withLangVersionPreview
+ |> compile
+ |> shouldFail
+ |> withResults [
+#if !NETCOREAPP
+ { Error = Warning 52
+ Range = { StartLine = 4
+ StartColumn = 25
+ EndLine = 4
+ EndColumn = 49 }
+ Message = "The value has been copied to ensure the original is not mutated by this operation or because the copy is implicit when returning a struct from a member and another member is then accessed" }
+#endif
+ { Error = Error 267
+ Range = { StartLine = 4
+ StartColumn = 25
+ EndLine = 4
+ EndColumn = 49 }
+ Message = "This is not a valid constant expression or custom attribute value" }
+ { Error = Error 267
+ Range = { StartLine = 4
+ StartColumn = 21
+ EndLine = 4
+ EndColumn = 49 }
+ Message = "This is not a valid constant expression or custom attribute value" }
+ ]
\ No newline at end of file