Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -579,15 +579,13 @@ module TcRecdUnionAndEnumDeclarations =
| SynExpr.Const (synConst, _) ->
let konst = TcConst cenv fieldTy valueRange env synConst
MakeEnumCaseSpec cenv env parent attrs thisTy caseRange id xmldoc konst
| _ when cenv.g.langVersion.SupportsFeature LanguageFeature.ArithmeticInLiterals ->
| _ ->
let expr, actualTy, _ = TcExprOfUnknownType cenv env tpenv valueExpr
UnifyTypes cenv env valueRange fieldTy actualTy

match EvalLiteralExprOrAttribArg cenv.g expr with
| Expr.Const (konst, _, _) -> MakeEnumCaseSpec cenv env parent attrs thisTy caseRange id xmldoc konst
| _ -> error(Error(FSComp.SR.tcInvalidEnumerationLiteral(), valueRange))
| _ ->
error(Error(FSComp.SR.tcInvalidEnumerationLiteral(), valueRange))

let TcEnumDecls (cenv: cenv) env tpenv parent thisTy enumCases =
let g = cenv.g
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1559,7 +1559,7 @@ featureMatchNotAllowedForUnionCaseWithNoData,"Pattern match discard is not allow
featureCSharpExtensionAttributeNotRequired,"Allow implicit Extension attribute on declaring types, modules"
featureErrorForNonVirtualMembersOverrides,"Raises errors for non-virtual members overrides"
featureWarningWhenInliningMethodImplNoInlineMarkedFunction,"Raises warnings when 'let inline ... =' is used together with [<MethodImpl(MethodImplOptions.NoInlining)>] attribute. Function is not getting inlined."
featureArithmeticInLiterals,"Allow arithmetic and logical operations in literals"
featureArithmeticInLiterals,"Arithmetic and logical operations in literals, enum definitions and attributes"
featureErrorReportingOnStaticClasses,"Error reporting on static classes"
featureTryWithInSeqExpressions,"Support for try-with in sequence expressions"
featureWarningWhenCopyAndUpdateRecordChangesAllFields,"Raises warnings when an copy-and-update record expression changes all fields of a record."
Expand Down
7 changes: 7 additions & 0 deletions src/Compiler/Facilities/DiagnosticsLogger.fs
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,13 @@ let NormalizeErrorString (text: string MaybeNull) =

buf.ToString()

/// Indicates whether a language feature check should be skipped. Typically used in recursive functions
/// where we don't want repeated recursive calls to raise the same diagnostic multiple times.
[<RequireQualifiedAccess>]
type internal SuppressLanguageFeatureCheck =
| Yes
| No

let private tryLanguageFeatureErrorAux (langVersion: LanguageVersion) (langFeature: LanguageFeature) (m: range) =
if not (langVersion.SupportsFeature langFeature) then
let featureStr = LanguageVersion.GetFeatureString langFeature
Expand Down
7 changes: 7 additions & 0 deletions src/Compiler/Facilities/DiagnosticsLogger.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,13 @@ val NewlineifyErrorString: message: string -> string
/// which is decoded by the IDE with 'NewlineifyErrorString' back into newlines, so that multi-line errors can be displayed in QuickInfo
val NormalizeErrorString: text: string -> string

/// Indicates whether a language feature check should be skipped. Typically used in recursive functions
/// where we don't want repeated recursive calls to raise the same diagnostic multiple times.
[<RequireQualifiedAccess>]
type SuppressLanguageFeatureCheck =
| Yes
| No

val checkLanguageFeatureError: langVersion: LanguageVersion -> langFeature: LanguageFeature -> m: range -> unit

val checkLanguageFeatureAndRecover: langVersion: LanguageVersion -> langFeature: LanguageFeature -> m: range -> unit
Expand Down
96 changes: 55 additions & 41 deletions src/Compiler/TypedTree/TypedTreeOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9659,11 +9659,13 @@ let EvalArithBinOp (opInt8, opInt16, opInt32, opInt64, opUInt8, opUInt16, opUInt
with :? System.OverflowException -> error (Error ( FSComp.SR.tastConstantExpressionOverflow(), m))

// See also PostTypeCheckSemanticChecks.CheckAttribArgExpr, which must match this precisely
let rec EvalAttribArgExpr (g: TcGlobals) x =
let rec EvalAttribArgExpr suppressLangFeatureCheck (g: TcGlobals) (x: Expr) =
let ignore (_x: 'a) = Unchecked.defaultof<'a>
let ignore2 (_x: 'a) (_y: 'a) = Unchecked.defaultof<'a>

let arithmeticInLiteralsEnabled = g.langVersion.SupportsFeature LanguageFeature.ArithmeticInLiterals
let inline checkFeature() =
if suppressLangFeatureCheck = SuppressLanguageFeatureCheck.No then
checkLanguageFeatureAndRecover g.langVersion LanguageFeature.ArithmeticInLiterals x.Range

match x with

Expand Down Expand Up @@ -9693,80 +9695,92 @@ let rec EvalAttribArgExpr (g: TcGlobals) x =
| TypeOfExpr g _ -> x
| TypeDefOfExpr g _ -> x
| Expr.Op (TOp.Coerce, _, [arg], _) ->
EvalAttribArgExpr g arg
EvalAttribArgExpr suppressLangFeatureCheck g arg
| EnumExpr g arg1 ->
EvalAttribArgExpr g arg1
EvalAttribArgExpr suppressLangFeatureCheck g arg1
// Detect bitwise or of attribute flags
| AttribBitwiseOrExpr g (arg1, arg2) ->
let v1 = EvalAttribArgExpr g arg1
let v1 = EvalAttribArgExpr suppressLangFeatureCheck g arg1

match v1 with
| IntegerConstExpr ->
EvalArithBinOp ((|||), (|||), (|||), (|||), (|||), (|||), (|||), (|||), ignore2, ignore2) v1 (EvalAttribArgExpr g arg2)
EvalArithBinOp ((|||), (|||), (|||), (|||), (|||), (|||), (|||), (|||), ignore2, ignore2) v1 (EvalAttribArgExpr suppressLangFeatureCheck 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
let v1, v2 = EvalAttribArgExpr suppressLangFeatureCheck g arg1, EvalAttribArgExpr suppressLangFeatureCheck 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, m, ty), Expr.Const (Const.Char x2, _, _) ->
checkFeature()
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
checkFeature()
EvalArithBinOp (Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+), Checked.(+)) v1 v2
| SpecificBinopExpr g g.unchecked_subtraction_vref (arg1, arg2) ->
checkFeature()
let v1, v2 = EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1, EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes 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
| SpecificBinopExpr g g.unchecked_multiply_vref (arg1, arg2) ->
checkFeature()
EvalArithBinOp (Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*), Checked.(*)) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg2)
| SpecificBinopExpr g g.unchecked_division_vref (arg1, arg2) ->
checkFeature()
EvalArithBinOp ((/), (/), (/), (/), (/), (/), (/), (/), (/), (/)) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg2)
| SpecificBinopExpr g g.unchecked_modulus_vref (arg1, arg2) ->
checkFeature()
EvalArithBinOp ((%), (%), (%), (%), (%), (%), (%), (%), (%), (%)) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg2)
| SpecificBinopExpr g g.bitwise_shift_left_vref (arg1, arg2) ->
checkFeature()
EvalArithShiftOp ((<<<), (<<<), (<<<), (<<<), (<<<), (<<<), (<<<), (<<<)) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg2)
| SpecificBinopExpr g g.bitwise_shift_right_vref (arg1, arg2) ->
checkFeature()
EvalArithShiftOp ((>>>), (>>>), (>>>), (>>>), (>>>), (>>>), (>>>), (>>>)) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg2)
| SpecificBinopExpr g g.bitwise_and_vref (arg1, arg2) ->
checkFeature()
let v1 = EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1

match v1 with
| IntegerConstExpr ->
EvalArithBinOp ((&&&), (&&&), (&&&), (&&&), (&&&), (&&&), (&&&), (&&&), ignore2, ignore2) v1 (EvalAttribArgExpr g arg2)
EvalArithBinOp ((&&&), (&&&), (&&&), (&&&), (&&&), (&&&), (&&&), (&&&), ignore2, ignore2) v1 (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes 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
| SpecificUnopExpr g g.unchecked_unary_minus_vref arg1 ->
checkFeature()
let v1 = EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes 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
| SpecificUnopExpr g g.unchecked_unary_plus_vref arg1 ->
checkFeature()
EvalArithUnOp ((~+), (~+), (~+), (~+), (~+), (~+), (~+), (~+), (~+), (~+)) (EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g arg1)
| SpecificUnopExpr g g.unchecked_unary_not_vref arg1 ->
checkFeature()

match EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes 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.Match (decision = TDSwitch (input = input; cases = [ TCase (DecisionTreeTest.Const (Const.Bool test), TDSuccess ([], targetNum)) ]); targets = [| TTarget (_, t0, _); TTarget (_, t1, _) |]) ->
checkFeature()

match EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g (stripDebugPoints input) with
| Expr.Const (Const.Bool value, _, _) ->
let pass, fail =
if targetNum = 0 then
Expand All @@ -9775,9 +9789,9 @@ let rec EvalAttribArgExpr (g: TcGlobals) x =
t1, t0

if value = test then
EvalAttribArgExpr g (stripDebugPoints pass)
EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g (stripDebugPoints pass)
else
EvalAttribArgExpr g (stripDebugPoints fail)
EvalAttribArgExpr SuppressLanguageFeatureCheck.Yes g (stripDebugPoints fail)
| _ ->
errorR (Error ( FSComp.SR.tastNotAConstantExpression(), x.Range))
x
Expand Down Expand Up @@ -9814,10 +9828,10 @@ let EvalLiteralExprOrAttribArg g x =
match x with
| Expr.Op (TOp.Coerce, _, [Expr.Op (TOp.Array, [elemTy], args, m)], _)
| Expr.Op (TOp.Array, [elemTy], args, m) ->
let args = args |> List.map (EvalAttribArgExpr g)
let args = args |> List.map (EvalAttribArgExpr SuppressLanguageFeatureCheck.No g)
Expr.Op (TOp.Array, [elemTy], args, m)
| _ ->
EvalAttribArgExpr g x
EvalAttribArgExpr SuppressLanguageFeatureCheck.No g x

// Take into account the fact that some "instance" members are compiled as static
// members when using CompilationRepresentation.Static, or any non-virtual instance members
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/xlf/FSComp.txt.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@
<note />
</trans-unit>
<trans-unit id="featureArithmeticInLiterals">
<source>Allow arithmetic and logical operations in literals</source>
<target state="translated">Povolit aritmetické a logické operace v literálech</target>
<source>Arithmetic and logical operations in literals, enum definitions and attributes</source>
<target state="needs-review-translation">Povolit aritmetické a logické operace v literálech</target>
<note />
</trans-unit>
<trans-unit id="featureAttributesToRightOfModuleKeyword">
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/xlf/FSComp.txt.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@
<note />
</trans-unit>
<trans-unit id="featureArithmeticInLiterals">
<source>Allow arithmetic and logical operations in literals</source>
<target state="translated">Arithmetische und logische Vorgänge in Literalen zulassen</target>
<source>Arithmetic and logical operations in literals, enum definitions and attributes</source>
<target state="needs-review-translation">Arithmetische und logische Vorgänge in Literalen zulassen</target>
<note />
</trans-unit>
<trans-unit id="featureAttributesToRightOfModuleKeyword">
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/xlf/FSComp.txt.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@
<note />
</trans-unit>
<trans-unit id="featureArithmeticInLiterals">
<source>Allow arithmetic and logical operations in literals</source>
<target state="translated">Permitir operaciones aritméticas y lógicas en literales</target>
<source>Arithmetic and logical operations in literals, enum definitions and attributes</source>
<target state="needs-review-translation">Permitir operaciones aritméticas y lógicas en literales</target>
<note />
</trans-unit>
<trans-unit id="featureAttributesToRightOfModuleKeyword">
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/xlf/FSComp.txt.fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@
<note />
</trans-unit>
<trans-unit id="featureArithmeticInLiterals">
<source>Allow arithmetic and logical operations in literals</source>
<target state="translated">Autoriser les opérations arithmétiques et logiques dans les littéraux</target>
<source>Arithmetic and logical operations in literals, enum definitions and attributes</source>
<target state="needs-review-translation">Autoriser les opérations arithmétiques et logiques dans les littéraux</target>
<note />
</trans-unit>
<trans-unit id="featureAttributesToRightOfModuleKeyword">
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/xlf/FSComp.txt.it.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@
<note />
</trans-unit>
<trans-unit id="featureArithmeticInLiterals">
<source>Allow arithmetic and logical operations in literals</source>
<target state="translated">Consentire operazioni aritmetiche e logiche in valori letterali</target>
<source>Arithmetic and logical operations in literals, enum definitions and attributes</source>
<target state="needs-review-translation">Consentire operazioni aritmetiche e logiche in valori letterali</target>
<note />
</trans-unit>
<trans-unit id="featureAttributesToRightOfModuleKeyword">
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/xlf/FSComp.txt.ja.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@
<note />
</trans-unit>
<trans-unit id="featureArithmeticInLiterals">
<source>Allow arithmetic and logical operations in literals</source>
<target state="translated">リテラルで算術演算と論理演算を許可する</target>
<source>Arithmetic and logical operations in literals, enum definitions and attributes</source>
<target state="needs-review-translation">リテラルで算術演算と論理演算を許可する</target>
<note />
</trans-unit>
<trans-unit id="featureAttributesToRightOfModuleKeyword">
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/xlf/FSComp.txt.ko.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@
<note />
</trans-unit>
<trans-unit id="featureArithmeticInLiterals">
<source>Allow arithmetic and logical operations in literals</source>
<target state="translated">리터럴에서 산술 및 논리 연산 허용</target>
<source>Arithmetic and logical operations in literals, enum definitions and attributes</source>
<target state="needs-review-translation">리터럴에서 산술 및 논리 연산 허용</target>
<note />
</trans-unit>
<trans-unit id="featureAttributesToRightOfModuleKeyword">
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/xlf/FSComp.txt.pl.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@
<note />
</trans-unit>
<trans-unit id="featureArithmeticInLiterals">
<source>Allow arithmetic and logical operations in literals</source>
<target state="translated">Zezwalaj na operacje arytmetyczne i logiczne w literałach</target>
<source>Arithmetic and logical operations in literals, enum definitions and attributes</source>
<target state="needs-review-translation">Zezwalaj na operacje arytmetyczne i logiczne w literałach</target>
<note />
</trans-unit>
<trans-unit id="featureAttributesToRightOfModuleKeyword">
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/xlf/FSComp.txt.pt-BR.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@
<note />
</trans-unit>
<trans-unit id="featureArithmeticInLiterals">
<source>Allow arithmetic and logical operations in literals</source>
<target state="translated">Permitir operações aritméticas e lógicas em literais</target>
<source>Arithmetic and logical operations in literals, enum definitions and attributes</source>
<target state="needs-review-translation">Permitir operações aritméticas e lógicas em literais</target>
<note />
</trans-unit>
<trans-unit id="featureAttributesToRightOfModuleKeyword">
Expand Down
Loading