From 1799aaf29034f01357684c7716b6eed8fc76468a Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Wed, 23 Apr 2025 15:27:24 +0100 Subject: [PATCH 01/39] make attribute targets mismatches a warning and not an error. --- .../Checking/Expressions/CheckExpressions.fs | 2 +- .../AttributeUsage/AttributeUsage.fs | 215 +++++++++--------- .../CustomAttributes/Basic/Basic.fs | 7 +- .../EntryPoint/EntryPoint.fs | 2 +- .../LetBindings/Basic/Basic.fs | 4 +- .../ErrorMessages/TailCallAttribute.fs | 32 +-- 6 files changed, 125 insertions(+), 137 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 5f390038e35..e2d21975311 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -11367,7 +11367,7 @@ and TcAttributeEx canFail (cenv: cenv) (env: TcEnv) attrTgt attrEx (synAttr: Syn if (directedTgts = AttributeTargets.Assembly || directedTgts = AttributeTargets.Module) then error(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElementUseDo(), mAttr)) else - error(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElement(), mAttr)) + warning(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElement(), mAttr)) match ResolveObjectConstructor cenv.nameResolver env.DisplayEnv mAttr ad ty with | Exception _ when canFail = TcCanFail.IgnoreAllErrors || canFail = TcCanFail.IgnoreMemberResoutionError -> [ ], true diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs index c7c2cf72eca..f027745b73e 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs @@ -104,10 +104,10 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 21, Col 21, Line 21, Col 22, "This attribute is not valid for use on this language element") - (Error 842, Line 24, Col 21, Line 24, Col 29, "This attribute is not valid for use on this language element") - (Error 842, Line 27, Col 7, Line 27, Col 16, "This attribute is not valid for use on this language element") - (Error 842, Line 18, Col 7, Line 18, Col 8, "This attribute is not valid for use on this language element") + (Warning 842, Line 21, Col 21, Line 21, Col 22, "This attribute is not valid for use on this language element") + (Warning 842, Line 24, Col 21, Line 24, Col 29, "This attribute is not valid for use on this language element") + (Warning 842, Line 27, Col 7, Line 27, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 18, Col 7, Line 18, Col 8, "This attribute is not valid for use on this language element") ] // SOURCE=E_AttributeTargets02.fs # E_AttributeTargets02.fs @@ -117,9 +117,10 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 14, Col 7, Line 14, Col 34, "This attribute is not valid for use on this language element") - (Error 842, Line 24, Col 7, Line 24, Col 36, "This attribute is not valid for use on this language element") - (Error 842, Line 29, Col 15, Line 29, Col 47, "This attribute is not valid for use on this language element") + (Warning 842, Line 14, Col 7, Line 14, Col 34, "This attribute is not valid for use on this language element") + (Warning 842, Line 24, Col 7, Line 24, Col 36, "This attribute is not valid for use on this language element") + (Warning 842, Line 29, Col 15, Line 29, Col 47, "This attribute is not valid for use on this language element") + (Error 3172, Line 28, Col 14, Line 28, Col 17, "A property's getter and setter must have the same type. Property 'Foo' has getter of type 'int' but setter of type 'obj'.") ] // SOURCE=E_AttributeTargetIsField01.fs # E_AttributeTargetIsField01.fs @@ -140,23 +141,23 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 9, Col 3, Line 9, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 12, Col 3, Line 12, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 15, Col 3, Line 15, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 18, Col 3, Line 18, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 21, Col 3, Line 21, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 24, Col 3, Line 24, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 27, Col 3, Line 27, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 30, Col 3, Line 30, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 33, Col 3, Line 33, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 36, Col 3, Line 36, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 39, Col 3, Line 39, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 42, Col 3, Line 42, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 45, Col 3, Line 45, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 49, Col 3, Line 49, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 56, Col 3, Line 56, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 64, Col 3, Line 64, Col 12, "This attribute is not valid for use on this language element") - (Error 842, Line 66, Col 7, Line 66, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 9, Col 3, Line 9, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 12, Col 3, Line 12, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 15, Col 3, Line 15, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 18, Col 3, Line 18, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 21, Col 3, Line 21, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 24, Col 3, Line 24, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 27, Col 3, Line 27, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 30, Col 3, Line 30, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 33, Col 3, Line 33, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 36, Col 3, Line 36, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 39, Col 3, Line 39, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 42, Col 3, Line 42, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 45, Col 3, Line 45, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 49, Col 3, Line 49, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 56, Col 3, Line 56, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 64, Col 3, Line 64, Col 12, "This attribute is not valid for use on this language element") + (Warning 842, Line 66, Col 7, Line 66, Col 16, "This attribute is not valid for use on this language element") ] // SOURCE=E_AttributeTargetIsField02.fs # E_AttributeTargetIsField02.fs @@ -194,17 +195,17 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 9, Col 3, Line 9, Col 13, "This attribute is not valid for use on this language element") - (Error 842, Line 12, Col 3, Line 12, Col 13, "This attribute is not valid for use on this language element") - (Error 842, Line 15, Col 3, Line 15, Col 13, "This attribute is not valid for use on this language element") - (Error 842, Line 18, Col 3, Line 18, Col 13, "This attribute is not valid for use on this language element") - (Error 842, Line 21, Col 3, Line 21, Col 13, "This attribute is not valid for use on this language element") - (Error 842, Line 24, Col 3, Line 24, Col 13, "This attribute is not valid for use on this language element") - (Error 842, Line 26, Col 7, Line 26, Col 17, "This attribute is not valid for use on this language element") - (Error 842, Line 28, Col 3, Line 28, Col 13, "This attribute is not valid for use on this language element") - (Error 842, Line 31, Col 3, Line 31, Col 13, "This attribute is not valid for use on this language element") - (Error 842, Line 34, Col 3, Line 34, Col 13, "This attribute is not valid for use on this language element") - (Error 842, Line 39, Col 3, Line 39, Col 13, "This attribute is not valid for use on this language element") + (Warning 842, Line 9, Col 3, Line 9, Col 13, "This attribute is not valid for use on this language element") + (Warning 842, Line 12, Col 3, Line 12, Col 13, "This attribute is not valid for use on this language element") + (Warning 842, Line 15, Col 3, Line 15, Col 13, "This attribute is not valid for use on this language element") + (Warning 842, Line 18, Col 3, Line 18, Col 13, "This attribute is not valid for use on this language element") + (Warning 842, Line 21, Col 3, Line 21, Col 13, "This attribute is not valid for use on this language element") + (Warning 842, Line 24, Col 3, Line 24, Col 13, "This attribute is not valid for use on this language element") + (Warning 842, Line 26, Col 7, Line 26, Col 17, "This attribute is not valid for use on this language element") + (Warning 842, Line 28, Col 3, Line 28, Col 13, "This attribute is not valid for use on this language element") + (Warning 842, Line 31, Col 3, Line 31, Col 13, "This attribute is not valid for use on this language element") + (Warning 842, Line 34, Col 3, Line 34, Col 13, "This attribute is not valid for use on this language element") + (Warning 842, Line 39, Col 3, Line 39, Col 13, "This attribute is not valid for use on this language element") ] // SOURCE=E_AttributeTargetIsMethod03.fs # E_AttributeTargetIsMethod03.fs @@ -225,21 +226,21 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 12, Col 6, Line 12, Col 16, "This attribute is not valid for use on this language element") - (Error 842, Line 15, Col 6, Line 15, Col 16, "This attribute is not valid for use on this language element") - (Error 842, Line 18, Col 6, Line 18, Col 16, "This attribute is not valid for use on this language element") - (Error 842, Line 20, Col 10, Line 20, Col 20, "This attribute is not valid for use on this language element") - (Error 842, Line 22, Col 6, Line 22, Col 16, "This attribute is not valid for use on this language element") - (Error 842, Line 25, Col 6, Line 25, Col 16, "This attribute is not valid for use on this language element") - (Error 842, Line 28, Col 6, Line 28, Col 16, "This attribute is not valid for use on this language element") - (Error 842, Line 31, Col 6, Line 31, Col 16, "This attribute is not valid for use on this language element") - (Error 842, Line 34, Col 6, Line 34, Col 16, "This attribute is not valid for use on this language element") - (Error 842, Line 37, Col 6, Line 37, Col 16, "This attribute is not valid for use on this language element") - (Error 842, Line 39, Col 10, Line 39, Col 20, "This attribute is not valid for use on this language element") - (Error 842, Line 41, Col 6, Line 41, Col 16, "This attribute is not valid for use on this language element") - (Error 842, Line 44, Col 6, Line 44, Col 16, "This attribute is not valid for use on this language element") - (Error 842, Line 47, Col 6, Line 47, Col 16, "This attribute is not valid for use on this language element") - (Error 842, Line 52, Col 6, Line 52, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 12, Col 6, Line 12, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 15, Col 6, Line 15, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 18, Col 6, Line 18, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 20, Col 10, Line 20, Col 20, "This attribute is not valid for use on this language element") + (Warning 842, Line 22, Col 6, Line 22, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 25, Col 6, Line 25, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 28, Col 6, Line 28, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 31, Col 6, Line 31, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 34, Col 6, Line 34, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 37, Col 6, Line 37, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 39, Col 10, Line 39, Col 20, "This attribute is not valid for use on this language element") + (Warning 842, Line 41, Col 6, Line 41, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 44, Col 6, Line 44, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 47, Col 6, Line 47, Col 16, "This attribute is not valid for use on this language element") + (Warning 842, Line 52, Col 6, Line 52, Col 16, "This attribute is not valid for use on this language element") ] // SOURCE=E_AttributeTargetIsMethod04.fs # E_AttributeTargetIsMethod04.fs @@ -250,8 +251,8 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 10, Col 3, Line 10, Col 15, "This attribute is not valid for use on this language element") - (Error 842, Line 13, Col 3, Line 13, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 10, Col 3, Line 10, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 13, Col 3, Line 13, Col 15, "This attribute is not valid for use on this language element") ] // SOURCE=E_ConditionalAttribute.fs SCFLAGS="--test:ErrorRanges" # E_ConditionalAttribute.fs @@ -293,7 +294,7 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 12, Col 3, Line 12, Col 6, "This attribute is not valid for use on this language element") + (Warning 842, Line 12, Col 3, Line 12, Col 6, "This attribute is not valid for use on this language element") ] // SOURCE=AttributeTargetIsStruct.fs # AttributeTargetIsStruct.fs @@ -342,18 +343,18 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 13, Col 3, Line 13, Col 14, "This attribute is not valid for use on this language element") - (Error 842, Line 19, Col 3, Line 19, Col 14, "This attribute is not valid for use on this language element") - (Error 842, Line 22, Col 11, Line 22, Col 22, "This attribute is not valid for use on this language element") - (Error 842, Line 25, Col 3, Line 25, Col 14, "This attribute is not valid for use on this language element") - (Error 842, Line 34, Col 3, Line 34, Col 18, "This attribute is not valid for use on this language element") - (Error 842, Line 35, Col 3, Line 35, Col 15, "This attribute is not valid for use on this language element") - (Error 842, Line 40, Col 3, Line 40, Col 14, "This attribute is not valid for use on this language element") - (Error 842, Line 41, Col 3, Line 41, Col 18, "This attribute is not valid for use on this language element") - (Error 842, Line 49, Col 3, Line 49, Col 18, "This attribute is not valid for use on this language element") - (Error 842, Line 50, Col 3, Line 50, Col 15, "This attribute is not valid for use on this language element") - (Error 842, Line 53, Col 3, Line 53, Col 14, "This attribute is not valid for use on this language element") - (Error 842, Line 54, Col 3, Line 54, Col 18, "This attribute is not valid for use on this language element") + (Warning 842, Line 13, Col 3, Line 13, Col 14, "This attribute is not valid for use on this language element") + (Warning 842, Line 19, Col 3, Line 19, Col 14, "This attribute is not valid for use on this language element") + (Warning 842, Line 22, Col 11, Line 22, Col 22, "This attribute is not valid for use on this language element") + (Warning 842, Line 25, Col 3, Line 25, Col 14, "This attribute is not valid for use on this language element") + (Warning 842, Line 34, Col 3, Line 34, Col 18, "This attribute is not valid for use on this language element") + (Warning 842, Line 35, Col 3, Line 35, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 40, Col 3, Line 40, Col 14, "This attribute is not valid for use on this language element") + (Warning 842, Line 41, Col 3, Line 41, Col 18, "This attribute is not valid for use on this language element") + (Warning 842, Line 49, Col 3, Line 49, Col 18, "This attribute is not valid for use on this language element") + (Warning 842, Line 50, Col 3, Line 50, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 53, Col 3, Line 53, Col 14, "This attribute is not valid for use on this language element") + (Warning 842, Line 54, Col 3, Line 54, Col 18, "This attribute is not valid for use on this language element") ] // SOURCE=E_AttributeTargetIsClass.fs # E_AttributeTargetIsClass.fs @@ -372,9 +373,9 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 13, Col 3, Line 13, Col 15, "This attribute is not valid for use on this language element") - (Error 842, Line 19, Col 3, Line 19, Col 15, "This attribute is not valid for use on this language element") - (Error 842, Line 22, Col 10, Line 22, Col 22, "This attribute is not valid for use on this language element") + (Warning 842, Line 13, Col 3, Line 13, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 19, Col 3, Line 19, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 22, Col 10, Line 22, Col 22, "This attribute is not valid for use on this language element") ] // SOURCE=E_AttributeTargetIsClass01.fs # E_AttributeTargetIsClass01.fs @@ -393,8 +394,8 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 7, Col 3, Line 7, Col 18, "This attribute is not valid for use on this language element") - (Error 842, Line 10, Col 10, Line 10, Col 25, "This attribute is not valid for use on this language element") + (Warning 842, Line 7, Col 3, Line 7, Col 18, "This attribute is not valid for use on this language element") + (Warning 842, Line 10, Col 10, Line 10, Col 25, "This attribute is not valid for use on this language element") ] // SOURCE=MarshalAsAttribute.fs # MarshalAsAttribute.fs @@ -480,7 +481,7 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 14, Col 5, Line 14, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 14, Col 5, Line 14, Col 15, "This attribute is not valid for use on this language element") ] // SOURCE=E_AttributeTargetIsField03.fs # E_AttributeTargetIsField03.fs @@ -491,8 +492,8 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 14, Col 5, Line 14, Col 15, "This attribute is not valid for use on this language element") - (Error 842, Line 15, Col 5, Line 15, Col 25, "This attribute is not valid for use on this language element") + (Warning 842, Line 14, Col 5, Line 14, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 15, Col 5, Line 15, Col 25, "This attribute is not valid for use on this language element") ] // SOURCE=E_AttributeTargetIsProperty01.fs # E_AttributeTargetIsField03.fs @@ -511,8 +512,8 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 14, Col 5, Line 14, Col 18, "This attribute is not valid for use on this language element") - (Error 842, Line 15, Col 5, Line 15, Col 25, "This attribute is not valid for use on this language element") + (Warning 842, Line 14, Col 5, Line 14, Col 18, "This attribute is not valid for use on this language element") + (Warning 842, Line 15, Col 5, Line 15, Col 25, "This attribute is not valid for use on this language element") ] // SOURCE=E_AttributeTargetIsCtor01.fs # E_AttributeTargetIsCtor01.fs @@ -531,10 +532,10 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 9, Col 15, Line 9, Col 27, "This attribute is not valid for use on this language element") - (Error 842, Line 11, Col 16, Line 11, Col 28, "This attribute is not valid for use on this language element") - (Error 842, Line 14, Col 15, Line 14, Col 27, "This attribute is not valid for use on this language element") - (Error 842, Line 17, Col 16, Line 17, Col 28, "This attribute is not valid for use on this language element") + (Warning 842, Line 9, Col 15, Line 9, Col 27, "This attribute is not valid for use on this language element") + (Warning 842, Line 11, Col 16, Line 11, Col 28, "This attribute is not valid for use on this language element") + (Warning 842, Line 14, Col 15, Line 14, Col 27, "This attribute is not valid for use on this language element") + (Warning 842, Line 17, Col 16, Line 17, Col 28, "This attribute is not valid for use on this language element") ] // SOURCE=AttributeTargetsIsEnum01.fs # AttributeTargetsIsEnum01.fs @@ -568,10 +569,10 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 19, Col 3, Line 19, Col 15, "This attribute is not valid for use on this language element") - (Error 842, Line 20, Col 3, Line 20, Col 14, "This attribute is not valid for use on this language element") - (Error 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element") - (Error 842, Line 22, Col 3, Line 22, Col 17, "This attribute is not valid for use on this language element") + (Warning 842, Line 19, Col 3, Line 19, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 20, Col 3, Line 20, Col 14, "This attribute is not valid for use on this language element") + (Warning 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element") + (Warning 842, Line 22, Col 3, Line 22, Col 17, "This attribute is not valid for use on this language element") ] // SOURCE=AttributeTargetsIsDelegate01.fs # AttributeTargetsIsDelegate01.fs @@ -605,10 +606,10 @@ module CustomAttributes_AttributeUsage = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 19, Col 3, Line 19, Col 14, "This attribute is not valid for use on this language element") - (Error 842, Line 20, Col 3, Line 20, Col 15, "This attribute is not valid for use on this language element") - (Error 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element") - (Error 842, Line 22, Col 3, Line 22, Col 13, "This attribute is not valid for use on this language element") + (Warning 842, Line 19, Col 3, Line 19, Col 14, "This attribute is not valid for use on this language element") + (Warning 842, Line 20, Col 3, Line 20, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element") + (Warning 842, Line 22, Col 3, Line 22, Col 13, "This attribute is not valid for use on this language element") ] [] @@ -654,10 +655,10 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 11, Col 3, Line 11, Col 14, "This attribute is not valid for use on this language element") - (Error 842, Line 14, Col 3, Line 14, Col 15, "This attribute is not valid for use on this language element") - (Error 842, Line 18, Col 3, Line 18, Col 14, "This attribute is not valid for use on this language element") - (Error 842, Line 19, Col 3, Line 19, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 11, Col 3, Line 11, Col 14, "This attribute is not valid for use on this language element") + (Warning 842, Line 14, Col 3, Line 14, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 18, Col 3, Line 18, Col 14, "This attribute is not valid for use on this language element") + (Warning 842, Line 19, Col 3, Line 19, Col 15, "This attribute is not valid for use on this language element") ] // SOURCE= E_AttributeTargetIsClass02.fs # E_AttributeTargetIsClass02.fs @@ -676,18 +677,18 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 15, Col 3, Line 15, Col 18, "This attribute is not valid for use on this language element"); - (Error 842, Line 16, Col 3, Line 16, Col 15, "This attribute is not valid for use on this language element") - (Error 842, Line 20, Col 3, Line 20, Col 14, "This attribute is not valid for use on this language element") - (Error 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element") - (Error 842, Line 26, Col 3, Line 26, Col 14, "This attribute is not valid for use on this language element") - (Error 842, Line 27, Col 3, Line 27, Col 18, "This attribute is not valid for use on this language element") - (Error 842, Line 34, Col 3, Line 34, Col 14, "This attribute is not valid for use on this language element") - (Error 842, Line 35, Col 3, Line 35, Col 18, "This attribute is not valid for use on this language element") - (Error 842, Line 43, Col 3, Line 43, Col 18, "This attribute is not valid for use on this language element") - (Error 842, Line 44, Col 3, Line 44, Col 15, "This attribute is not valid for use on this language element") - (Error 842, Line 47, Col 3, Line 47, Col 14, "This attribute is not valid for use on this language element") - (Error 842, Line 48, Col 3, Line 48, Col 18, "This attribute is not valid for use on this language element") + (Warning 842, Line 15, Col 3, Line 15, Col 18, "This attribute is not valid for use on this language element"); + (Warning 842, Line 16, Col 3, Line 16, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 20, Col 3, Line 20, Col 14, "This attribute is not valid for use on this language element") + (Warning 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element") + (Warning 842, Line 26, Col 3, Line 26, Col 14, "This attribute is not valid for use on this language element") + (Warning 842, Line 27, Col 3, Line 27, Col 18, "This attribute is not valid for use on this language element") + (Warning 842, Line 34, Col 3, Line 34, Col 14, "This attribute is not valid for use on this language element") + (Warning 842, Line 35, Col 3, Line 35, Col 18, "This attribute is not valid for use on this language element") + (Warning 842, Line 43, Col 3, Line 43, Col 18, "This attribute is not valid for use on this language element") + (Warning 842, Line 44, Col 3, Line 44, Col 15, "This attribute is not valid for use on this language element") + (Warning 842, Line 47, Col 3, Line 47, Col 14, "This attribute is not valid for use on this language element") + (Warning 842, Line 48, Col 3, Line 48, Col 18, "This attribute is not valid for use on this language element") ] // SOURCE= CLIMutableAttribute01.fs # CLIMutableAttribute01.fs @@ -756,8 +757,8 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) = (Error 934, Line 33, Col 10, Line 33, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") (Error 934, Line 36, Col 10, Line 36, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") (Error 934, Line 39, Col 10, Line 39, Col 13, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") - (Error 842, Line 41, Col 7, Line 41, Col 23, "This attribute is not valid for use on this language element") - (Error 842, Line 44, Col 7, Line 44, Col 23, "This attribute is not valid for use on this language element") + (Warning 842, Line 41, Col 7, Line 41, Col 23, "This attribute is not valid for use on this language element") + (Warning 842, Line 44, Col 7, Line 44, Col 23, "This attribute is not valid for use on this language element") (Error 935, Line 54, Col 10, Line 54, Col 11, "Types with the 'AllowNullLiteral' attribute may only inherit from or implement types which also allow the use of the null literal") ] @@ -775,8 +776,8 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) = (Error 934, Line 33, Col 10, Line 33, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") (Error 934, Line 36, Col 10, Line 36, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") (Error 934, Line 39, Col 10, Line 39, Col 13, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") - (Error 842, Line 41, Col 7, Line 41, Col 23, "This attribute is not valid for use on this language element") - (Error 842, Line 44, Col 7, Line 44, Col 23, "This attribute is not valid for use on this language element") + (Warning 842, Line 41, Col 7, Line 41, Col 23, "This attribute is not valid for use on this language element") + (Warning 842, Line 44, Col 7, Line 44, Col 23, "This attribute is not valid for use on this language element") (Error 935, Line 54, Col 10, Line 54, Col 11, "Types with the 'AllowNullLiteral' attribute may only inherit from or implement types which also allow the use of the null literal") ] diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs index 1e3c99dc8a5..44ee388af9d 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs @@ -61,7 +61,7 @@ module CustomAttributes_Basic = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 15, Col 7, Line 15, Col 17, "This attribute is not valid for use on this language element") + (Warning 842, Line 15, Col 7, Line 15, Col 17, "This attribute is not valid for use on this language element") ] // SOURCE=E_AttributeApplication04.fs SCFLAGS="--test:ErrorRanges" # E_AttributeApplication04.fs @@ -71,7 +71,7 @@ module CustomAttributes_Basic = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 14, Col 3, Line 14, Col 13, "This attribute is not valid for use on this language element") + (Warning 842, Line 14, Col 3, Line 14, Col 13, "This attribute is not valid for use on this language element") ] // SOURCE=E_AttributeApplication05.fs SCFLAGS="--test:ErrorRanges" # E_AttributeApplication05.fs @@ -81,7 +81,8 @@ module CustomAttributes_Basic = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 8, Col 7, Line 8, Col 8, "This attribute is not valid for use on this language element") + (Warning 842, Line 8, Col 7, Line 8, Col 8, "This attribute is not valid for use on this language element") + (Error 824, Line 8, Col 7, Line 8, Col 8, "Attributes are not permitted on 'let' bindings in expressions") (Warning 20, Line 8, Col 1, Line 8, Col 31, "The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") ] diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/EntryPoint/EntryPoint.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/EntryPoint/EntryPoint.fs index ce51bcf6c14..38b84fb6498 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/EntryPoint/EntryPoint.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/EntryPoint/EntryPoint.fs @@ -75,7 +75,7 @@ module EntryPoint = |> compile |> shouldFail |> withDiagnostics [ - (Error 842, Line 9, Col 3, Line 9, Col 13, """This attribute is not valid for use on this language element""") + (Warning 842, Line 9, Col 3, Line 9, Col 13, """This attribute is not valid for use on this language element""") ] // SOURCE=E_twoattributesonsamefunction001.fs SCFLAGS="--test:ErrorRanges" # E_twoattributesonsamefunction001.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/LetBindings/Basic/Basic.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/LetBindings/Basic/Basic.fs index c0a19c9ad3e..b59d28cbdd2 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/LetBindings/Basic/Basic.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/LetBindings/Basic/Basic.fs @@ -53,9 +53,9 @@ module LetBindings_Basic = |> shouldFail |> withDiagnostics [ (Error 683, Line 14, Col 6, Line 14, Col 27, "Attributes are not allowed within patterns") - (Error 842, Line 14, Col 8, Line 14, Col 25, "This attribute is not valid for use on this language element") + (Warning 842, Line 14, Col 8, Line 14, Col 25, "This attribute is not valid for use on this language element") (Error 683, Line 14, Col 42, Line 14, Col 63, "Attributes are not allowed within patterns") - (Error 842, Line 14, Col 44, Line 14, Col 61, "This attribute is not valid for use on this language element") + (Warning 842, Line 14, Col 44, Line 14, Col 61, "This attribute is not valid for use on this language element") ] // SOURCE=E_ErrorsForInlineValue.fs SCFLAGS="--test:ErrorRanges" # E_ErrorsForInlineValue.fs diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TailCallAttribute.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TailCallAttribute.fs index 1b68505ab1e..81ce04fc05a 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TailCallAttribute.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TailCallAttribute.fs @@ -245,7 +245,7 @@ namespace N [] let ``Warn successfully for invalid tailcalls in type methods`` () = - """ + FSharp """ namespace N module M = @@ -261,29 +261,12 @@ namespace N printfn "M2 called" this.M1() + 2 // should warn """ - |> FSharp |> withLangVersion80 |> compile |> shouldFail - |> withResults [ - { Error = Warning 3569 - Range = { StartLine = 10 - StartColumn = 17 - EndLine = 10 - EndColumn = 26 } - Message = - "The member or function 'M2' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way." } - { Error = Warning 3569 - Range = { StartLine = 15 - StartColumn = 17 - EndLine = 15 - EndColumn = 26 } - Message = -#if Debug - "The member or function 'M2' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way." } -#else - "The member or function 'M1' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way." } -#endif + |> withDiagnostics [ + (Warning 3569, Line 10, Col 17, Line 10, Col 26, "The member or function 'M2' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way."); + (Warning 3569, Line 15, Col 17, Line 15, Col 26, "The member or function 'M1' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way.") ] [] @@ -1481,7 +1464,10 @@ namespace N |> withLangVersionPreview |> compile |> shouldFail - |> withSingleDiagnostic (Error 842, Line 6, Col 11, Line 6, Col 19, "This attribute is not valid for use on this language element") + |> withDiagnostics [ + (Warning 842, Line 6, Col 11, Line 6, Col 19, "This attribute is not valid for use on this language element") + (Warning 3861, Line 7, Col 13, Line 7, Col 18, "The TailCall attribute should only be applied to recursive functions.") + ] [] let ``Error about attribute on recursive let-bound value`` () = @@ -1497,7 +1483,7 @@ namespace N |> withLangVersionPreview |> compile |> shouldFail - |> withSingleDiagnostic (Error 842, Line 6, Col 11, Line 6, Col 19, "This attribute is not valid for use on this language element") + |> withSingleDiagnostic (Warning 842, Line 6, Col 11, Line 6, Col 19, "This attribute is not valid for use on this language element") [] let ``Warn about self-defined attribute`` () = // is the analysis available for users of older FSharp.Core versions From 55507e9e7e98e640678932f96a25cb3bacc82904 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Wed, 23 Apr 2025 15:39:04 +0100 Subject: [PATCH 02/39] release notes --- docs/release-notes/.FSharp.Compiler.Service/9.0.300.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 16f5721e22a..05e15a667dd 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -48,6 +48,7 @@ * Warning for "useless null handling" works with piped syntax constructs now ([PR #18331](https://github.com/dotnet/fsharp/pull/18331)) * Make indent in generated overridden member code depend on the context, not fix to 4. ([PR #18341](https://github.com/dotnet/fsharp/pull/18341)) * Adjust caller info attribute error message range ([PR #18388](https://github.com/dotnet/fsharp/pull/18388)) +* Make attribute targets mismatch a warning and not an error ([PR #18492](https://github.com/dotnet/fsharp/pull/18492)) ### Breaking Changes * Struct unions with overlapping fields now generate mappings needed for reading via reflection ([Issue #18121](https://github.com/dotnet/fsharp/issues/17797), [PR #18274](https://github.com/dotnet/fsharp/pull/17877)) From 17380183feebe6a1cf30a8f678965b6cd689de82 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Wed, 23 Apr 2025 16:19:59 +0100 Subject: [PATCH 03/39] update tests --- .../PatternMatchCompilationTests.fs | 1 + .../Language/StructActivePatternTests.fs | 2 +- tests/fsharp/typecheck/sigs/neg16.bsl | 4 +- tests/fsharp/typecheck/sigs/neg20.bsl | 46 +++++++++---------- tests/fsharp/typecheck/sigs/neg32.bsl | 2 +- .../fsharp/typecheck/sigs/version50/neg20.bsl | 46 +++++++++---------- .../UnitsOfMeasure/WithOOP/E_GenericUOM01.fs | 2 +- 7 files changed, 52 insertions(+), 51 deletions(-) diff --git a/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs b/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs index 1b6d54d3577..cf870698077 100644 --- a/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs @@ -41,6 +41,7 @@ match () with dumpDiagnostics checkResults |> shouldEqual [ "(3,2--3,25): Attributes are not allowed within patterns" "(3,4--3,23): This attribute is not valid for use on this language element" + "(3,17--3,22): This is not a valid constant expression or custom attribute value" ] diff --git a/tests/fsharp/Compiler/Language/StructActivePatternTests.fs b/tests/fsharp/Compiler/Language/StructActivePatternTests.fs index aac654f549c..4c2451142fa 100644 --- a/tests/fsharp/Compiler/Language/StructActivePatternTests.fs +++ b/tests/fsharp/Compiler/Language/StructActivePatternTests.fs @@ -176,7 +176,7 @@ let (|Foo|_|) x = ValueNone [] let (|Foo|_|) x = ValueNone """ - [|(FSharpDiagnosticSeverity.Error, 842, (2, 3, 2, 9), + [|(FSharpDiagnosticSeverity.Warning, 842, (2, 3, 2, 9), "This attribute is not valid for use on this language element"); (FSharpDiagnosticSeverity.Error, 3350, (3, 6, 3, 13), "Feature 'Boolean-returning and return-type-directed partial active patterns' is not available in F# 8.0. Please use language version 9.0 or greater.")|] diff --git a/tests/fsharp/typecheck/sigs/neg16.bsl b/tests/fsharp/typecheck/sigs/neg16.bsl index 4c2300470f7..448ca9127be 100644 --- a/tests/fsharp/typecheck/sigs/neg16.bsl +++ b/tests/fsharp/typecheck/sigs/neg16.bsl @@ -13,9 +13,9 @@ neg16.fs(44,10,44,11): typecheck error FS0934: Records, union, abbreviations and neg16.fs(47,10,47,13): typecheck error FS0934: Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute -neg16.fs(49,7,49,23): typecheck error FS0842: This attribute is not valid for use on this language element +neg16.fs(49,7,49,23): typecheck warning FS0842: This attribute is not valid for use on this language element -neg16.fs(52,7,52,23): typecheck error FS0842: This attribute is not valid for use on this language element +neg16.fs(52,7,52,23): typecheck warning FS0842: This attribute is not valid for use on this language element neg16.fs(59,8,59,17): typecheck error FS0001: This expression was expected to have type 'Choice<'a,'b>' diff --git a/tests/fsharp/typecheck/sigs/neg20.bsl b/tests/fsharp/typecheck/sigs/neg20.bsl index 5229dcaacf6..28fa11b53f7 100644 --- a/tests/fsharp/typecheck/sigs/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/neg20.bsl @@ -213,53 +213,53 @@ neg20.fs(190,34,190,39): typecheck error FS0001: This expression was expected to but here has type 'objnull' -neg20.fs(195,5,195,10): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(195,5,195,10): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(198,5,198,11): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(198,5,198,11): typecheck warning FS0842: This attribute is not valid for use on this language element neg20.fs(202,7,202,9): typecheck error FS0825: The 'DefaultValue' attribute may only be used on 'val' declarations -neg20.fs(204,5,204,14): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(204,5,204,14): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(207,5,207,11): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(207,5,207,11): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(210,5,210,12): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(210,5,210,12): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(213,5,213,33): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(213,5,213,33): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(216,5,216,12): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(216,5,216,12): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(219,5,219,15): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(219,5,219,15): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(222,5,222,31): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(222,5,222,31): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(225,5,225,22): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(225,5,225,22): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(228,5,228,23): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(228,5,228,23): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(231,5,231,21): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(231,5,231,21): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(234,5,234,34): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(234,5,234,34): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(237,5,237,34): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(237,5,237,34): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(240,5,240,23): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(240,5,240,23): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(243,5,243,23): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(243,5,243,23): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(249,9,249,27): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(249,9,249,27): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(255,5,255,28): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(255,5,255,28): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(258,5,258,38): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(258,5,258,38): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(261,5,261,17): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(261,5,261,17): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(265,5,265,24): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(265,5,265,24): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(268,5,268,27): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(268,5,268,27): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(271,5,271,15): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(271,5,271,15): typecheck warning FS0842: This attribute is not valid for use on this language element neg20.fs(278,14,278,95): typecheck error FS0507: No accessible member or object constructor named 'ProcessStartInfo' takes 0 arguments. Note the call to this member also provides 2 named arguments. diff --git a/tests/fsharp/typecheck/sigs/neg32.bsl b/tests/fsharp/typecheck/sigs/neg32.bsl index 87fbc723312..376138c1858 100644 --- a/tests/fsharp/typecheck/sigs/neg32.bsl +++ b/tests/fsharp/typecheck/sigs/neg32.bsl @@ -1,5 +1,5 @@ -neg32.fs(17,11,17,56): typecheck error FS0842: This attribute is not valid for use on this language element +neg32.fs(17,11,17,56): typecheck warning FS0842: This attribute is not valid for use on this language element neg32.fs(24,15,24,16): typecheck error FS0043: The member or object constructor 'TryParse' does not take 1 argument(s). An overload was found taking 2 arguments. diff --git a/tests/fsharp/typecheck/sigs/version50/neg20.bsl b/tests/fsharp/typecheck/sigs/version50/neg20.bsl index 394f7777b2a..f85f1d5d14f 100644 --- a/tests/fsharp/typecheck/sigs/version50/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/version50/neg20.bsl @@ -261,53 +261,53 @@ neg20.fs(190,34,190,39): typecheck error FS0001: This expression was expected to but here has type 'objnull' -neg20.fs(195,5,195,10): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(195,5,195,10): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(198,5,198,11): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(198,5,198,11): typecheck warning FS0842: This attribute is not valid for use on this language element neg20.fs(202,7,202,9): typecheck error FS0825: The 'DefaultValue' attribute may only be used on 'val' declarations -neg20.fs(204,5,204,14): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(204,5,204,14): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(207,5,207,11): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(207,5,207,11): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(210,5,210,12): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(210,5,210,12): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(213,5,213,33): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(213,5,213,33): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(216,5,216,12): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(216,5,216,12): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(219,5,219,15): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(219,5,219,15): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(222,5,222,31): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(222,5,222,31): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(225,5,225,22): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(225,5,225,22): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(228,5,228,23): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(228,5,228,23): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(231,5,231,21): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(231,5,231,21): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(234,5,234,34): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(234,5,234,34): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(237,5,237,34): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(237,5,237,34): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(240,5,240,23): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(240,5,240,23): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(243,5,243,23): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(243,5,243,23): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(249,9,249,27): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(249,9,249,27): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(255,5,255,28): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(255,5,255,28): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(258,5,258,38): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(258,5,258,38): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(261,5,261,17): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(261,5,261,17): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(265,5,265,24): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(265,5,265,24): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(268,5,268,27): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(268,5,268,27): typecheck warning FS0842: This attribute is not valid for use on this language element -neg20.fs(271,5,271,15): typecheck error FS0842: This attribute is not valid for use on this language element +neg20.fs(271,5,271,15): typecheck warning FS0842: This attribute is not valid for use on this language element neg20.fs(278,14,278,95): typecheck error FS0507: No accessible member or object constructor named 'ProcessStartInfo' takes 0 arguments. Note the call to this member also provides 2 named arguments. diff --git a/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/WithOOP/E_GenericUOM01.fs b/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/WithOOP/E_GenericUOM01.fs index 369697935e3..0f27193b5a7 100644 --- a/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/WithOOP/E_GenericUOM01.fs +++ b/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/WithOOP/E_GenericUOM01.fs @@ -1,7 +1,7 @@ // #Regression #Conformance #UnitsOfMeasure #ObjectOrientedTypes // Verify error when putting invalid attributes on type arguments // (We should only allow [].) -//This attribute is not valid for use on this language element +//This attribute is not valid for use on this language element open System From 6f2b7064781a2c33c254f17ffac1a31a8cd3f41e Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Tue, 29 Apr 2025 09:43:56 +0100 Subject: [PATCH 04/39] update baselines --- tests/fsharp/typecheck/sigs/neg16.bsl | 4 +- tests/fsharp/typecheck/sigs/neg20.bsl | 48 ++++++++++--------- tests/fsharp/typecheck/sigs/neg32.bsl | 4 +- .../fsharp/typecheck/sigs/version50/neg20.bsl | 48 ++++++++++--------- 4 files changed, 54 insertions(+), 50 deletions(-) diff --git a/tests/fsharp/typecheck/sigs/neg16.bsl b/tests/fsharp/typecheck/sigs/neg16.bsl index 448ca9127be..4c2300470f7 100644 --- a/tests/fsharp/typecheck/sigs/neg16.bsl +++ b/tests/fsharp/typecheck/sigs/neg16.bsl @@ -13,9 +13,9 @@ neg16.fs(44,10,44,11): typecheck error FS0934: Records, union, abbreviations and neg16.fs(47,10,47,13): typecheck error FS0934: Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute -neg16.fs(49,7,49,23): typecheck warning FS0842: This attribute is not valid for use on this language element +neg16.fs(49,7,49,23): typecheck error FS0842: This attribute is not valid for use on this language element -neg16.fs(52,7,52,23): typecheck warning FS0842: This attribute is not valid for use on this language element +neg16.fs(52,7,52,23): typecheck error FS0842: This attribute is not valid for use on this language element neg16.fs(59,8,59,17): typecheck error FS0001: This expression was expected to have type 'Choice<'a,'b>' diff --git a/tests/fsharp/typecheck/sigs/neg20.bsl b/tests/fsharp/typecheck/sigs/neg20.bsl index 28fa11b53f7..2ff8515a78a 100644 --- a/tests/fsharp/typecheck/sigs/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/neg20.bsl @@ -213,53 +213,53 @@ neg20.fs(190,34,190,39): typecheck error FS0001: This expression was expected to but here has type 'objnull' -neg20.fs(195,5,195,10): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(195,5,195,10): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(198,5,198,11): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(198,5,198,11): typecheck error FS0842: This attribute is not valid for use on this language element neg20.fs(202,7,202,9): typecheck error FS0825: The 'DefaultValue' attribute may only be used on 'val' declarations -neg20.fs(204,5,204,14): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(204,5,204,14): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(207,5,207,11): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(207,5,207,11): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(210,5,210,12): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(210,5,210,12): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(213,5,213,33): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(213,5,213,33): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(216,5,216,12): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(216,5,216,12): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(219,5,219,15): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(219,5,219,15): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(222,5,222,31): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(222,5,222,31): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(225,5,225,22): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(225,5,225,22): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(228,5,228,23): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(228,5,228,23): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(231,5,231,21): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(231,5,231,21): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(234,5,234,34): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(234,5,234,34): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(237,5,237,34): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(237,5,237,34): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(240,5,240,23): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(240,5,240,23): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(243,5,243,23): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(243,5,243,23): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(249,9,249,27): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(249,9,249,27): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(255,5,255,28): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(255,5,255,28): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(258,5,258,38): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(258,5,258,38): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(261,5,261,17): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(261,5,261,17): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(265,5,265,24): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(265,5,265,24): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(268,5,268,27): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(268,5,268,27): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(271,5,271,15): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(271,5,271,15): typecheck error FS0842: This attribute is not valid for use on this language element neg20.fs(278,14,278,95): typecheck error FS0507: No accessible member or object constructor named 'ProcessStartInfo' takes 0 arguments. Note the call to this member also provides 2 named arguments. @@ -294,6 +294,7 @@ neg20.fs(335,11,335,24): typecheck error FS0041: A unique overload for method 'S Known type of argument: 'a0 Candidates: + - System.String(value: System.ReadOnlySpan) : System.String - System.String(value: char array) : System.String - System.String(value: nativeptr) : System.String - System.String(value: nativeptr) : System.String @@ -303,6 +304,7 @@ neg20.fs(336,11,336,22): typecheck error FS0041: A unique overload for method 'G Known type of argument: 'a0 Candidates: + - System.Guid(b: System.ReadOnlySpan) : System.Guid - System.Guid(b: byte array) : System.Guid - System.Guid(g: string) : System.Guid diff --git a/tests/fsharp/typecheck/sigs/neg32.bsl b/tests/fsharp/typecheck/sigs/neg32.bsl index 376138c1858..7649c0719b5 100644 --- a/tests/fsharp/typecheck/sigs/neg32.bsl +++ b/tests/fsharp/typecheck/sigs/neg32.bsl @@ -1,7 +1,7 @@ -neg32.fs(17,11,17,56): typecheck warning FS0842: This attribute is not valid for use on this language element +neg32.fs(17,11,17,56): typecheck error FS0842: This attribute is not valid for use on this language element -neg32.fs(24,15,24,16): typecheck error FS0043: The member or object constructor 'TryParse' does not take 1 argument(s). An overload was found taking 2 arguments. +neg32.fs(24,15,24,16): typecheck error FS0043: The member or object constructor 'TryParse' does not take 1 argument(s). An overload was found taking 4 arguments. neg32.fs(43,17,43,19): typecheck error FS0039: The type parameter 'T is not defined. diff --git a/tests/fsharp/typecheck/sigs/version50/neg20.bsl b/tests/fsharp/typecheck/sigs/version50/neg20.bsl index f85f1d5d14f..d5de8268fab 100644 --- a/tests/fsharp/typecheck/sigs/version50/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/version50/neg20.bsl @@ -261,53 +261,53 @@ neg20.fs(190,34,190,39): typecheck error FS0001: This expression was expected to but here has type 'objnull' -neg20.fs(195,5,195,10): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(195,5,195,10): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(198,5,198,11): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(198,5,198,11): typecheck error FS0842: This attribute is not valid for use on this language element neg20.fs(202,7,202,9): typecheck error FS0825: The 'DefaultValue' attribute may only be used on 'val' declarations -neg20.fs(204,5,204,14): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(204,5,204,14): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(207,5,207,11): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(207,5,207,11): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(210,5,210,12): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(210,5,210,12): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(213,5,213,33): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(213,5,213,33): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(216,5,216,12): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(216,5,216,12): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(219,5,219,15): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(219,5,219,15): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(222,5,222,31): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(222,5,222,31): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(225,5,225,22): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(225,5,225,22): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(228,5,228,23): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(228,5,228,23): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(231,5,231,21): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(231,5,231,21): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(234,5,234,34): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(234,5,234,34): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(237,5,237,34): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(237,5,237,34): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(240,5,240,23): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(240,5,240,23): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(243,5,243,23): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(243,5,243,23): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(249,9,249,27): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(249,9,249,27): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(255,5,255,28): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(255,5,255,28): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(258,5,258,38): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(258,5,258,38): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(261,5,261,17): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(261,5,261,17): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(265,5,265,24): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(265,5,265,24): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(268,5,268,27): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(268,5,268,27): typecheck error FS0842: This attribute is not valid for use on this language element -neg20.fs(271,5,271,15): typecheck warning FS0842: This attribute is not valid for use on this language element +neg20.fs(271,5,271,15): typecheck error FS0842: This attribute is not valid for use on this language element neg20.fs(278,14,278,95): typecheck error FS0507: No accessible member or object constructor named 'ProcessStartInfo' takes 0 arguments. Note the call to this member also provides 2 named arguments. @@ -342,6 +342,7 @@ neg20.fs(335,11,335,24): typecheck error FS0041: A unique overload for method 'S Known type of argument: 'a0 Candidates: + - System.String(value: System.ReadOnlySpan) : System.String - System.String(value: char array) : System.String - System.String(value: nativeptr) : System.String - System.String(value: nativeptr) : System.String @@ -351,6 +352,7 @@ neg20.fs(336,11,336,22): typecheck error FS0041: A unique overload for method 'G Known type of argument: 'a0 Candidates: + - System.Guid(b: System.ReadOnlySpan) : System.Guid - System.Guid(b: byte array) : System.Guid - System.Guid(g: string) : System.Guid From 75d8f5ef637741991df6c15ae75d202b8412dd65 Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Tue, 29 Apr 2025 19:33:38 +0100 Subject: [PATCH 05/39] Update baselines --- tests/fsharp/typecheck/sigs/neg20.bsl | 2 -- tests/fsharp/typecheck/sigs/neg32.bsl | 2 +- tests/fsharp/typecheck/sigs/version50/neg20.bsl | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/fsharp/typecheck/sigs/neg20.bsl b/tests/fsharp/typecheck/sigs/neg20.bsl index 2ff8515a78a..5229dcaacf6 100644 --- a/tests/fsharp/typecheck/sigs/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/neg20.bsl @@ -294,7 +294,6 @@ neg20.fs(335,11,335,24): typecheck error FS0041: A unique overload for method 'S Known type of argument: 'a0 Candidates: - - System.String(value: System.ReadOnlySpan) : System.String - System.String(value: char array) : System.String - System.String(value: nativeptr) : System.String - System.String(value: nativeptr) : System.String @@ -304,7 +303,6 @@ neg20.fs(336,11,336,22): typecheck error FS0041: A unique overload for method 'G Known type of argument: 'a0 Candidates: - - System.Guid(b: System.ReadOnlySpan) : System.Guid - System.Guid(b: byte array) : System.Guid - System.Guid(g: string) : System.Guid diff --git a/tests/fsharp/typecheck/sigs/neg32.bsl b/tests/fsharp/typecheck/sigs/neg32.bsl index 7649c0719b5..87fbc723312 100644 --- a/tests/fsharp/typecheck/sigs/neg32.bsl +++ b/tests/fsharp/typecheck/sigs/neg32.bsl @@ -1,7 +1,7 @@ neg32.fs(17,11,17,56): typecheck error FS0842: This attribute is not valid for use on this language element -neg32.fs(24,15,24,16): typecheck error FS0043: The member or object constructor 'TryParse' does not take 1 argument(s). An overload was found taking 4 arguments. +neg32.fs(24,15,24,16): typecheck error FS0043: The member or object constructor 'TryParse' does not take 1 argument(s). An overload was found taking 2 arguments. neg32.fs(43,17,43,19): typecheck error FS0039: The type parameter 'T is not defined. diff --git a/tests/fsharp/typecheck/sigs/version50/neg20.bsl b/tests/fsharp/typecheck/sigs/version50/neg20.bsl index d5de8268fab..394f7777b2a 100644 --- a/tests/fsharp/typecheck/sigs/version50/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/version50/neg20.bsl @@ -342,7 +342,6 @@ neg20.fs(335,11,335,24): typecheck error FS0041: A unique overload for method 'S Known type of argument: 'a0 Candidates: - - System.String(value: System.ReadOnlySpan) : System.String - System.String(value: char array) : System.String - System.String(value: nativeptr) : System.String - System.String(value: nativeptr) : System.String @@ -352,7 +351,6 @@ neg20.fs(336,11,336,22): typecheck error FS0041: A unique overload for method 'G Known type of argument: 'a0 Candidates: - - System.Guid(b: System.ReadOnlySpan) : System.Guid - System.Guid(b: byte array) : System.Guid - System.Guid(g: string) : System.Guid From 4248f2a9225b2533cb4137d1e1b4311ce9e3cad1 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Wed, 30 Apr 2025 21:58:10 +0100 Subject: [PATCH 06/39] Move attribute form logic to an AP --- .../Checking/Expressions/CheckExpressions.fs | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index e2d21975311..567e1da0310 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -3187,6 +3187,24 @@ let BuildRecdFieldSet g m objExpr (rfinfo: RecdFieldInfo) argExpr = let wrap, objExpr, _readonly, _writeonly = mkExprAddrOfExpr g boxity false DefinitelyMutates objExpr None m wrap (mkRecdFieldSetViaExprAddr (objExpr, rfinfo.RecdFieldRef, rfinfo.TypeInst, argExpr, m) ) +// This is used to check the target of an attribute with the form of +// Long Form: [] +// Short Form: [] +let (|LongFormAttrTarget|UnrecognizedLongAttrTarget|ShortFormAttributeTarget|) (targetIndicator: Ident option) = + match targetIndicator with + | Some id when id.idText = "assembly" -> LongFormAttrTarget AttributeTargets.Assembly + | Some id when id.idText = "module" -> LongFormAttrTarget AttributeTargets.Module + | Some id when id.idText = "return" -> LongFormAttrTarget AttributeTargets.ReturnValue + | Some id when id.idText = "field" -> LongFormAttrTarget AttributeTargets.Field + | Some id when id.idText = "property" -> LongFormAttrTarget AttributeTargets.Property + | Some id when id.idText = "method" -> LongFormAttrTarget AttributeTargets.Method + | Some id when id.idText = "param" -> LongFormAttrTarget AttributeTargets.Parameter + | Some id when id.idText = "type" -> LongFormAttrTarget AttributeTargets.TyconDecl + | Some id when id.idText = "constructor" -> LongFormAttrTarget AttributeTargets.Constructor + | Some id when id.idText = "event" -> LongFormAttrTarget AttributeTargets.Event + | Some id -> UnrecognizedLongAttrTarget id + | None -> ShortFormAttributeTarget + //------------------------------------------------------------------------- // Helpers dealing with named and optional args at callsites //------------------------------------------------------------------------- @@ -11344,27 +11362,18 @@ and TcAttributeEx canFail (cenv: cenv) (env: TcEnv) attrTgt attrEx (synAttr: Syn (validOnDefault, inheritedDefault) | _ -> (validOnDefault, inheritedDefault) - let possibleTgts = enum validOn &&& attrTgt - let directedTgts = + let attributeTargets = enum validOn &&& attrTgt + let directedTargets = match targetIndicator with - | Some id when id.idText = "assembly" -> AttributeTargets.Assembly - | Some id when id.idText = "module" -> AttributeTargets.Module - | Some id when id.idText = "return" -> AttributeTargets.ReturnValue - | Some id when id.idText = "field" -> AttributeTargets.Field - | Some id when id.idText = "property" -> AttributeTargets.Property - | Some id when id.idText = "method" -> AttributeTargets.Method - | Some id when id.idText = "param" -> AttributeTargets.Parameter - | Some id when id.idText = "type" -> AttributeTargets.TyconDecl - | Some id when id.idText = "constructor" -> AttributeTargets.Constructor - | Some id when id.idText = "event" -> AttributeTargets.Event - | Some id -> - errorR(Error(FSComp.SR.tcUnrecognizedAttributeTarget(), id.idRange)) - possibleTgts - // mask explicit targets - | _ -> possibleTgts &&& ~~~ attrEx - let constrainedTgts = possibleTgts &&& directedTgts - if constrainedTgts = enum 0 then - if (directedTgts = AttributeTargets.Assembly || directedTgts = AttributeTargets.Module) then + | LongFormAttrTarget attrTarget -> attrTarget + | UnrecognizedLongAttrTarget attrTarget -> + errorR(Error(FSComp.SR.tcUnrecognizedAttributeTarget(), attrTarget.idRange)) + attributeTargets + | ShortFormAttributeTarget -> attributeTargets &&& ~~~ attrEx + + let constrainedTargets = attributeTargets &&& directedTargets + if constrainedTargets = enum 0 then + if (directedTargets = AttributeTargets.Assembly || directedTargets = AttributeTargets.Module) then error(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElementUseDo(), mAttr)) else warning(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElement(), mAttr)) @@ -11428,11 +11437,11 @@ and TcAttributeEx canFail (cenv: cenv) (env: TcEnv) attrTgt attrEx (synAttr: Syn if isStruct then error (Error(FSComp.SR.tcCustomAttributeMustBeReferenceType(), m)) if args.Length <> ilMethRef.ArgTypes.Length then error (Error(FSComp.SR.tcCustomAttributeArgumentMismatch(), m)) let args = args |> List.map mkAttribExpr - Attrib(tcref, ILAttrib ilMethRef, args, namedAttribArgMap, isAppliedToGetterOrSetter, Some constrainedTgts, m) + Attrib(tcref, ILAttrib ilMethRef, args, namedAttribArgMap, isAppliedToGetterOrSetter, Some constrainedTargets, m) | Expr.App (InnerExprPat(ExprValWithPossibleTypeInst(vref, _, _, _)), _, _, args, _) -> let args = args |> List.collect (function Expr.Const (Const.Unit, _, _) -> [] | expr -> tryDestRefTupleExpr expr) |> List.map mkAttribExpr - Attrib(tcref, FSAttrib vref, args, namedAttribArgMap, isAppliedToGetterOrSetter, Some constrainedTgts, mAttr) + Attrib(tcref, FSAttrib vref, args, namedAttribArgMap, isAppliedToGetterOrSetter, Some constrainedTargets, mAttr) | _ -> error (Error(FSComp.SR.tcCustomAttributeMustInvokeConstructor(), mAttr)) @@ -11440,7 +11449,7 @@ and TcAttributeEx canFail (cenv: cenv) (env: TcEnv) attrTgt attrEx (synAttr: Syn | _ -> error(Error(FSComp.SR.tcAttributeExpressionsMustBeConstructorCalls(), mAttr)) - [ (constrainedTgts, attrib) ], false + [ (constrainedTargets, attrib) ], false and TcAttributesWithPossibleTargetsEx canFail (cenv: cenv) env attrTgt attrEx synAttribs = From e465d63c411b578610b95567245a6fb69f2ce7c6 Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Fri, 6 Jun 2025 16:32:49 +0100 Subject: [PATCH 07/39] Allow mixing ranges and values to construct sequences --- .../CheckArrayOrListComputedExpressions.fs | 192 ++++++++++++----- .../Expressions/CheckSequenceExpressions.fs | 73 ++++++- .../FSharp.Compiler.ComponentTests.fsproj | 1 + ...dRangesAndValuesSequenceExpressionTests.fs | 203 ++++++++++++++++++ 4 files changed, 407 insertions(+), 62 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedRangesAndValuesSequenceExpressionTests.fs diff --git a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs index f8a2abd7d73..0dd2d013c26 100644 --- a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs @@ -7,12 +7,13 @@ open FSharp.Compiler.CheckBasics open FSharp.Compiler.ConstraintSolver open FSharp.Compiler.CheckExpressionsOps open FSharp.Compiler.CheckExpressions +open FSharp.Compiler.CheckSequenceExpressions open FSharp.Compiler.NameResolution open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.Features open FSharp.Compiler.DiagnosticsLogger open FSharp.Compiler.Syntax -open FSharp.Compiler.CheckSequenceExpressions +open FSharp.Compiler.SyntaxTrivia let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallTy) tpenv (isArray, comp) m = let g = cenv.g @@ -68,66 +69,146 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT errorR (Deprecated(FSComp.SR.tcExpressionWithIfRequiresParenthesis (), m)) | _ -> () - let replacementExpr = - if isArray then - // This are to improve parsing/processing speed for parser tables by converting to an array blob ASAP - let nelems = elems.Length - - if - nelems > 0 - && List.forall - (function - | SynExpr.Const(SynConst.UInt16 _, _) -> true - | _ -> false) - elems - then - SynExpr.Const( - SynConst.UInt16s( - Array.ofList ( - List.map - (function - | SynExpr.Const(SynConst.UInt16 x, _) -> x - | _ -> failwith "unreachable") - elems + let containsRanges = + elems + |> List.exists (function + | SynExpr.IndexRange _ -> true + | _ -> false) + + if containsRanges then + let rec buildBody elems = + match elems with + | [] -> SynExpr.Const(SynConst.Unit, m) + | [ elem ] -> + match elem with + | SynExpr.IndexRange _ -> + match RewriteRangeExpr elem with + | Some rewritten -> + SynExpr.YieldOrReturnFrom( + (true, false), + rewritten, + elem.Range, + { + YieldOrReturnFromKeyword = elem.Range + } ) - ), - m + | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + | elem :: rest -> + let headExpr = + match elem with + | SynExpr.IndexRange _ -> + match RewriteRangeExpr elem with + | Some rewritten -> + SynExpr.YieldOrReturnFrom( + (true, false), + rewritten, + elem.Range, + { + YieldOrReturnFromKeyword = elem.Range + } + ) + | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + + let tailExpr = buildBody rest + + SynExpr.Sequential( + DebugPointAtSequential.SuppressNeither, + true, + headExpr, + tailExpr, + m, + SynExprSequentialTrivia.Zero ) - elif - nelems > 0 - && List.forall - (function - | SynExpr.Const(SynConst.Byte _, _) -> true - | _ -> false) - elems - then - SynExpr.Const( - SynConst.Bytes( - Array.ofList ( - List.map - (function - | SynExpr.Const(SynConst.Byte x, _) -> x - | _ -> failwith "unreachable") - elems + + let transformedBody = buildBody elems + + let genCollElemTy = NewInferenceType g + let genCollTy = (if isArray then mkArrayType else mkListTy) cenv.g genCollElemTy + + TcPropagatingExprLeafThenConvert cenv overallTy genCollTy env m (fun () -> + let exprTy = mkSeqTy cenv.g genCollElemTy + + let expr, tpenv' = + TcSequenceExpression cenv env tpenv transformedBody (MustEqual exprTy) m + + let expr = mkCoerceIfNeeded cenv.g exprTy (tyOfExpr cenv.g expr) expr + + let expr = + if cenv.g.compilingFSharpCore then + expr + else + mkCallSeq cenv.g m genCollElemTy expr + + let expr = mkCoerceExpr (expr, exprTy, expr.Range, overallTy.Commit) + + let expr = + if isArray then + mkCallSeqToArray cenv.g m genCollElemTy expr + else + mkCallSeqToList cenv.g m genCollElemTy expr + + expr, tpenv') + else + let replacementExpr = + if isArray then + let nelems = elems.Length + + if + nelems > 0 + && List.forall + (function + | SynExpr.Const(SynConst.UInt16 _, _) -> true + | _ -> false) + elems + then + SynExpr.Const( + SynConst.UInt16s( + Array.ofList ( + List.map + (function + | SynExpr.Const(SynConst.UInt16 x, _) -> x + | _ -> failwith "unreachable") + elems + ) ), - SynByteStringKind.Regular, m - ), - m - ) - else + ) + elif + nelems > 0 + && List.forall + (function + | SynExpr.Const(SynConst.Byte _, _) -> true + | _ -> false) + elems + then + SynExpr.Const( + SynConst.Bytes( + Array.ofList ( + List.map + (function + | SynExpr.Const(SynConst.Byte x, _) -> x + | _ -> failwith "unreachable") + elems + ), + SynByteStringKind.Regular, + m + ), + m + ) + else + SynExpr.ArrayOrList(isArray, elems, m) + else if cenv.g.langVersion.SupportsFeature(LanguageFeature.ReallyLongLists) then SynExpr.ArrayOrList(isArray, elems, m) - else if cenv.g.langVersion.SupportsFeature(LanguageFeature.ReallyLongLists) then - SynExpr.ArrayOrList(isArray, elems, m) - else - if elems.Length > 500 then - error (Error(FSComp.SR.tcListLiteralMaxSize (), m)) + else + if elems.Length > 500 then + error (Error(FSComp.SR.tcListLiteralMaxSize (), m)) - SynExpr.ArrayOrList(isArray, elems, m) + SynExpr.ArrayOrList(isArray, elems, m) - TcExprUndelayed cenv overallTy env tpenv replacementExpr + TcExprUndelayed cenv overallTy env tpenv replacementExpr | _ -> - let genCollElemTy = NewInferenceType g let genCollTy = (if isArray then mkArrayType else mkListTy) cenv.g genCollElemTy @@ -138,8 +219,7 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT let exprTy = mkSeqTy cenv.g genCollElemTy - // Check the comprehension - let expr, tpenv = TcSequenceExpression cenv env tpenv comp (MustEqual exprTy) m + let expr, tpenv' = TcSequenceExpression cenv env tpenv comp (MustEqual exprTy) m let expr = mkCoerceIfNeeded cenv.g exprTy (tyOfExpr cenv.g expr) expr @@ -160,4 +240,4 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT else mkCallSeqToList cenv.g m genCollElemTy expr - expr, tpenv) + expr, tpenv') diff --git a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs index 499ed2ca914..17da4aa43f2 100644 --- a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs @@ -12,6 +12,7 @@ open FSharp.Compiler.Features open FSharp.Compiler.NameResolution open FSharp.Compiler.PatternMatchCompilation open FSharp.Compiler.Syntax +open FSharp.Compiler.SyntaxTrivia open FSharp.Compiler.Text open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeOps @@ -460,10 +461,70 @@ let TcSequenceExpressionEntry (cenv: TcFileState) env (overallTy: OverallTy) tpe match comp with | SimpleSemicolonSequence cenv false _ when validateObjectSequenceOrRecordExpression -> - errorR (Error(FSComp.SR.tcInvalidObjectSequenceOrRecordExpression (), m)) - | _ -> () - - if not hasBuilder && not cenv.g.compilingFSharpCore then - error (Error(FSComp.SR.tcInvalidSequenceExpressionSyntaxForm (), m)) + error (Error(FSComp.SR.tcInvalidObjectSequenceOrRecordExpression (), m)) + | SimpleSemicolonSequence cenv false elems when hasBuilder -> + // Check if we have any range expressions mixed with regular values in seq { ... } + let containsRanges = + elems + |> List.exists (function + | SynExpr.IndexRange _ -> true + | _ -> false) + + if containsRanges then + // Transform to proper sequence expression body: yield v1; yield! r1..r2; yield v2; ... + let rec buildSeqBody elems = + match elems with + | [] -> SynExpr.Const(SynConst.Unit, m) + | [ elem ] -> + match elem with + | SynExpr.IndexRange _ -> + match RewriteRangeExpr elem with + | Some rewrittenRange -> + SynExpr.YieldOrReturnFrom( + (true, false), + rewrittenRange, + elem.Range, + { + YieldOrReturnFromKeyword = elem.Range + } + ) + | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + | elem :: rest -> + let headExpr = + match elem with + | SynExpr.IndexRange _ -> + match RewriteRangeExpr elem with + | Some rewrittenRange -> + SynExpr.YieldOrReturnFrom( + (true, false), + rewrittenRange, + elem.Range, + { + YieldOrReturnFromKeyword = elem.Range + } + ) + | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + + let tailExpr = buildSeqBody rest + + SynExpr.Sequential( + DebugPointAtSequential.SuppressNeither, + true, + headExpr, + tailExpr, + m, + SynExprSequentialTrivia.Zero + ) + + let transformedBody = buildSeqBody elems + TcSequenceExpression cenv env tpenv transformedBody overallTy m + else + // No ranges, use regular handling + TcSequenceExpression cenv env tpenv comp overallTy m + | _ -> + if not hasBuilder && not cenv.g.compilingFSharpCore then + error (Error(FSComp.SR.tcInvalidSequenceExpressionSyntaxForm (), m)) - TcSequenceExpression cenv env tpenv comp overallTy m + TcSequenceExpression cenv env tpenv comp overallTy m diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 952624f9fcd..2eacd0604c7 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -233,6 +233,7 @@ + diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedRangesAndValuesSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedRangesAndValuesSequenceExpressionTests.fs new file mode 100644 index 00000000000..4a42ede8829 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedRangesAndValuesSequenceExpressionTests.fs @@ -0,0 +1,203 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Language + +open FSharp.Test +open Xunit +open FSharp.Test.Compiler + +module MixedRangesAndValuesSequenceExpressionTests = + [] + let ``Mixed ranges and values in lists``() = + FSharp """ +module MixedRangeListTests + +let test1 = [-3; 1..10] +let expected1 = [-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10] +if test1 <> expected1 then failwith $"test1 failed: got {test1}" + +let test2 = [-3; 1..10; 19] +let expected2 = [-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 19] +if test2 <> expected2 then failwith $"test2 failed: got {test2}" + +let test3 = [1..3; 5..7; 10] +let expected3 = [1; 2; 3; 5; 6; 7; 10] +if test3 <> expected3 then failwith $"test3 failed: got {test3}" + +let test4 = [0; 2..2..10; 15] +let expected4 = [0; 2; 4; 6; 8; 10; 15] +if test4 <> expected4 then failwith $"test4 failed: got {test4}" + +printfn "All list tests passed!" + """ + |> withLangVersion90 + |> asExe + |> compileAndRun + |> shouldSucceed + + [] + let ``Mixed ranges and values in arrays``() = + FSharp """ +module MixedRangeArrayTests + +let test1 = [|-3; 1..10|] +let expected1 = [|-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10|] +if test1 <> expected1 then failwith $"test1 failed: got {test1}" + +let test2 = [|-3; 1..10; 19|] +let expected2 = [|-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 19|] +if test2 <> expected2 then failwith $"test2 failed: got {test2}" + +let test3 = [|1..3; 5..7; 10|] +let expected3 = [|1; 2; 3; 5; 6; 7; 10|] +if test3 <> expected3 then failwith $"test3 failed: got {test3}" + +let test4 = [|0; 2..2..10; 15|] +let expected4 = [|0; 2; 4; 6; 8; 10; 15|] +if test4 <> expected4 then failwith $"test4 failed: got {test4}" + +let test5 = [|1; 5..4; 10|] +let expected5 = [|1; 10|] +if test5 <> expected5 then failwith $"test5 failed: got {test5}" + +let test6 = [|0; 5..5; 10|] +let expected6 = [|0; 5; 10|] +if test6 <> expected6 then failwith $"test6 failed: got {test6}" + +printfn "All array tests passed!" + """ + |> withLangVersion90 + |> asExe + |> compileAndRun + |> shouldSucceed + + [] + let ``Mixed ranges and values in sequences``() = + FSharp """ +module MixedRangeSeqTests + +let test1 = seq { 1..10; 19 } +let expected1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 19] +if List.ofSeq test1 <> expected1 then failwith $"test1 failed" + +let test2 = seq { -3; 1..5; 10..12 } +let expected2 = [-3; 1; 2; 3; 4; 5; 10; 11; 12] +if List.ofSeq test2 <> expected2 then failwith $"test2 failed" + +let test3 = seq { 0; 2..2..10; 15 } +let expected3 = [0; 2; 4; 6; 8; 10; 15] +if List.ofSeq test3 <> expected3 then failwith $"test3 failed" + +let test4 = seq { + yield 1 + yield! [2..5] + yield 10 + yield! [15..2..20] +} +let expected4 = [1; 2; 3; 4; 5; 10; 15; 17; 19] +if List.ofSeq test4 <> expected4 then failwith $"test4 failed" + +printfn "All sequence tests passed!" + """ + |> withLangVersion90 + |> asExe + |> compileAndRun + |> shouldSucceed + + [] + let ``Type inference with mixed ranges and values``() = + FSharp """ +module TypeInferenceTests + +let test1: int list = [1..5; 10] +let test2: int array = [|1..5; 10|] +let test3: seq = seq { 1..5; 10 } + +let inline mixedRange start finish extra = + [start..finish; extra] + +let test4 = mixedRange 1 5 10 +let test5 = mixedRange 1.0 5.0 10.0 +let test6 = mixedRange 'a' 'e' 'z' + +if test4 <> [1; 2; 3; 4; 5; 10] then failwith "int range failed" +if test5 <> [1.0; 2.0; 3.0; 4.0; 5.0; 10.0] then failwith "float range failed" +if test6 <> ['a'; 'b'; 'c'; 'd'; 'e'; 'z'] then failwith "char range failed" + +printfn "Type inference tests passed!" + """ + |> withLangVersion90 + |> asExe + |> compileAndRun + |> shouldSucceed + + [] + let ``Complex expressions with mixed ranges and values``() = + FSharp """ +module ComplexExpressionTests + +let x = 5 +let test1 = [1; x..x+5; 20] +let expected1 = [1; 5; 6; 7; 8; 9; 10; 20] +if test1 <> expected1 then failwith $"test1 failed: got {test1}" + +// Conditional with ranges +let includeRange = true +let test2 = if includeRange then [1; 2..5; 10] else [1; 10] +let expected2 = [1; 2; 3; 4; 5; 10] +if test2 <> expected2 then failwith $"test2 failed: got {test2}" + +let getStart() = 1 +let getEnd() = 5 +let test3 = [0; getStart()..getEnd(); 10] +let expected3 = [0; 1; 2; 3; 4; 5; 10] +if test3 <> expected3 then failwith $"test3 failed: got {test3}" + +let test4 = [ + yield 1 + yield! [2..4] + yield 5 + yield! [6; 7..9; 10] +] +let expected4 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] +if test4 <> expected4 then failwith $"test4 failed: got {test4}" + +printfn "Complex expression tests passed!" + """ + |> withLangVersion90 + |> asExe + |> compileAndRun + |> shouldSucceed + + [] + let ``Edge cases for mixed ranges and values``() = + FSharp """ +module EdgeCaseTests + +let test1 = [1..3; 5..7; 9..10] +let expected1 = [1; 2; 3; 5; 6; 7; 9; 10] +if test1 <> expected1 then failwith $"test1 failed: got {test1}" + +let test2 = [1..5; 3..7] +let expected2 = [1; 2; 3; 4; 5; 3; 4; 5; 6; 7] +if test2 <> expected2 then failwith $"test2 failed: got {test2}" + +let test3 = [20; 10..-1..5; 0] +let expected3 = [20; 10; 9; 8; 7; 6; 5; 0] +if test3 <> expected3 then failwith $"test3 failed: got {test3}" + +let test4 = [0; 1..1000; 2000] +if test4.Length <> 1002 then failwith $"test4 failed: expected length 1002, got {test4.Length}" +if test4.[0] <> 0 then failwith "test4: first element should be 0" +if test4.[1001] <> 2000 then failwith "test4: last element should be 2000" + +// Mixed types should fail compilation +// This is a compile-time test, not runtime +// let shouldFail = [1; 2.0..5.0] // This should not compile + +printfn "Edge case tests passed!" + """ + |> withLangVersion90 + |> asExe + |> compileAndRun + |> shouldSucceed \ No newline at end of file From 433e5dabbc1ac6537a9e83200c0baf26665035b8 Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Fri, 6 Jun 2025 22:38:17 +0100 Subject: [PATCH 08/39] Add AllowMixedRangesAndValuesInSeqExpressions --- src/Compiler/FSComp.txt | 1 + src/Compiler/Facilities/LanguageFeatures.fs | 3 +++ src/Compiler/Facilities/LanguageFeatures.fsi | 1 + src/Compiler/xlf/FSComp.txt.cs.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.de.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.es.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.fr.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.it.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.ja.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.ko.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.pl.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.ru.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.tr.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 5 +++++ 16 files changed, 70 insertions(+) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 78dde5bd148..dcd3608463e 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1802,6 +1802,7 @@ featureSupportWarnWhenUnitPassedToObjArg,"Warn when unit is passed to a member a featureUseBangBindingValueDiscard,"Allows use! _ = ... in computation expressions" featureBetterAnonymousRecordParsing,"Support for better anonymous record parsing" featureScopedNowarn,"Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules" +featureAllowMixedRangesAndValuesInSeqExpressions,"Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }}" featureAllowLetOrUseBangTypeAnnotationWithoutParens,"Allow let! and use! type annotations without requiring parentheses" 3874,lexWarnDirectiveMustBeFirst,"#nowarn/#warnon directives must appear as the first non-whitespace characters on a line" 3875,lexWarnDirectiveMustHaveArgs,"Warn directives must have warning number(s) as argument(s)" diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index 246ec741d67..9340eb8c0b7 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -103,6 +103,7 @@ type LanguageFeature = | BetterAnonymousRecordParsing | ScopedNowarn | AllowTypedLetOrUseBang + | AllowMixedRangesAndValuesInSeqExpressions /// LanguageVersion management type LanguageVersion(versionText) = @@ -237,6 +238,7 @@ type LanguageVersion(versionText) = LanguageFeature.BetterAnonymousRecordParsing, previewVersion LanguageFeature.ScopedNowarn, previewVersion LanguageFeature.AllowTypedLetOrUseBang, previewVersion + LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions, previewVersion ] static let defaultLanguageVersion = LanguageVersion("default") @@ -403,6 +405,7 @@ type LanguageVersion(versionText) = | LanguageFeature.BetterAnonymousRecordParsing -> FSComp.SR.featureBetterAnonymousRecordParsing () | LanguageFeature.ScopedNowarn -> FSComp.SR.featureScopedNowarn () | LanguageFeature.AllowTypedLetOrUseBang -> FSComp.SR.featureAllowLetOrUseBangTypeAnnotationWithoutParens () + | LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions -> FSComp.SR.featureAllowMixedRangesAndValuesInSeqExpressions () /// 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 c9e70ce1567..9ed0e868964 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -94,6 +94,7 @@ type LanguageFeature = | BetterAnonymousRecordParsing | ScopedNowarn | AllowTypedLetOrUseBang + | AllowMixedRangesAndValuesInSeqExpressions /// LanguageVersion management type LanguageVersion = diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index bcd1c3fb0bd..b29dbfaebc6 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -292,6 +292,11 @@ Allow let! and use! type annotations without requiring parentheses + + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + + Allow object expressions without overrides Allow object expressions without overrides diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 0886b9ec60b..d0b5746c603 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -292,6 +292,11 @@ Allow let! and use! type annotations without requiring parentheses + + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + + Allow object expressions without overrides Allow object expressions without overrides diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index bdb43c5e1af..5cfa09f0432 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -292,6 +292,11 @@ Allow let! and use! type annotations without requiring parentheses + + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + + Allow object expressions without overrides Allow object expressions without overrides diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 5344354b3ab..7be81a9ad23 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -292,6 +292,11 @@ Allow let! and use! type annotations without requiring parentheses + + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + + Allow object expressions without overrides Allow object expressions without overrides diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index ec472ee00b9..2c2b90b0f0a 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -292,6 +292,11 @@ Allow let! and use! type annotations without requiring parentheses + + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + + Allow object expressions without overrides Allow object expressions without overrides diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 8db04ab1625..ef9822c9c7b 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -292,6 +292,11 @@ Allow let! and use! type annotations without requiring parentheses + + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + + Allow object expressions without overrides Allow object expressions without overrides diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index a17460ee156..b6ad67fa237 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -292,6 +292,11 @@ Allow let! and use! type annotations without requiring parentheses + + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + + Allow object expressions without overrides Allow object expressions without overrides diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 94416cfb231..37e1434b9e5 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -292,6 +292,11 @@ Allow let! and use! type annotations without requiring parentheses + + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + + Allow object expressions without overrides Allow object expressions without overrides diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 99709def4e0..c846a0dee4a 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -292,6 +292,11 @@ Allow let! and use! type annotations without requiring parentheses + + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + + Allow object expressions without overrides Allow object expressions without overrides diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index e1e97fdf67e..d760599f094 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -292,6 +292,11 @@ Allow let! and use! type annotations without requiring parentheses + + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + + Allow object expressions without overrides Allow object expressions without overrides diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index cff0f89ef17..70be886278d 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -292,6 +292,11 @@ Allow let! and use! type annotations without requiring parentheses + + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + + Allow object expressions without overrides Allow object expressions without overrides diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 5ce3ac9c822..dd32894ebd2 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -292,6 +292,11 @@ Allow let! and use! type annotations without requiring parentheses + + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + + Allow object expressions without overrides Allow object expressions without overrides diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index ae4eeed6b13..6bc5d6e5129 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -292,6 +292,11 @@ Allow let! and use! type annotations without requiring parentheses + + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + Allow mixed ranges and values in sequence expressions, e.g. seq {{ 1..10; 20 }} + + Allow object expressions without overrides Allow object expressions without overrides From bfc42207f4554f70e26603bd5c4f0c6c52918820 Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Fri, 6 Jun 2025 22:38:42 +0100 Subject: [PATCH 09/39] Use AllowMixedRangesAndValuesInSeqExpressions --- .../Expressions/CheckArrayOrListComputedExpressions.fs | 10 +++++++++- .../Checking/Expressions/CheckSequenceExpressions.fs | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs index 0dd2d013c26..6da9afbafff 100644 --- a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs @@ -75,7 +75,10 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT | SynExpr.IndexRange _ -> true | _ -> false) - if containsRanges then + if + containsRanges + && g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions + then let rec buildBody elems = match elems with | [] -> SynExpr.Const(SynConst.Unit, m) @@ -151,6 +154,11 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT expr, tpenv') else + // Check if ranges are present but feature is disabled + if containsRanges then + // Report error for mixed ranges when feature is disabled + checkLanguageFeatureAndRecover cenv.g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m + let replacementExpr = if isArray then let nelems = elems.Length diff --git a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs index 17da4aa43f2..1401ea0f638 100644 --- a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs @@ -470,7 +470,10 @@ let TcSequenceExpressionEntry (cenv: TcFileState) env (overallTy: OverallTy) tpe | SynExpr.IndexRange _ -> true | _ -> false) - if containsRanges then + if + containsRanges + && cenv.g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions + then // Transform to proper sequence expression body: yield v1; yield! r1..r2; yield v2; ... let rec buildSeqBody elems = match elems with @@ -521,6 +524,11 @@ let TcSequenceExpressionEntry (cenv: TcFileState) env (overallTy: OverallTy) tpe let transformedBody = buildSeqBody elems TcSequenceExpression cenv env tpenv transformedBody overallTy m else + // Check if ranges are present but feature is disabled + if containsRanges then + // Report error for mixed ranges when feature is disabled + checkLanguageFeatureAndRecover cenv.g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m + // No ranges, use regular handling TcSequenceExpression cenv env tpenv comp overallTy m | _ -> From c7246850ef8f98da61fa6695515dc711c5c07ac7 Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Fri, 6 Jun 2025 22:41:37 +0100 Subject: [PATCH 10/39] update tests --- ...dRangesAndValuesSequenceExpressionTests.fs | 96 +++++++++++++++---- 1 file changed, 78 insertions(+), 18 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedRangesAndValuesSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedRangesAndValuesSequenceExpressionTests.fs index 4a42ede8829..bed96ad401f 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedRangesAndValuesSequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedRangesAndValuesSequenceExpressionTests.fs @@ -7,6 +7,72 @@ open Xunit open FSharp.Test.Compiler module MixedRangesAndValuesSequenceExpressionTests = + + let verifyCompile compilation = + compilation + |> asExe + |> withOptions ["--nowarn:988"] + |> compile + + let verifyCompileAndRun compilation = + compilation + |> asExe + |> withOptions ["--nowarn:988"] + |> compileAndRun + + [] + let ``Version 90: Mixed ranges and values require preview language version``() = + FSharp """ +module MixedRangeVersionTest + +let test = [1; 2..5; 10] + """ + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 4, Col 12, Line 4, Col 25, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 4, Col 16, Line 4, Col 20, "Incomplete expression or invalid use of indexer syntax") + ] + + [] + let ``Preview: Mixed ranges and values require preview language version``() = + FSharp """ +module MixedRangeVersionTest + +let test = [1; 2..5; 10] + """ + |> withLangVersionPreview + |> verifyCompile + |> shouldSucceed + + [] + let ``Version 90: Mixed ranges require preview language version``() = + FSharp """ +module MixedRangeVersionTest + +let test = [ 2..5; 10..20 ] + """ + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 4, Col 12, Line 4, Col 28, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 4, Col 14, Line 4, Col 18, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 4, Col 20, Line 4, Col 26, "Incomplete expression or invalid use of indexer syntax") + ] + + [] + let ``Preview: Mixed ranges require preview language version``() = + FSharp """ +module MixedRangeVersionTest + +let test = [ 2..5; 10..20 ] + """ + |> withLangVersionPreview + |> verifyCompile + |> shouldSucceed + [] let ``Mixed ranges and values in lists``() = FSharp """ @@ -30,9 +96,8 @@ if test4 <> expected4 then failwith $"test4 failed: got {test4}" printfn "All list tests passed!" """ - |> withLangVersion90 - |> asExe - |> compileAndRun + |> withLangVersionPreview + |> verifyCompileAndRun |> shouldSucceed [] @@ -66,9 +131,8 @@ if test6 <> expected6 then failwith $"test6 failed: got {test6}" printfn "All array tests passed!" """ - |> withLangVersion90 - |> asExe - |> compileAndRun + |> withLangVersionPreview + |> verifyCompileAndRun |> shouldSucceed [] @@ -99,9 +163,8 @@ if List.ofSeq test4 <> expected4 then failwith $"test4 failed" printfn "All sequence tests passed!" """ - |> withLangVersion90 - |> asExe - |> compileAndRun + |> withLangVersionPreview + |> verifyCompileAndRun |> shouldSucceed [] @@ -126,9 +189,8 @@ if test6 <> ['a'; 'b'; 'c'; 'd'; 'e'; 'z'] then failwith "char range failed" printfn "Type inference tests passed!" """ - |> withLangVersion90 - |> asExe - |> compileAndRun + |> withLangVersionPreview + |> verifyCompileAndRun |> shouldSucceed [] @@ -164,9 +226,8 @@ if test4 <> expected4 then failwith $"test4 failed: got {test4}" printfn "Complex expression tests passed!" """ - |> withLangVersion90 - |> asExe - |> compileAndRun + |> withLangVersionPreview + |> verifyCompileAndRun |> shouldSucceed [] @@ -197,7 +258,6 @@ if test4.[1001] <> 2000 then failwith "test4: last element should be 2000" printfn "Edge case tests passed!" """ - |> withLangVersion90 - |> asExe - |> compileAndRun + |> withLangVersionPreview + |> verifyCompileAndRun |> shouldSucceed \ No newline at end of file From 80109860fa9e22f965854cfba981b86c19ce1139 Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Sat, 7 Jun 2025 00:14:51 +0100 Subject: [PATCH 11/39] reduce diff --- .../CheckArrayOrListComputedExpressions.fs | 174 +++++++++--------- .../Expressions/CheckSequenceExpressions.fs | 94 +++++----- 2 files changed, 132 insertions(+), 136 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs index 6da9afbafff..5687b655b5d 100644 --- a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs @@ -15,6 +15,87 @@ open FSharp.Compiler.DiagnosticsLogger open FSharp.Compiler.Syntax open FSharp.Compiler.SyntaxTrivia +/// Check if a list/array expression contains range expressions +let private containsRangeExpressions elems = + elems + |> List.exists (function + | SynExpr.IndexRange _ -> true + | _ -> false) + +/// Transform a mixed list/array with ranges into a sequence computation expression +/// E.g., [-3; 1..10; 19] becomes seq { yield -3; yield! 1..10; yield 19 } +let private transformMixedListWithRangesToSeqExpr elems m = + let rec buildBody elems = + match elems with + | [] -> SynExpr.Const(SynConst.Unit, m) + | [ elem ] -> + match elem with + | SynExpr.IndexRange _ -> + match RewriteRangeExpr elem with + | Some rewritten -> + SynExpr.YieldOrReturnFrom( + (true, false), + rewritten, + elem.Range, + { + YieldOrReturnFromKeyword = elem.Range + } + ) + | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + | elem :: rest -> + let headExpr = + match elem with + | SynExpr.IndexRange _ -> + match RewriteRangeExpr elem with + | Some rewritten -> + SynExpr.YieldOrReturnFrom( + (true, false), + rewritten, + elem.Range, + { + YieldOrReturnFromKeyword = elem.Range + } + ) + | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + + let tailExpr = buildBody rest + SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, headExpr, tailExpr, m, SynExprSequentialTrivia.Zero) + + buildBody elems + +let private TcMixedSequencesWithRanges (cenv: TcFileState) env overallTy tpenv isArray elems m = + let g = cenv.g + let transformedBody = transformMixedListWithRangesToSeqExpr elems m + + let genCollElemTy = NewInferenceType g + let genCollTy = (if isArray then mkArrayType else mkListTy) g genCollElemTy + + TcPropagatingExprLeafThenConvert cenv overallTy genCollTy env m (fun () -> + let exprTy = mkSeqTy g genCollElemTy + + let expr, tpenv' = + TcSequenceExpression cenv env tpenv transformedBody (MustEqual exprTy) m + + let expr = mkCoerceIfNeeded g exprTy (tyOfExpr g expr) expr + + let expr = + if g.compilingFSharpCore then + expr + else + mkCallSeq g m genCollElemTy expr + + let expr = mkCoerceExpr (expr, exprTy, expr.Range, overallTy.Commit) + + let expr = + if isArray then + mkCallSeqToArray g m genCollElemTy expr + else + mkCallSeqToList g m genCollElemTy expr + + expr, tpenv') + let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallTy) tpenv (isArray, comp) m = let g = cenv.g @@ -69,97 +150,17 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT errorR (Deprecated(FSComp.SR.tcExpressionWithIfRequiresParenthesis (), m)) | _ -> () - let containsRanges = - elems - |> List.exists (function - | SynExpr.IndexRange _ -> true - | _ -> false) - if - containsRanges + containsRangeExpressions elems && g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions then - let rec buildBody elems = - match elems with - | [] -> SynExpr.Const(SynConst.Unit, m) - | [ elem ] -> - match elem with - | SynExpr.IndexRange _ -> - match RewriteRangeExpr elem with - | Some rewritten -> - SynExpr.YieldOrReturnFrom( - (true, false), - rewritten, - elem.Range, - { - YieldOrReturnFromKeyword = elem.Range - } - ) - | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - | elem :: rest -> - let headExpr = - match elem with - | SynExpr.IndexRange _ -> - match RewriteRangeExpr elem with - | Some rewritten -> - SynExpr.YieldOrReturnFrom( - (true, false), - rewritten, - elem.Range, - { - YieldOrReturnFromKeyword = elem.Range - } - ) - | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - - let tailExpr = buildBody rest - - SynExpr.Sequential( - DebugPointAtSequential.SuppressNeither, - true, - headExpr, - tailExpr, - m, - SynExprSequentialTrivia.Zero - ) - - let transformedBody = buildBody elems - - let genCollElemTy = NewInferenceType g - let genCollTy = (if isArray then mkArrayType else mkListTy) cenv.g genCollElemTy - - TcPropagatingExprLeafThenConvert cenv overallTy genCollTy env m (fun () -> - let exprTy = mkSeqTy cenv.g genCollElemTy - - let expr, tpenv' = - TcSequenceExpression cenv env tpenv transformedBody (MustEqual exprTy) m - - let expr = mkCoerceIfNeeded cenv.g exprTy (tyOfExpr cenv.g expr) expr - - let expr = - if cenv.g.compilingFSharpCore then - expr - else - mkCallSeq cenv.g m genCollElemTy expr - - let expr = mkCoerceExpr (expr, exprTy, expr.Range, overallTy.Commit) - - let expr = - if isArray then - mkCallSeqToArray cenv.g m genCollElemTy expr - else - mkCallSeqToList cenv.g m genCollElemTy expr - - expr, tpenv') + TcMixedSequencesWithRanges cenv env overallTy tpenv isArray elems m else - // Check if ranges are present but feature is disabled - if containsRanges then - // Report error for mixed ranges when feature is disabled + if containsRangeExpressions elems then checkLanguageFeatureAndRecover cenv.g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m let replacementExpr = + // This are to improve parsing/processing speed for parser tables by converting to an array blob ASAP if isArray then let nelems = elems.Length @@ -227,7 +228,8 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT let exprTy = mkSeqTy cenv.g genCollElemTy - let expr, tpenv' = TcSequenceExpression cenv env tpenv comp (MustEqual exprTy) m + // Check the comprehension + let expr, tpenv = TcSequenceExpression cenv env tpenv comp (MustEqual exprTy) m let expr = mkCoerceIfNeeded cenv.g exprTy (tyOfExpr cenv.g expr) expr @@ -248,4 +250,4 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT else mkCallSeqToList cenv.g m genCollElemTy expr - expr, tpenv') + expr, tpenv) diff --git a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs index 1401ea0f638..7c85819a2d3 100644 --- a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs @@ -450,6 +450,49 @@ let TcSequenceExpression (cenv: TcFileState) env tpenv comp (overallTy: OverallT let delayedExpr = mkSeqDelayedExpr coreExpr.Range coreExpr delayedExpr, tpenv +let private TcMixedSequencesWithRanges cenv env tpenv overallTy elems m = + let rec buildSeqBody elems = + match elems with + | [] -> SynExpr.Const(SynConst.Unit, m) + | [ elem ] -> + match elem with + | SynExpr.IndexRange _ -> + match RewriteRangeExpr elem with + | Some rewrittenRange -> + SynExpr.YieldOrReturnFrom( + (true, false), + rewrittenRange, + elem.Range, + { + YieldOrReturnFromKeyword = elem.Range + } + ) + | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + | elem :: rest -> + let headExpr = + match elem with + | SynExpr.IndexRange _ -> + match RewriteRangeExpr elem with + | Some rewrittenRange -> + SynExpr.YieldOrReturnFrom( + (true, false), + rewrittenRange, + elem.Range, + { + YieldOrReturnFromKeyword = elem.Range + } + ) + | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) + + let tailExpr = buildSeqBody rest + + SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, headExpr, tailExpr, m, SynExprSequentialTrivia.Zero) + + let transformedBody = buildSeqBody elems + TcSequenceExpression cenv env tpenv transformedBody overallTy m + let TcSequenceExpressionEntry (cenv: TcFileState) env (overallTy: OverallTy) tpenv (hasBuilder, comp) m = match RewriteRangeExpr comp with | Some replacementExpr -> TcExpr cenv overallTy env tpenv replacementExpr @@ -463,7 +506,6 @@ let TcSequenceExpressionEntry (cenv: TcFileState) env (overallTy: OverallTy) tpe | SimpleSemicolonSequence cenv false _ when validateObjectSequenceOrRecordExpression -> error (Error(FSComp.SR.tcInvalidObjectSequenceOrRecordExpression (), m)) | SimpleSemicolonSequence cenv false elems when hasBuilder -> - // Check if we have any range expressions mixed with regular values in seq { ... } let containsRanges = elems |> List.exists (function @@ -474,55 +516,7 @@ let TcSequenceExpressionEntry (cenv: TcFileState) env (overallTy: OverallTy) tpe containsRanges && cenv.g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions then - // Transform to proper sequence expression body: yield v1; yield! r1..r2; yield v2; ... - let rec buildSeqBody elems = - match elems with - | [] -> SynExpr.Const(SynConst.Unit, m) - | [ elem ] -> - match elem with - | SynExpr.IndexRange _ -> - match RewriteRangeExpr elem with - | Some rewrittenRange -> - SynExpr.YieldOrReturnFrom( - (true, false), - rewrittenRange, - elem.Range, - { - YieldOrReturnFromKeyword = elem.Range - } - ) - | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - | elem :: rest -> - let headExpr = - match elem with - | SynExpr.IndexRange _ -> - match RewriteRangeExpr elem with - | Some rewrittenRange -> - SynExpr.YieldOrReturnFrom( - (true, false), - rewrittenRange, - elem.Range, - { - YieldOrReturnFromKeyword = elem.Range - } - ) - | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - - let tailExpr = buildSeqBody rest - - SynExpr.Sequential( - DebugPointAtSequential.SuppressNeither, - true, - headExpr, - tailExpr, - m, - SynExprSequentialTrivia.Zero - ) - - let transformedBody = buildSeqBody elems - TcSequenceExpression cenv env tpenv transformedBody overallTy m + TcMixedSequencesWithRanges cenv env tpenv overallTy elems m else // Check if ranges are present but feature is disabled if containsRanges then From 64c4a050acda376fca06a6f71b0506c321a0f357 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Sat, 7 Jun 2025 22:53:09 +0100 Subject: [PATCH 12/39] improve tests --- .../FSharp.Compiler.ComponentTests.fsproj | 2 +- ...dRangesAndValuesSequenceExpressionTests.fs | 263 ------------------ .../MixedSequenceExpressionTests.fs | 178 ++++++++++++ .../SequenceExpressions02.fs | 19 ++ .../SequenceExpressions03.fs | 27 ++ .../SequenceExpressions04.fs | 25 ++ .../SequenceExpressions05.fs | 21 ++ .../SequenceExpressions06.fs | 18 ++ 8 files changed, 289 insertions(+), 264 deletions(-) delete mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedRangesAndValuesSequenceExpressionTests.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions03.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions04.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions05.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions06.fs diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 2eacd0604c7..47fd0c446a6 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -233,7 +233,7 @@ - + diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedRangesAndValuesSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedRangesAndValuesSequenceExpressionTests.fs deleted file mode 100644 index bed96ad401f..00000000000 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedRangesAndValuesSequenceExpressionTests.fs +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. - -namespace Language - -open FSharp.Test -open Xunit -open FSharp.Test.Compiler - -module MixedRangesAndValuesSequenceExpressionTests = - - let verifyCompile compilation = - compilation - |> asExe - |> withOptions ["--nowarn:988"] - |> compile - - let verifyCompileAndRun compilation = - compilation - |> asExe - |> withOptions ["--nowarn:988"] - |> compileAndRun - - [] - let ``Version 90: Mixed ranges and values require preview language version``() = - FSharp """ -module MixedRangeVersionTest - -let test = [1; 2..5; 10] - """ - |> withLangVersion90 - |> verifyCompile - |> shouldFail - |> withDiagnostics [ - (Error 3350, Line 4, Col 12, Line 4, Col 25, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 4, Col 16, Line 4, Col 20, "Incomplete expression or invalid use of indexer syntax") - ] - - [] - let ``Preview: Mixed ranges and values require preview language version``() = - FSharp """ -module MixedRangeVersionTest - -let test = [1; 2..5; 10] - """ - |> withLangVersionPreview - |> verifyCompile - |> shouldSucceed - - [] - let ``Version 90: Mixed ranges require preview language version``() = - FSharp """ -module MixedRangeVersionTest - -let test = [ 2..5; 10..20 ] - """ - |> withLangVersion90 - |> verifyCompile - |> shouldFail - |> withDiagnostics [ - (Error 3350, Line 4, Col 12, Line 4, Col 28, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); - (Error 751, Line 4, Col 14, Line 4, Col 18, "Incomplete expression or invalid use of indexer syntax"); - (Error 751, Line 4, Col 20, Line 4, Col 26, "Incomplete expression or invalid use of indexer syntax") - ] - - [] - let ``Preview: Mixed ranges require preview language version``() = - FSharp """ -module MixedRangeVersionTest - -let test = [ 2..5; 10..20 ] - """ - |> withLangVersionPreview - |> verifyCompile - |> shouldSucceed - - [] - let ``Mixed ranges and values in lists``() = - FSharp """ -module MixedRangeListTests - -let test1 = [-3; 1..10] -let expected1 = [-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10] -if test1 <> expected1 then failwith $"test1 failed: got {test1}" - -let test2 = [-3; 1..10; 19] -let expected2 = [-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 19] -if test2 <> expected2 then failwith $"test2 failed: got {test2}" - -let test3 = [1..3; 5..7; 10] -let expected3 = [1; 2; 3; 5; 6; 7; 10] -if test3 <> expected3 then failwith $"test3 failed: got {test3}" - -let test4 = [0; 2..2..10; 15] -let expected4 = [0; 2; 4; 6; 8; 10; 15] -if test4 <> expected4 then failwith $"test4 failed: got {test4}" - -printfn "All list tests passed!" - """ - |> withLangVersionPreview - |> verifyCompileAndRun - |> shouldSucceed - - [] - let ``Mixed ranges and values in arrays``() = - FSharp """ -module MixedRangeArrayTests - -let test1 = [|-3; 1..10|] -let expected1 = [|-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10|] -if test1 <> expected1 then failwith $"test1 failed: got {test1}" - -let test2 = [|-3; 1..10; 19|] -let expected2 = [|-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 19|] -if test2 <> expected2 then failwith $"test2 failed: got {test2}" - -let test3 = [|1..3; 5..7; 10|] -let expected3 = [|1; 2; 3; 5; 6; 7; 10|] -if test3 <> expected3 then failwith $"test3 failed: got {test3}" - -let test4 = [|0; 2..2..10; 15|] -let expected4 = [|0; 2; 4; 6; 8; 10; 15|] -if test4 <> expected4 then failwith $"test4 failed: got {test4}" - -let test5 = [|1; 5..4; 10|] -let expected5 = [|1; 10|] -if test5 <> expected5 then failwith $"test5 failed: got {test5}" - -let test6 = [|0; 5..5; 10|] -let expected6 = [|0; 5; 10|] -if test6 <> expected6 then failwith $"test6 failed: got {test6}" - -printfn "All array tests passed!" - """ - |> withLangVersionPreview - |> verifyCompileAndRun - |> shouldSucceed - - [] - let ``Mixed ranges and values in sequences``() = - FSharp """ -module MixedRangeSeqTests - -let test1 = seq { 1..10; 19 } -let expected1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 19] -if List.ofSeq test1 <> expected1 then failwith $"test1 failed" - -let test2 = seq { -3; 1..5; 10..12 } -let expected2 = [-3; 1; 2; 3; 4; 5; 10; 11; 12] -if List.ofSeq test2 <> expected2 then failwith $"test2 failed" - -let test3 = seq { 0; 2..2..10; 15 } -let expected3 = [0; 2; 4; 6; 8; 10; 15] -if List.ofSeq test3 <> expected3 then failwith $"test3 failed" - -let test4 = seq { - yield 1 - yield! [2..5] - yield 10 - yield! [15..2..20] -} -let expected4 = [1; 2; 3; 4; 5; 10; 15; 17; 19] -if List.ofSeq test4 <> expected4 then failwith $"test4 failed" - -printfn "All sequence tests passed!" - """ - |> withLangVersionPreview - |> verifyCompileAndRun - |> shouldSucceed - - [] - let ``Type inference with mixed ranges and values``() = - FSharp """ -module TypeInferenceTests - -let test1: int list = [1..5; 10] -let test2: int array = [|1..5; 10|] -let test3: seq = seq { 1..5; 10 } - -let inline mixedRange start finish extra = - [start..finish; extra] - -let test4 = mixedRange 1 5 10 -let test5 = mixedRange 1.0 5.0 10.0 -let test6 = mixedRange 'a' 'e' 'z' - -if test4 <> [1; 2; 3; 4; 5; 10] then failwith "int range failed" -if test5 <> [1.0; 2.0; 3.0; 4.0; 5.0; 10.0] then failwith "float range failed" -if test6 <> ['a'; 'b'; 'c'; 'd'; 'e'; 'z'] then failwith "char range failed" - -printfn "Type inference tests passed!" - """ - |> withLangVersionPreview - |> verifyCompileAndRun - |> shouldSucceed - - [] - let ``Complex expressions with mixed ranges and values``() = - FSharp """ -module ComplexExpressionTests - -let x = 5 -let test1 = [1; x..x+5; 20] -let expected1 = [1; 5; 6; 7; 8; 9; 10; 20] -if test1 <> expected1 then failwith $"test1 failed: got {test1}" - -// Conditional with ranges -let includeRange = true -let test2 = if includeRange then [1; 2..5; 10] else [1; 10] -let expected2 = [1; 2; 3; 4; 5; 10] -if test2 <> expected2 then failwith $"test2 failed: got {test2}" - -let getStart() = 1 -let getEnd() = 5 -let test3 = [0; getStart()..getEnd(); 10] -let expected3 = [0; 1; 2; 3; 4; 5; 10] -if test3 <> expected3 then failwith $"test3 failed: got {test3}" - -let test4 = [ - yield 1 - yield! [2..4] - yield 5 - yield! [6; 7..9; 10] -] -let expected4 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] -if test4 <> expected4 then failwith $"test4 failed: got {test4}" - -printfn "Complex expression tests passed!" - """ - |> withLangVersionPreview - |> verifyCompileAndRun - |> shouldSucceed - - [] - let ``Edge cases for mixed ranges and values``() = - FSharp """ -module EdgeCaseTests - -let test1 = [1..3; 5..7; 9..10] -let expected1 = [1; 2; 3; 5; 6; 7; 9; 10] -if test1 <> expected1 then failwith $"test1 failed: got {test1}" - -let test2 = [1..5; 3..7] -let expected2 = [1; 2; 3; 4; 5; 3; 4; 5; 6; 7] -if test2 <> expected2 then failwith $"test2 failed: got {test2}" - -let test3 = [20; 10..-1..5; 0] -let expected3 = [20; 10; 9; 8; 7; 6; 5; 0] -if test3 <> expected3 then failwith $"test3 failed: got {test3}" - -let test4 = [0; 1..1000; 2000] -if test4.Length <> 1002 then failwith $"test4 failed: expected length 1002, got {test4.Length}" -if test4.[0] <> 0 then failwith "test4: first element should be 0" -if test4.[1001] <> 2000 then failwith "test4: last element should be 2000" - -// Mixed types should fail compilation -// This is a compile-time test, not runtime -// let shouldFail = [1; 2.0..5.0] // This should not compile - -printfn "Edge case tests passed!" - """ - |> withLangVersionPreview - |> verifyCompileAndRun - |> shouldSucceed \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs new file mode 100644 index 00000000000..1cc9a512002 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs @@ -0,0 +1,178 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Language + +open FSharp.Test +open Xunit +open FSharp.Test.Compiler + +module MixedSequenceExpressionTests = + + let verifyCompile compilation = + compilation + |> asExe + |> withOptions ["--nowarn:988"] + |> compile + + let verifyCompileAndRun compilation = + compilation + |> asExe + |> withOptions ["--nowarn:988"] + |> compileAndRun + + [] + let ``Version 90: Mixed ranges and values require preview language version``() = + FSharp """ +module MixedRangeVersionTest + +let test = [1; 2..5; 10] + """ + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 4, Col 12, Line 4, Col 25, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 4, Col 16, Line 4, Col 20, "Incomplete expression or invalid use of indexer syntax") + ] + + [] + let ``Preview: Mixed ranges and values require preview language version``() = + FSharp """ +module MixedRangeVersionTest + +let test = [1; 2..5; 10] + """ + |> withLangVersionPreview + |> verifyCompile + |> shouldSucceed + + // SOURCE=SequenceExpressions02.fs # SequenceExpressions02.fs + [] + let ``Version 9: SequenceExpressions02 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 13, Line 3, Col 24, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 3, Col 18, Line 3, Col 23, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 7, Col 13, Line 7, Col 28, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 7, Col 18, Line 7, Col 23, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 11, Col 13, Line 11, Col 29, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 11, Col 14, Line 11, Col 18, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 11, Col 20, Line 11, Col 24, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 15, Col 13, Line 15, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 15, Col 17, Line 15, Col 25, "Incomplete expression or invalid use of indexer syntax") + ] + + // SOURCE=SequenceExpressions02.fs # SequenceExpressions02.fs + [] + let ``Preview: SequenceExpressions02 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions03.fs # SequenceExpressions03.fs + [] + let ``Preview: SequenceExpressions03 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions03.fs # SequenceExpressions03.fs + [] + let ``Version 9: SequenceExpressions03 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 13, Line 3, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 3, Col 19, Line 3, Col 24, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 7, Col 13, Line 7, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 7, Col 19, Line 7, Col 24, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 11, Col 13, Line 11, Col 31, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 11, Col 15, Line 11, Col 19, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 11, Col 21, Line 11, Col 25, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 15, Col 13, Line 15, Col 32, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 15, Col 18, Line 15, Col 26, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 19, Col 13, Line 19, Col 28, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 19, Col 18, Line 19, Col 22, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 23, Col 13, Line 23, Col 28, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 23, Col 18, Line 23, Col 22, "Incomplete expression or invalid use of indexer syntax") + ] + + // SOURCE=SequenceExpressions04.fs # SequenceExpressions04.fs + [] + let ``Preview: SequenceExpressions04 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions04.fs # SequenceExpressions04.fs + [] + let ``Version 9: SequenceExpressions04 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 17, Line 3, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 3, Col 19, Line 3, Col 24, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 7, Col 17, Line 7, Col 37, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 7, Col 23, Line 7, Col 27, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 7, Col 29, Line 7, Col 35, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 11, Col 17, Line 11, Col 36, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 11, Col 22, Line 11, Col 30, "Incomplete expression or invalid use of indexer syntax") + ] + + // SOURCE=SequenceExpressions05.fs # SequenceExpressions05.fs + [] + let ``Preview: SequenceExpressions05 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions05.fs # SequenceExpressions05.fs + [] + let ``Version 9: SequenceExpressions05 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 17, Line 3, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 3, Col 19, Line 3, Col 24, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 7, Col 17, Line 7, Col 36, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 7, Col 22, Line 7, Col 30, "Incomplete expression or invalid use of indexer syntax") + ] + + // SOURCE=SequenceExpressions06.fs # SequenceExpressions06.fs + [] + let ``Preview: SequenceExpressions06 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions06.fs # SequenceExpressions06.fs + [] + let ``Version 9: SequenceExpressions06 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 23, Line 3, Col 33, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 3, Col 24, Line 3, Col 28, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 4, Col 24, Line 4, Col 36, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 4, Col 26, Line 4, Col 30, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 5, Col 27, Line 5, Col 39, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 5, Col 29, Line 5, Col 33, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 8, Col 5, Line 8, Col 27, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 8, Col 6, Line 8, Col 19, "Incomplete expression or invalid use of indexer syntax") + ] \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02.fs new file mode 100644 index 00000000000..69427e47cb7 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02.fs @@ -0,0 +1,19 @@ +module MixedRangeListTests + +let test1 = [-3; 1..10] +let expected1 = [-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10] +if test1 <> expected1 then failwith $"test1 failed: got {test1}" + +let test2 = [-3; 1..10; 19] +let expected2 = [-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 19] +if test2 <> expected2 then failwith $"test2 failed: got {test2}" + +let test3 = [1..3; 5..7; 10] +let expected3 = [1; 2; 3; 5; 6; 7; 10] +if test3 <> expected3 then failwith $"test3 failed: got {test3}" + +let test4 = [0; 2..2..10; 15] +let expected4 = [0; 2; 4; 6; 8; 10; 15] +if test4 <> expected4 then failwith $"test4 failed: got {test4}" + +printfn "All list tests passed!" \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions03.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions03.fs new file mode 100644 index 00000000000..f835c06052f --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions03.fs @@ -0,0 +1,27 @@ +module MixedRangeArrayTests + +let test1 = [|-3; 1..10|] +let expected1 = [|-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10|] +if test1 <> expected1 then failwith $"test1 failed: got {test1}" + +let test2 = [|-3; 1..10; 19|] +let expected2 = [|-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 19|] +if test2 <> expected2 then failwith $"test2 failed: got {test2}" + +let test3 = [|1..3; 5..7; 10|] +let expected3 = [|1; 2; 3; 5; 6; 7; 10|] +if test3 <> expected3 then failwith $"test3 failed: got {test3}" + +let test4 = [|0; 2..2..10; 15|] +let expected4 = [|0; 2; 4; 6; 8; 10; 15|] +if test4 <> expected4 then failwith $"test4 failed: got {test4}" + +let test5 = [|1; 5..4; 10|] +let expected5 = [|1; 10|] +if test5 <> expected5 then failwith $"test5 failed: got {test5}" + +let test6 = [|0; 5..5; 10|] +let expected6 = [|0; 5; 10|] +if test6 <> expected6 then failwith $"test6 failed: got {test6}" + +printfn "All array tests passed!" \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions04.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions04.fs new file mode 100644 index 00000000000..46b6ccaef15 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions04.fs @@ -0,0 +1,25 @@ +module MixedRangeSeqTests + +let test1 = seq { 1..10; 19 } +let expected1 = seq { 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 19 } +if List.ofSeq test1 <> List.ofSeq expected1 then failwith $"test1 failed got {test1}" + +let test2 = seq { -3; 1..5; 10..12 } +let expected2 = seq { -3; 1; 2; 3; 4; 5; 10; 11; 12 } +if List.ofSeq test2 <> List.ofSeq expected2 then failwith $"test2 failed got {test2}" + +let test3 = seq { 0; 2..2..10; 15 } +let expected3 = seq { 0; 2; 4; 6; 8; 10; 15 } +if List.ofSeq test3 <> List.ofSeq expected3 then failwith $"test3 failed got {test3}" + +let test4 = seq { + yield 1 + yield! seq { 2..5 } + yield 10 + yield! seq { 15..2..20 } +} + +let expected4 = seq { 1; 2; 3; 4; 5; 10; 15; 17; 19 } +if List.ofSeq test4 <> List.ofSeq expected4 then failwith $"test4 failed got {test4}" + +printfn "All sequence tests passed!" \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions05.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions05.fs new file mode 100644 index 00000000000..0a7e119714b --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions05.fs @@ -0,0 +1,21 @@ +module MixedRangeSeqTests + +let test1 = seq { 1..10; 19 } +let expected1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 19] +if List.ofSeq test1 <> expected1 then failwith $"test1 failed" + +let test2 = seq { 0; 2..2..10; 15 } +let expected2 = [|0; 2; 4; 6; 8; 10; 15|] +if Array.ofSeq test2 <> expected2 then failwith $"test2 failed" + +let test3 = seq { + yield 1 + yield! [2..5] + yield 10 + yield! [| 15..2..20 |] +} + +let expected3 = [1; 2; 3; 4; 5; 10; 15; 17; 19] +if List.ofSeq test3 <> expected3 then failwith $"test3 failed" + +printfn "All sequence tests passed!" \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions06.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions06.fs new file mode 100644 index 00000000000..8a9bce2ed58 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions06.fs @@ -0,0 +1,18 @@ +module TypeInferenceTests + +let test1: int list = [1..5; 10] +let test2: int array = [|1..5; 10|] +let test3: seq = seq { 1..5; 10 } + +let inline mixedRange start finish extra = + [start..finish; extra] + +let test4 = mixedRange 1 5 10 +let test5 = mixedRange 1.0 5.0 10.0 +let test6 = mixedRange 'a' 'e' 'z' + +if test4 <> [1; 2; 3; 4; 5; 10] then failwith "int range failed" +if test5 <> [1.0; 2.0; 3.0; 4.0; 5.0; 10.0] then failwith "float range failed" +if test6 <> ['a'; 'b'; 'c'; 'd'; 'e'; 'z'] then failwith "char range failed" + +printfn "Type inference tests passed!" \ No newline at end of file From d505e46ca7dc56e2268b660b037d72bba63569cf Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Sat, 7 Jun 2025 22:59:01 +0100 Subject: [PATCH 13/39] release notes --- docs/release-notes/.FSharp.Compiler.Service/10.0.100.md | 1 + docs/release-notes/.Language/preview.md | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md index b4df947561a..b364248a141 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md @@ -1,6 +1,7 @@ ### Added * Add opt-in warning attribute not valid for union case with fields [PR #18532](https://github.com/dotnet/fsharp/pull/18532)) * Add support for `when 'T : Enum` library-only static optimization constraint. ([PR #18546](https://github.com/dotnet/fsharp/pull/18546)) +* Allow mixing ranges and values to construct sequences. ([PR #18670](https://github.com/dotnet/fsharp/pull/18670)) ### Fixed diff --git a/docs/release-notes/.Language/preview.md b/docs/release-notes/.Language/preview.md index 687402597c5..535a3bf9818 100644 --- a/docs/release-notes/.Language/preview.md +++ b/docs/release-notes/.Language/preview.md @@ -9,6 +9,7 @@ * Fix parsing errors using anonymous records and units of measures ([PR #18543](https://github.com/dotnet/fsharp/pull/18543)) * Scoped Nowarn: added the #warnon compiler directive ([Language suggestion #278](https://github.com/fsharp/fslang-suggestions/issues/278), [RFC FS-1146 PR](https://github.com/fsharp/fslang-design/pull/782), [PR #18049](https://github.com/dotnet/fsharp/pull/18049)) * Allow `let!` and `use!` type annotations without requiring parentheses. ([PR #18508](https://github.com/dotnet/fsharp/pull/18508)) +* Allow mixing ranges and values to construct sequences. ([PR #18670](https://github.com/dotnet/fsharp/pull/18670)) ### Fixed From 77c0e7c435772e9855868ca46251afa50d6b4857 Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Sun, 8 Jun 2025 23:31:54 +0100 Subject: [PATCH 14/39] Allow mixing ranges and values to construct sequences in custom defined CE --- .../CheckComputationExpressions.fs | 98 ++++++++++++++++++- .../MixedSequenceExpressionTests.fs | 51 +++++++++- .../SequenceExpressions07.fs | 25 +++++ 3 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions07.fs diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index 0d2404c5b1a..a46ea325c51 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -944,6 +944,10 @@ let requireBuilderMethod methodName m1 cenv env ad builderTy m2 = if isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m1 ad methodName builderTy) then error (Error(FSComp.SR.tcRequireBuilderMethod methodName, m2)) +/// Checks if a builder method exists (without reporting an error) +let hasBuilderMethod methodName cenv env ad builderTy m = + not (isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad methodName builderTy)) + /// /// Try translate the syntax sugar /// @@ -1559,12 +1563,26 @@ let rec TryTranslateComputationExpression Some(ConsumeCustomOpClauses ceenv comp q varSpace dataCompPriorToOp comp false mClause) | SynExpr.Sequential(sp, true, innerComp1, innerComp2, m, _) -> - + if + ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions + && containsRangeExpressions comp + then + if builderSupportsMixedRanges ceenv m then + let transformed = TransformSequenceWithRanges ceenv comp + Some(TranslateComputationExpression ceenv CompExprTranslationPass.Initial q varSpace transformed translatedCtxt) + else + None // Check for 'where x > y' and other mis-applications of infix operators. If detected, give a good error message, and just ignore innerComp1 - if ceenv.isQuery && checkForBinaryApp ceenv innerComp1 then + elif ceenv.isQuery && checkForBinaryApp ceenv innerComp1 then + if containsRangeExpressions comp then + reportRangeExpressionsNotSupported ceenv comp + Some(TranslateComputationExpression ceenv CompExprTranslationPass.Initial q varSpace innerComp2 translatedCtxt) else + if containsRangeExpressions comp then + reportRangeExpressionsNotSupported ceenv comp + if ceenv.isQuery && not (innerComp1.IsArbExprAndThusAlreadyReportedError) then match innerComp1 with | SynExpr.JoinIn _ -> () @@ -2641,6 +2659,82 @@ and isSimpleExpr ceenv comp = | SynExpr.DoBang _ -> false | _ -> true +/// Check if a sequential expression contains range expressions +and containsRangeExpressions expr = + match expr with + | SynExpr.IndexRange _ -> true + | SynExpr.Sequential(_, true, e1, e2, _, _) -> containsRangeExpressions e1 || containsRangeExpressions e2 + | _ -> false + +/// Report language feature error for each range expression in a sequence +and reportRangeExpressionsNotSupported ceenv expr = + match expr with + | SynExpr.IndexRange(_, _, _, _, _, m) -> + checkLanguageFeatureAndRecover ceenv.cenv.g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m + | SynExpr.Sequential(_, true, e1, e2, _, _) -> + reportRangeExpressionsNotSupported ceenv e1 + reportRangeExpressionsNotSupported ceenv e2 + | _ -> () + +/// Check if this is a simple semicolon sequence (potentially with ranges) +and isSimpleSemicolonSequence ceenv expr = + match expr with + | SynExpr.Sequential(_, true, e1, e2, _, _) -> isSimpleExpr ceenv e1 && isSimpleSemicolonSequence ceenv e2 + | e -> isSimpleExpr ceenv e + +/// Check if builder supports required methods for mixed ranges +and builderSupportsMixedRanges ceenv m = + hasBuilderMethod "Yield" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m + && hasBuilderMethod "Combine" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m + && hasBuilderMethod "Delay" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m + +/// Transform a single expression to Yield or YieldFrom based on whether it's a range +and TransformExprToYieldOrYieldFrom ceenv expr = + match expr with + | SynExpr.IndexRange _ -> + match RewriteRangeExpr expr with + | Some rewrittenRange -> + // Check if YieldFrom is available + match + TryFindIntrinsicOrExtensionMethInfo + ResultCollectionSettings.AllResults + ceenv.cenv + ceenv.env + expr.Range + ceenv.ad + "YieldFrom" + ceenv.builderTy + with + | [] -> + // No YieldFrom, use Yield + // Create a YieldOrReturn expression and let the CE machinery handle it + SynExpr.YieldOrReturn((true, false), rewrittenRange, expr.Range, { YieldOrReturnKeyword = expr.Range }) + | _ -> + SynExpr.YieldOrReturnFrom( + (true, false), + rewrittenRange, + expr.Range, + { + YieldOrReturnFromKeyword = expr.Range + } + ) + | None -> + // If we can't rewrite range, yield the expression + SynExpr.YieldOrReturn((true, false), expr, expr.Range, { YieldOrReturnKeyword = expr.Range }) + | e -> SynExpr.YieldOrReturn((true, false), e, e.Range, { YieldOrReturnKeyword = e.Range }) + +/// Transform a sequential expression with ranges into yields and yieldFroms +and TransformSequenceWithRanges ceenv expr = + match expr with + | SynExpr.Sequential(sp, true, e1, e2, m, trivia) -> + // Transform each part to yield/yieldFrom + let e1Transformed = TransformExprToYieldOrYieldFrom ceenv e1 + let e2Transformed = TransformSequenceWithRanges ceenv e2 + + // Create a new sequential expression with the transformed parts + SynExpr.Sequential(sp, true, e1Transformed, e2Transformed, m, trivia) + | e -> TransformExprToYieldOrYieldFrom ceenv e + and TranslateComputationExpression (ceenv: ComputationExpressionContext<'a>) firstTry q varSpace comp translatedCtxt = ceenv.cenv.stackGuard.Guard diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs index 1cc9a512002..ea3e2ce6197 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs @@ -24,15 +24,25 @@ module MixedSequenceExpressionTests = let ``Version 90: Mixed ranges and values require preview language version``() = FSharp """ module MixedRangeVersionTest + +let a = seq { yield! seq { 1..10 }; 19 } +let b = [-3; yield! [1..10]] +let c = [|-3; yield! [|1..10|]; 19|] -let test = [1; 2..5; 10] +let d = seq { 1..10; 19 } +let e = [-3; 1..10] +let f = [|-3; 1..10; 19|] """ |> withLangVersion90 |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 4, Col 12, Line 4, Col 25, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 4, Col 16, Line 4, Col 20, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 8, Col 13, Line 8, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 8, Col 15, Line 8, Col 20, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 9, Col 9, Line 9, Col 20, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 9, Col 14, Line 9, Col 19, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 10, Col 9, Line 10, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 10, Col 15, Line 10, Col 20, "Incomplete expression or invalid use of indexer syntax") ] [] @@ -40,7 +50,13 @@ let test = [1; 2..5; 10] FSharp """ module MixedRangeVersionTest -let test = [1; 2..5; 10] +let a = seq { yield! seq { 1..10 }; 19 } +let b = [-3; yield! [1..10]] +let c = [|-3; yield! [|1..10|]; 19|] + +let d = seq { 1..10; 19 } +let e = [-3; 1..10] +let f = [|-3; 1..10; 19|] """ |> withLangVersionPreview |> verifyCompile @@ -175,4 +191,31 @@ let test = [1; 2..5; 10] (Error 751, Line 5, Col 29, Line 5, Col 33, "Incomplete expression or invalid use of indexer syntax") (Error 3350, Line 8, Col 5, Line 8, Col 27, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 8, Col 6, Line 8, Col 19, "Incomplete expression or invalid use of indexer syntax") + ] + + // SOURCE=SequenceExpressions07.fs # SequenceExpressions07.fs + [] + let ``Preview: SequenceExpressions07 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + + // SOURCE=SequenceExpressions07.fs # SequenceExpressions07.fs + [] + let ``Version 9: SequenceExpressions07 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 13, Col 25, Line 13, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 13, Col 25, Line 13, Col 30, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 17, Col 21, Line 17, Col 25, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 17, Col 27, Line 17, Col 31, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 17, Col 21, Line 17, Col 25, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 17, Col 27, Line 17, Col 31, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 21, Col 24, Line 21, Col 32, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 21, Col 24, Line 21, Col 32, "Incomplete expression or invalid use of indexer syntax") ] \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions07.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions07.fs new file mode 100644 index 00000000000..7989a0ace81 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions07.fs @@ -0,0 +1,25 @@ +module CustomCEWithRanges + +type ArrayBuilder() = + member _.Yield(x) = [| x |] + member _.YieldFrom(xs: seq<_>) = Seq.toArray xs + member _.Zero() = [||] + member _.Combine(a: int array, b: unit -> int array) = Array.append a (b()) + member _.Delay(f) = f + member _.Run(f) = f() + +let array = ArrayBuilder() + +let test1 = array { -3; 1..10; 19 } +let expected1 = [| -3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 19 |] +if test1 <> expected1 then failwith $"test1 failed: got {test1}" + +let test2 = array { 1..3; 5..7; 10 } +let expected2 = [| 1; 2; 3; 5; 6; 7; 10 |] +if test2 <> expected2 then failwith $"test2 failed: got {test2}" + +let test3 = array { 0; 2..2..10; 15 } +let expected3 = [| 0; 2; 4; 6; 8; 10; 15 |] +if test3 <> expected3 then failwith $"test3 failed: got {test3}" + +printfn "Custom CE with ranges tests passed!" \ No newline at end of file From e535d476572c7e8f04b4683a1ce49d555819d58d Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Mon, 9 Jun 2025 12:45:34 +0100 Subject: [PATCH 15/39] more tests --- .../MixedSequenceExpressionTests.fs | 26 +++++++++++++++- .../SequenceExpressions08.fs | 17 +++++++++++ .../SequenceExpressions09.fs | 30 +++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions08.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions09.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs index ea3e2ce6197..24adc7af224 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs @@ -218,4 +218,28 @@ let f = [|-3; 1..10; 19|] (Error 751, Line 17, Col 27, Line 17, Col 31, "Incomplete expression or invalid use of indexer syntax") (Error 3350, Line 21, Col 24, Line 21, Col 32, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 21, Col 24, Line 21, Col 32, "Incomplete expression or invalid use of indexer syntax") - ] \ No newline at end of file + ] + + // SOURCE=SequenceExpressions08.fs # SequenceExpressions08.fs + [] + let ``Preview: SequenceExpressions08 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions09.fs # SequenceExpressions09.fs + [] + let ``Preview: SequenceExpressions09 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions09.fs # SequenceExpressions09.fs + [] + let ``Version 9: SequenceExpressions09 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompileAndRun + |> shouldSucceed \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions08.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions08.fs new file mode 100644 index 00000000000..6090432cf8c --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions08.fs @@ -0,0 +1,17 @@ +module MixedRangeVersionTest + +let a = seq { yield! seq { 1..10 }; 19 } +let b = [-3; yield! [1..10]] +let c = [|-3; yield! [|1..10|]; 19|] + +let d = seq { 1..10; 19 } +let e = [-3; 1..10] +let f = [|-3; 1..10; 19|] + +if List.ofSeq a <> List.ofSeq d then failwithf $"a = d failed got {List.ofSeq a}" + +if b <> e then failwithf $"b = e failed got {b}" + +if c <> f then failwithf $"c = f failed got {c}" + +printfn "All sequence tests passed!" \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions09.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions09.fs new file mode 100644 index 00000000000..8c183dd8428 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions09.fs @@ -0,0 +1,30 @@ +module OverridingRangeOperator + +open System.Collections +open System.Collections.Generic + +type X(elements: X list) = + member this.Elements = elements + + interface IEnumerable with + member this.GetEnumerator() = + (this.Elements :> IEnumerable).GetEnumerator() + + member this.GetEnumerator() : IEnumerator = + (this.Elements :> IEnumerable).GetEnumerator() + + static member Combine(x1: X, x2: X) = + X(x1.Elements @ x2.Elements) + +let (..) a b = seq { X.Combine(a,b) } + +let a = X([]) +let b = X([]) + +let whatIsThis = seq { a..b } + +let result1 = [ whatIsThis ;a ; b] +let result2 = [ yield! whatIsThis; a; b ] + +printfn $"As is: {result1}" +printfn $"Implicit yield! {result2}" \ No newline at end of file From a647112df3845ad344d2d74df2e8fbd12482127c Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Wed, 11 Jun 2025 21:40:20 +0100 Subject: [PATCH 16/39] more tests --- .../MixedSequenceExpressionTests.fs | 76 +++++++++++++++++++ .../SequenceExpressions10.fs | 63 +++++++++++++++ .../SequenceExpressions11.fs | 63 +++++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions10.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions11.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs index 24adc7af224..47c8629ddd9 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs @@ -220,6 +220,22 @@ let f = [|-3; 1..10; 19|] (Error 751, Line 21, Col 24, Line 21, Col 32, "Incomplete expression or invalid use of indexer syntax") ] + // SOURCE=SequenceExpressions08.fs # SequenceExpressions08.fs + [] + let ``Version 9: SequenceExpressions08 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 7, Col 13, Line 7, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 7, Col 15, Line 7, Col 20, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 8, Col 9, Line 8, Col 20, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 8, Col 14, Line 8, Col 19, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 9, Col 9, Line 9, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 9, Col 15, Line 9, Col 20, "Incomplete expression or invalid use of indexer syntax") + ] + // SOURCE=SequenceExpressions08.fs # SequenceExpressions08.fs [] let ``Preview: SequenceExpressions08 fs`` compilation = @@ -242,4 +258,64 @@ let f = [|-3; 1..10; 19|] compilation |> withLangVersion90 |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions10.fs # SequenceExpressions10.fs + [] + let ``Version 9: SequenceExpressions10 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 13, Line 10, Col 2, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 5, Col 5, Line 5, Col 9, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 7, Col 5, Line 7, Col 11, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 9, Col 5, Line 9, Col 11, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 12, Col 9, Line 19, Col 2, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 14, Col 5, Line 14, Col 9, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 16, Col 5, Line 16, Col 11, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 18, Col 5, Line 18, Col 11, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 20, Col 9, Line 27, Col 3, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 22, Col 5, Line 22, Col 9, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 24, Col 5, Line 24, Col 11, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 26, Col 5, Line 26, Col 11, "Incomplete expression or invalid use of indexer syntax") + ] + + // SOURCE=SequenceExpressions10.fs # SequenceExpressions10.fs + [] + let ``Preview: SequenceExpressions10 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions11.fs # SequenceExpressions11.fs + [] + let ``Version 9: SequenceExpressions11 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 13, Line 10, Col 2, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 5, Col 5, Line 5, Col 13, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 7, Col 5, Line 7, Col 11, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 9, Col 5, Line 9, Col 14, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 12, Col 9, Line 19, Col 2, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 14, Col 5, Line 14, Col 13, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 16, Col 5, Line 16, Col 11, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 18, Col 5, Line 18, Col 14, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 20, Col 9, Line 27, Col 3, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 22, Col 5, Line 22, Col 13, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 24, Col 5, Line 24, Col 11, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 26, Col 5, Line 26, Col 14, "Incomplete expression or invalid use of indexer syntax") + ] + + // SOURCE=SequenceExpressions11.fs # SequenceExpressions11.fs + [] + let ``Preview: SequenceExpressions11 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun |> shouldSucceed \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions10.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions10.fs new file mode 100644 index 00000000000..0434fd0a57b --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions10.fs @@ -0,0 +1,63 @@ +module MixedRangeVersionTest + +let a = seq { + 0 + 1..5 + 10 + 11..15 + 20 + 21..25 +} + +let b = [ + 0 + 1..5 + 10 + 11..15 + 20 + 21..25 +] +let c = [| + 0 + 1..5 + 10 + 11..15 + 20 + 21..25 +|] + +let d = seq { + 0 + yield! [1..5] + 10 + yield! [11..15] + 20 + yield! [21..25] + +} + +let e = [ + 0 + yield! [1..5] + 10 + yield! [11..15] + 20 + yield! [21..25] +] + +let f = [| + 0 + yield! [1..5] + 10 + yield! [11..15] + 20 + yield! [21..25] +|] + +if List.ofSeq a <> List.ofSeq d then failwithf $"a = d failed got {List.ofSeq a}" + +if b <> e then failwithf $"b = e failed got {b}" + +if c <> f then failwithf $"c = f failed got {c}" + +printfn "All sequence tests passed!" \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions11.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions11.fs new file mode 100644 index 00000000000..b85c0e03565 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions11.fs @@ -0,0 +1,63 @@ +module MixedRangeVersionTest + +let a = seq { + 0 + 1..2..10 + 10 + 11..15 + 20 + 21..1..30 +} + +let b = [ + 0 + 1..2..10 + 10 + 11..15 + 20 + 21..1..30 +] +let c = [| + 0 + 1..2..10 + 10 + 11..15 + 20 + 21..1..30 +|] + +let d = seq { + 0 + yield! [1..2..10] + 10 + yield! [11..15] + 20 + yield! [21..1..30] + +} + +let e = [ + 0 + yield! [1..2..10] + 10 + yield! [11..15] + 20 + yield! [21..1..30] +] + +let f = [| + 0 + yield! [1..2..10] + 10 + yield! [11..15] + 20 + yield! [21..1..30] +|] + +if List.ofSeq a <> List.ofSeq d then failwithf $"a = d failed got {List.ofSeq a}" + +if b <> e then failwithf $"b = e failed got {b}" + +if c <> f then failwithf $"c = f failed got {c}" + +printfn "All sequence tests passed!" \ No newline at end of file From a78f4d799e4075967e96fbe02c45656ce4e1130e Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 12 Jun 2025 10:15:45 +0100 Subject: [PATCH 17/39] Update src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs Co-authored-by: Brian Rourke Boll --- .../Expressions/CheckArrayOrListComputedExpressions.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs index 5687b655b5d..62297f81ce9 100644 --- a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs @@ -22,8 +22,8 @@ let private containsRangeExpressions elems = | SynExpr.IndexRange _ -> true | _ -> false) -/// Transform a mixed list/array with ranges into a sequence computation expression -/// E.g., [-3; 1..10; 19] becomes seq { yield -3; yield! 1..10; yield 19 } +/// Adds implicit `yield!` before ranges in a mixed list/array comprehension. +/// E.g., [-3; 1..10; 19] becomes [yield -3; yield! seq { 1..10 }; yield 19] let private transformMixedListWithRangesToSeqExpr elems m = let rec buildBody elems = match elems with From a4f5c16a34f03c39d6d61a878580943aa7135f36 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 12 Jun 2025 10:33:01 +0100 Subject: [PATCH 18/39] Update src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs Co-authored-by: Brian Rourke Boll --- .../CheckArrayOrListComputedExpressions.fs | 51 +++++-------------- 1 file changed, 13 insertions(+), 38 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs index 62297f81ce9..bb3d3a78294 100644 --- a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs @@ -25,45 +25,20 @@ let private containsRangeExpressions elems = /// Adds implicit `yield!` before ranges in a mixed list/array comprehension. /// E.g., [-3; 1..10; 19] becomes [yield -3; yield! seq { 1..10 }; yield 19] let private transformMixedListWithRangesToSeqExpr elems m = - let rec buildBody elems = + let (|RangeExpr|_|) = RewriteRangeExpr + let ``yield!`` rewritten (orig: SynExpr) = SynExpr.YieldOrReturnFrom((true, false), rewritten, orig.Range, { YieldOrReturnFromKeyword = orig.Range }) + let ``yield`` (orig: SynExpr) = SynExpr.YieldOrReturn((true, false), orig, orig.Range, { YieldOrReturnKeyword = orig.Range }) + let ``;`` expr1 expr2 = SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, expr1, expr2, m, SynExprSequentialTrivia.Zero) + + let rec loop elems cont = match elems with - | [] -> SynExpr.Const(SynConst.Unit, m) - | [ elem ] -> - match elem with - | SynExpr.IndexRange _ -> - match RewriteRangeExpr elem with - | Some rewritten -> - SynExpr.YieldOrReturnFrom( - (true, false), - rewritten, - elem.Range, - { - YieldOrReturnFromKeyword = elem.Range - } - ) - | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - | elem :: rest -> - let headExpr = - match elem with - | SynExpr.IndexRange _ -> - match RewriteRangeExpr elem with - | Some rewritten -> - SynExpr.YieldOrReturnFrom( - (true, false), - rewritten, - elem.Range, - { - YieldOrReturnFromKeyword = elem.Range - } - ) - | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - - let tailExpr = buildBody rest - SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, headExpr, tailExpr, m, SynExprSequentialTrivia.Zero) - - buildBody elems + | [] -> cont (SynExpr.Const(SynConst.Unit, m)) + | [elem & RangeExpr rangeExpr] -> cont (``yield!`` rangeExpr elem) + | [elem] -> cont (``yield`` elem) + | (elem & RangeExpr rangeExpr) :: elems -> loop elems (cont << ``;`` (``yield!`` rangeExpr elem)) + | elem :: elems -> loop elems (cont << ``;`` (``yield`` elem)) + + loop elems id let private TcMixedSequencesWithRanges (cenv: TcFileState) env overallTy tpenv isArray elems m = let g = cenv.g From 2b05d761d6f6c2adce346ee5f59c8bf8398c269b Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Thu, 12 Jun 2025 10:41:57 +0100 Subject: [PATCH 19/39] format code --- .../CheckArrayOrListComputedExpressions.fs | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs index bb3d3a78294..fa3c56809d4 100644 --- a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs @@ -15,29 +15,35 @@ open FSharp.Compiler.DiagnosticsLogger open FSharp.Compiler.Syntax open FSharp.Compiler.SyntaxTrivia -/// Check if a list/array expression contains range expressions -let private containsRangeExpressions elems = - elems - |> List.exists (function - | SynExpr.IndexRange _ -> true - | _ -> false) - /// Adds implicit `yield!` before ranges in a mixed list/array comprehension. /// E.g., [-3; 1..10; 19] becomes [yield -3; yield! seq { 1..10 }; yield 19] let private transformMixedListWithRangesToSeqExpr elems m = let (|RangeExpr|_|) = RewriteRangeExpr - let ``yield!`` rewritten (orig: SynExpr) = SynExpr.YieldOrReturnFrom((true, false), rewritten, orig.Range, { YieldOrReturnFromKeyword = orig.Range }) - let ``yield`` (orig: SynExpr) = SynExpr.YieldOrReturn((true, false), orig, orig.Range, { YieldOrReturnKeyword = orig.Range }) - let ``;`` expr1 expr2 = SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, expr1, expr2, m, SynExprSequentialTrivia.Zero) - + + let ``yield!`` rewritten (orig: SynExpr) = + SynExpr.YieldOrReturnFrom( + (true, false), + rewritten, + orig.Range, + { + YieldOrReturnFromKeyword = orig.Range + } + ) + + let ``yield`` (orig: SynExpr) = + SynExpr.YieldOrReturn((true, false), orig, orig.Range, { YieldOrReturnKeyword = orig.Range }) + + let ``;`` expr1 expr2 = + SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, expr1, expr2, m, SynExprSequentialTrivia.Zero) + let rec loop elems cont = match elems with | [] -> cont (SynExpr.Const(SynConst.Unit, m)) - | [elem & RangeExpr rangeExpr] -> cont (``yield!`` rangeExpr elem) - | [elem] -> cont (``yield`` elem) + | [ elem & RangeExpr rangeExpr ] -> cont (``yield!`` rangeExpr elem) + | [ elem ] -> cont (``yield`` elem) | (elem & RangeExpr rangeExpr) :: elems -> loop elems (cont << ``;`` (``yield!`` rangeExpr elem)) | elem :: elems -> loop elems (cont << ``;`` (``yield`` elem)) - + loop elems id let private TcMixedSequencesWithRanges (cenv: TcFileState) env overallTy tpenv isArray elems m = @@ -125,17 +131,23 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT errorR (Deprecated(FSComp.SR.tcExpressionWithIfRequiresParenthesis (), m)) | _ -> () + let containsRangeExpressions = + elems + |> List.exists (function + | SynExpr.IndexRange _ -> true + | _ -> false) + if - containsRangeExpressions elems + containsRangeExpressions && g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions then TcMixedSequencesWithRanges cenv env overallTy tpenv isArray elems m else - if containsRangeExpressions elems then + if containsRangeExpressions then checkLanguageFeatureAndRecover cenv.g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m let replacementExpr = - // This are to improve parsing/processing speed for parser tables by converting to an array blob ASAP + // These are to improve parsing/processing speed for parser tables by converting to an array blob ASAP if isArray then let nelems = elems.Length From 8ceb9f6ff84dfcb9fd83a323fd1308dea5b8b6b7 Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Fri, 13 Jun 2025 14:24:32 +0100 Subject: [PATCH 20/39] containsRangeExpressions first and reuse --- .../CheckComputationExpressions.fs | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index a46ea325c51..44aa6c5a405 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -1563,10 +1563,23 @@ let rec TryTranslateComputationExpression Some(ConsumeCustomOpClauses ceenv comp q varSpace dataCompPriorToOp comp false mClause) | SynExpr.Sequential(sp, true, innerComp1, innerComp2, m, _) -> + let rec containsRangeExpressions expr = + match expr with + | SynExpr.IndexRange _ -> true + | SynExpr.Sequential(_, true, e1, e2, _, _) -> containsRangeExpressions e1 || containsRangeExpressions e2 + | _ -> false + + let containsRangeExpressions = containsRangeExpressions comp + if ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions - && containsRangeExpressions comp + && containsRangeExpressions then + let builderSupportsMixedRanges ceenv m = + hasBuilderMethod "Yield" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m + && hasBuilderMethod "Combine" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m + && hasBuilderMethod "Delay" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m + if builderSupportsMixedRanges ceenv m then let transformed = TransformSequenceWithRanges ceenv comp Some(TranslateComputationExpression ceenv CompExprTranslationPass.Initial q varSpace transformed translatedCtxt) @@ -1574,13 +1587,12 @@ let rec TryTranslateComputationExpression None // Check for 'where x > y' and other mis-applications of infix operators. If detected, give a good error message, and just ignore innerComp1 elif ceenv.isQuery && checkForBinaryApp ceenv innerComp1 then - if containsRangeExpressions comp then - reportRangeExpressionsNotSupported ceenv comp - + // if containsRangeExpressions then + // reportRangeExpressionsNotSupported ceenv comp Some(TranslateComputationExpression ceenv CompExprTranslationPass.Initial q varSpace innerComp2 translatedCtxt) else - if containsRangeExpressions comp then + if containsRangeExpressions then reportRangeExpressionsNotSupported ceenv comp if ceenv.isQuery && not (innerComp1.IsArbExprAndThusAlreadyReportedError) then @@ -2659,13 +2671,6 @@ and isSimpleExpr ceenv comp = | SynExpr.DoBang _ -> false | _ -> true -/// Check if a sequential expression contains range expressions -and containsRangeExpressions expr = - match expr with - | SynExpr.IndexRange _ -> true - | SynExpr.Sequential(_, true, e1, e2, _, _) -> containsRangeExpressions e1 || containsRangeExpressions e2 - | _ -> false - /// Report language feature error for each range expression in a sequence and reportRangeExpressionsNotSupported ceenv expr = match expr with @@ -2682,12 +2687,6 @@ and isSimpleSemicolonSequence ceenv expr = | SynExpr.Sequential(_, true, e1, e2, _, _) -> isSimpleExpr ceenv e1 && isSimpleSemicolonSequence ceenv e2 | e -> isSimpleExpr ceenv e -/// Check if builder supports required methods for mixed ranges -and builderSupportsMixedRanges ceenv m = - hasBuilderMethod "Yield" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m - && hasBuilderMethod "Combine" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m - && hasBuilderMethod "Delay" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m - /// Transform a single expression to Yield or YieldFrom based on whether it's a range and TransformExprToYieldOrYieldFrom ceenv expr = match expr with From 5f947fa9a050697b7223340921d2a2fa889504cb Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Fri, 13 Jun 2025 15:26:43 +0100 Subject: [PATCH 21/39] Move transformMixedListWithRangesToSeqExpr to CheckExpressionsOps --- .../CheckArrayOrListComputedExpressions.fs | 38 ++--------------- .../CheckComputationExpressions.fs | 29 +++++++------ .../Expressions/CheckExpressionsOps.fs | 32 +++++++++++++++ .../Expressions/CheckSequenceExpressions.fs | 41 +------------------ 4 files changed, 50 insertions(+), 90 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs index fa3c56809d4..cd6c7335d26 100644 --- a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs @@ -13,40 +13,8 @@ open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.Features open FSharp.Compiler.DiagnosticsLogger open FSharp.Compiler.Syntax -open FSharp.Compiler.SyntaxTrivia - -/// Adds implicit `yield!` before ranges in a mixed list/array comprehension. -/// E.g., [-3; 1..10; 19] becomes [yield -3; yield! seq { 1..10 }; yield 19] -let private transformMixedListWithRangesToSeqExpr elems m = - let (|RangeExpr|_|) = RewriteRangeExpr - - let ``yield!`` rewritten (orig: SynExpr) = - SynExpr.YieldOrReturnFrom( - (true, false), - rewritten, - orig.Range, - { - YieldOrReturnFromKeyword = orig.Range - } - ) - - let ``yield`` (orig: SynExpr) = - SynExpr.YieldOrReturn((true, false), orig, orig.Range, { YieldOrReturnKeyword = orig.Range }) - - let ``;`` expr1 expr2 = - SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, expr1, expr2, m, SynExprSequentialTrivia.Zero) - - let rec loop elems cont = - match elems with - | [] -> cont (SynExpr.Const(SynConst.Unit, m)) - | [ elem & RangeExpr rangeExpr ] -> cont (``yield!`` rangeExpr elem) - | [ elem ] -> cont (``yield`` elem) - | (elem & RangeExpr rangeExpr) :: elems -> loop elems (cont << ``;`` (``yield!`` rangeExpr elem)) - | elem :: elems -> loop elems (cont << ``;`` (``yield`` elem)) - - loop elems id - -let private TcMixedSequencesWithRanges (cenv: TcFileState) env overallTy tpenv isArray elems m = + +let private tcMixedSequencesWithRanges (cenv: TcFileState) env overallTy tpenv isArray elems m = let g = cenv.g let transformedBody = transformMixedListWithRangesToSeqExpr elems m @@ -141,7 +109,7 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT containsRangeExpressions && g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions then - TcMixedSequencesWithRanges cenv env overallTy tpenv isArray elems m + tcMixedSequencesWithRanges cenv env overallTy tpenv isArray elems m else if containsRangeExpressions then checkLanguageFeatureAndRecover cenv.g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index 44aa6c5a405..717113dff06 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -1581,14 +1581,25 @@ let rec TryTranslateComputationExpression && hasBuilderMethod "Delay" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m if builderSupportsMixedRanges ceenv m then - let transformed = TransformSequenceWithRanges ceenv comp + let rec transformSequenceWithRanges ceenv expr = + match expr with + | SynExpr.Sequential(sp, true, e1, e2, m, trivia) -> + // Transform each part to yield/yieldFrom + let e1Transformed = TransformExprToYieldOrYieldFrom ceenv e1 + let e2Transformed = transformSequenceWithRanges ceenv e2 + // Create a new sequential expression with the transformed parts + SynExpr.Sequential(sp, true, e1Transformed, e2Transformed, m, trivia) + | e -> TransformExprToYieldOrYieldFrom ceenv e + + let transformed = transformSequenceWithRanges ceenv comp Some(TranslateComputationExpression ceenv CompExprTranslationPass.Initial q varSpace transformed translatedCtxt) else None // Check for 'where x > y' and other mis-applications of infix operators. If detected, give a good error message, and just ignore innerComp1 elif ceenv.isQuery && checkForBinaryApp ceenv innerComp1 then - // if containsRangeExpressions then - // reportRangeExpressionsNotSupported ceenv comp + if containsRangeExpressions then + reportRangeExpressionsNotSupported ceenv comp + Some(TranslateComputationExpression ceenv CompExprTranslationPass.Initial q varSpace innerComp2 translatedCtxt) else @@ -2722,18 +2733,6 @@ and TransformExprToYieldOrYieldFrom ceenv expr = SynExpr.YieldOrReturn((true, false), expr, expr.Range, { YieldOrReturnKeyword = expr.Range }) | e -> SynExpr.YieldOrReturn((true, false), e, e.Range, { YieldOrReturnKeyword = e.Range }) -/// Transform a sequential expression with ranges into yields and yieldFroms -and TransformSequenceWithRanges ceenv expr = - match expr with - | SynExpr.Sequential(sp, true, e1, e2, m, trivia) -> - // Transform each part to yield/yieldFrom - let e1Transformed = TransformExprToYieldOrYieldFrom ceenv e1 - let e2Transformed = TransformSequenceWithRanges ceenv e2 - - // Create a new sequential expression with the transformed parts - SynExpr.Sequential(sp, true, e1Transformed, e2Transformed, m, trivia) - | e -> TransformExprToYieldOrYieldFrom ceenv e - and TranslateComputationExpression (ceenv: ComputationExpressionContext<'a>) firstTry q varSpace comp translatedCtxt = ceenv.cenv.stackGuard.Guard diff --git a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs index 7f5ff2f9f64..6f2001f1a44 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs @@ -17,6 +17,7 @@ open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeBasics open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.SyntaxTreeOps +open FSharp.Compiler.SyntaxTrivia let TryAllowFlexibleNullnessInControlFlow isFirst (g: TcGlobals.TcGlobals) ty = match isFirst, g.checkNullness, GetTyparTyIfSupportsNull g ty with @@ -393,3 +394,34 @@ let inline mkOptionalParamTyBasedOnAttribute (g: TcGlobals.TcGlobals) tyarg attr mkValueOptionTy g tyarg else mkOptionTy g tyarg + +/// Adds implicit `yield!` before ranges in a mixed list/array comprehension. +/// E.g., [-3; 1..10; 19] becomes [yield -3; yield! seq { 1..10 }; yield 19] +let transformMixedListWithRangesToSeqExpr elems m = + let (|RangeExpr|_|) = RewriteRangeExpr + + let ``yield!`` rewritten (orig: SynExpr) = + SynExpr.YieldOrReturnFrom( + (true, false), + rewritten, + orig.Range, + { + YieldOrReturnFromKeyword = orig.Range + } + ) + + let ``yield`` (orig: SynExpr) = + SynExpr.YieldOrReturn((true, false), orig, orig.Range, { YieldOrReturnKeyword = orig.Range }) + + let ``;`` expr1 expr2 = + SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, expr1, expr2, m, SynExprSequentialTrivia.Zero) + + let rec loop elems cont = + match elems with + | [] -> cont (SynExpr.Const(SynConst.Unit, m)) + | [ elem & RangeExpr rangeExpr ] -> cont (``yield!`` rangeExpr elem) + | [ elem ] -> cont (``yield`` elem) + | (elem & RangeExpr rangeExpr) :: elems -> loop elems (cont << ``;`` (``yield!`` rangeExpr elem)) + | elem :: elems -> loop elems (cont << ``;`` (``yield`` elem)) + + loop elems id diff --git a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs index 7c85819a2d3..a10fb054cf9 100644 --- a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs @@ -451,46 +451,7 @@ let TcSequenceExpression (cenv: TcFileState) env tpenv comp (overallTy: OverallT delayedExpr, tpenv let private TcMixedSequencesWithRanges cenv env tpenv overallTy elems m = - let rec buildSeqBody elems = - match elems with - | [] -> SynExpr.Const(SynConst.Unit, m) - | [ elem ] -> - match elem with - | SynExpr.IndexRange _ -> - match RewriteRangeExpr elem with - | Some rewrittenRange -> - SynExpr.YieldOrReturnFrom( - (true, false), - rewrittenRange, - elem.Range, - { - YieldOrReturnFromKeyword = elem.Range - } - ) - | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - | elem :: rest -> - let headExpr = - match elem with - | SynExpr.IndexRange _ -> - match RewriteRangeExpr elem with - | Some rewrittenRange -> - SynExpr.YieldOrReturnFrom( - (true, false), - rewrittenRange, - elem.Range, - { - YieldOrReturnFromKeyword = elem.Range - } - ) - | None -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - | _ -> SynExpr.YieldOrReturn((true, false), elem, elem.Range, { YieldOrReturnKeyword = elem.Range }) - - let tailExpr = buildSeqBody rest - - SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, headExpr, tailExpr, m, SynExprSequentialTrivia.Zero) - - let transformedBody = buildSeqBody elems + let transformedBody = transformMixedListWithRangesToSeqExpr elems m TcSequenceExpression cenv env tpenv transformedBody overallTy m let TcSequenceExpressionEntry (cenv: TcFileState) env (overallTy: OverallTy) tpenv (hasBuilder, comp) m = From 17cbb60abbf393d08ebca4813328eb1e7682e952 Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Fri, 13 Jun 2025 18:20:43 +0100 Subject: [PATCH 22/39] update baselines --- tests/fsharp/typecheck/sigs/version46/neg24.bsl | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/fsharp/typecheck/sigs/version46/neg24.bsl b/tests/fsharp/typecheck/sigs/version46/neg24.bsl index 97aa11a5d26..eec18e70ccd 100644 --- a/tests/fsharp/typecheck/sigs/version46/neg24.bsl +++ b/tests/fsharp/typecheck/sigs/version46/neg24.bsl @@ -13,8 +13,6 @@ neg24.fs(16,14,16,35): typecheck error FS0035: This construct is deprecated: Thi neg24.fs(17,18,17,45): typecheck error FS0739: Invalid object, sequence or record expression -neg24.fs(17,20,17,43): typecheck error FS0793: This construct is ambiguous as part of a sequence expression. Nested expressions may be written using 'let _ = (...)' and nested sequences using 'yield! seq {... }'. - neg24.fs(53,24,53,30): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form. neg24.fs(55,31,55,37): typecheck error FS0816: One or more of the overloads of this method has curried arguments. Consider redesigning these members to take arguments in tupled form. From aac9a697b0202ea9727f16e36ad30ef3b8854256 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Fri, 13 Jun 2025 21:12:41 +0100 Subject: [PATCH 23/39] Update src/Compiler/Checking/Expressions/CheckExpressionsOps.fs Co-authored-by: Brian Rourke Boll --- src/Compiler/Checking/Expressions/CheckExpressionsOps.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs index 6f2001f1a44..826b416eff5 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs @@ -397,7 +397,7 @@ let inline mkOptionalParamTyBasedOnAttribute (g: TcGlobals.TcGlobals) tyarg attr /// Adds implicit `yield!` before ranges in a mixed list/array comprehension. /// E.g., [-3; 1..10; 19] becomes [yield -3; yield! seq { 1..10 }; yield 19] -let transformMixedListWithRangesToSeqExpr elems m = +let insertImplicitYieldsAndYieldBangs elems m = let (|RangeExpr|_|) = RewriteRangeExpr let ``yield!`` rewritten (orig: SynExpr) = From 4053f405769abf0f66682306e354591e88dabb7c Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Fri, 13 Jun 2025 21:13:03 +0100 Subject: [PATCH 24/39] Update src/Compiler/Checking/Expressions/CheckComputationExpressions.fs Co-authored-by: Brian Rourke Boll --- .../CheckComputationExpressions.fs | 49 +++++++------------ 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index 717113dff06..afadd99438f 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -2700,38 +2700,23 @@ and isSimpleSemicolonSequence ceenv expr = /// Transform a single expression to Yield or YieldFrom based on whether it's a range and TransformExprToYieldOrYieldFrom ceenv expr = - match expr with - | SynExpr.IndexRange _ -> - match RewriteRangeExpr expr with - | Some rewrittenRange -> - // Check if YieldFrom is available - match - TryFindIntrinsicOrExtensionMethInfo - ResultCollectionSettings.AllResults - ceenv.cenv - ceenv.env - expr.Range - ceenv.ad - "YieldFrom" - ceenv.builderTy - with - | [] -> - // No YieldFrom, use Yield - // Create a YieldOrReturn expression and let the CE machinery handle it - SynExpr.YieldOrReturn((true, false), rewrittenRange, expr.Range, { YieldOrReturnKeyword = expr.Range }) - | _ -> - SynExpr.YieldOrReturnFrom( - (true, false), - rewrittenRange, - expr.Range, - { - YieldOrReturnFromKeyword = expr.Range - } - ) - | None -> - // If we can't rewrite range, yield the expression - SynExpr.YieldOrReturn((true, false), expr, expr.Range, { YieldOrReturnKeyword = expr.Range }) - | e -> SynExpr.YieldOrReturn((true, false), e, e.Range, { YieldOrReturnKeyword = e.Range }) + let m = expr.Range + + let ``yield!`` rewrittenRange = + SynExpr.YieldOrReturnFrom((true, false), rewrittenRange, m, { YieldOrReturnFromKeyword = m }) + + let ``yield`` rewrittenRange = + SynExpr.YieldOrReturn((true, false), rewrittenRange, m, { YieldOrReturnKeyword = m }) + + // If there is no YieldFrom defined on the builder, use Yield; + // create a YieldOrReturn expression and let the CE machinery handle it. + match RewriteRangeExpr expr with + | Some rewrittenRange -> + if hasBuilderMethod "YieldFrom" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m then + ``yield!`` rewrittenRange + else + ``yield`` rewrittenRange + | None -> ``yield`` expr and TranslateComputationExpression (ceenv: ComputationExpressionContext<'a>) firstTry q varSpace comp translatedCtxt = From 461fc3fdccff9df404dc93fb7089a9af2d8350a6 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Fri, 13 Jun 2025 21:13:16 +0100 Subject: [PATCH 25/39] Update src/Compiler/Checking/Expressions/CheckComputationExpressions.fs Co-authored-by: Brian Rourke Boll --- .../CheckComputationExpressions.fs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index afadd99438f..04a00e5f528 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -1581,15 +1581,17 @@ let rec TryTranslateComputationExpression && hasBuilderMethod "Delay" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m if builderSupportsMixedRanges ceenv m then - let rec transformSequenceWithRanges ceenv expr = - match expr with - | SynExpr.Sequential(sp, true, e1, e2, m, trivia) -> - // Transform each part to yield/yieldFrom - let e1Transformed = TransformExprToYieldOrYieldFrom ceenv e1 - let e2Transformed = transformSequenceWithRanges ceenv e2 - // Create a new sequential expression with the transformed parts - SynExpr.Sequential(sp, true, e1Transformed, e2Transformed, m, trivia) - | e -> TransformExprToYieldOrYieldFrom ceenv e + let transformSequenceWithRanges ceenv expr = + let rec loop expr cont = + match expr with + | SynExpr.Sequential(sp, true, e1, e2, m, trivia) -> + // Transform each part to yield/yieldFrom + let e1Transformed = TransformExprToYieldOrYieldFrom ceenv e1 + // Create a new sequential expression with the transformed parts + loop e2 (cont << fun e2Transformed -> SynExpr.Sequential(sp, true, e1Transformed, e2Transformed, m, trivia)) + | e -> cont (TransformExprToYieldOrYieldFrom ceenv e) + + loop expr id let transformed = transformSequenceWithRanges ceenv comp Some(TranslateComputationExpression ceenv CompExprTranslationPass.Initial q varSpace transformed translatedCtxt) From 4de39c7f9fc776684bd4ba95888a33091c1d336f Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Fri, 13 Jun 2025 21:13:26 +0100 Subject: [PATCH 26/39] Update src/Compiler/Checking/Expressions/CheckComputationExpressions.fs Co-authored-by: Brian Rourke Boll --- .../Expressions/CheckComputationExpressions.fs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index 04a00e5f528..9709ad2b0f4 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -1563,11 +1563,14 @@ let rec TryTranslateComputationExpression Some(ConsumeCustomOpClauses ceenv comp q varSpace dataCompPriorToOp comp false mClause) | SynExpr.Sequential(sp, true, innerComp1, innerComp2, m, _) -> - let rec containsRangeExpressions expr = - match expr with - | SynExpr.IndexRange _ -> true - | SynExpr.Sequential(_, true, e1, e2, _, _) -> containsRangeExpressions e1 || containsRangeExpressions e2 - | _ -> false + let containsRangeExpressions expr = + let rec loop exprs = + match exprs with + | SynExpr.IndexRange _ :: _ -> true + | SynExpr.Sequential(_, true, e1, e2, _, _) :: exprs -> loop (e1 :: e2 :: exprs) + | _ -> false + + loop [ expr ] let containsRangeExpressions = containsRangeExpressions comp From a2dc4eec49a15f1224c2cc30b552f7f533291de3 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Fri, 13 Jun 2025 21:13:41 +0100 Subject: [PATCH 27/39] Update src/Compiler/Checking/Expressions/CheckComputationExpressions.fs Co-authored-by: Brian Rourke Boll --- .../Checking/Expressions/CheckComputationExpressions.fs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index 9709ad2b0f4..93a22a03604 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -2697,12 +2697,6 @@ and reportRangeExpressionsNotSupported ceenv expr = reportRangeExpressionsNotSupported ceenv e2 | _ -> () -/// Check if this is a simple semicolon sequence (potentially with ranges) -and isSimpleSemicolonSequence ceenv expr = - match expr with - | SynExpr.Sequential(_, true, e1, e2, _, _) -> isSimpleExpr ceenv e1 && isSimpleSemicolonSequence ceenv e2 - | e -> isSimpleExpr ceenv e - /// Transform a single expression to Yield or YieldFrom based on whether it's a range and TransformExprToYieldOrYieldFrom ceenv expr = let m = expr.Range From bc8a8f1b49adb2f975022261042d2eed5ef47e1a Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Fri, 13 Jun 2025 21:21:54 +0100 Subject: [PATCH 28/39] make things tail-recursive --- .../CheckArrayOrListComputedExpressions.fs | 2 +- .../CheckComputationExpressions.fs | 36 +++++++++++-------- .../Expressions/CheckSequenceExpressions.fs | 2 +- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs index cd6c7335d26..07f5d1de16b 100644 --- a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs @@ -16,7 +16,7 @@ open FSharp.Compiler.Syntax let private tcMixedSequencesWithRanges (cenv: TcFileState) env overallTy tpenv isArray elems m = let g = cenv.g - let transformedBody = transformMixedListWithRangesToSeqExpr elems m + let transformedBody = insertImplicitYieldsAndYieldBangs elems m let genCollElemTy = NewInferenceType g let genCollTy = (if isArray then mkArrayType else mkListTy) g genCollElemTy diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index 93a22a03604..3ad9741aae8 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -1574,6 +1574,19 @@ let rec TryTranslateComputationExpression let containsRangeExpressions = containsRangeExpressions comp + /// Report language feature error for each range expression in a sequence + let reportRangeExpressionsNotSupported ceenv expr = + let rec loop exprs = + match exprs with + | [] -> () + | SynExpr.IndexRange(_, _, _, _, _, m) :: exprs -> + checkLanguageFeatureAndRecover ceenv.cenv.g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m + loop exprs + | SynExpr.Sequential(_, true, e1, e2, _, _) :: exprs -> loop (e1 :: e2 :: exprs) + | _ :: exprs -> loop exprs + + loop [ expr ] + if ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions && containsRangeExpressions @@ -1591,9 +1604,12 @@ let rec TryTranslateComputationExpression // Transform each part to yield/yieldFrom let e1Transformed = TransformExprToYieldOrYieldFrom ceenv e1 // Create a new sequential expression with the transformed parts - loop e2 (cont << fun e2Transformed -> SynExpr.Sequential(sp, true, e1Transformed, e2Transformed, m, trivia)) + loop + e2 + (cont + << fun e2Transformed -> SynExpr.Sequential(sp, true, e1Transformed, e2Transformed, m, trivia)) | e -> cont (TransformExprToYieldOrYieldFrom ceenv e) - + loop expr id let transformed = transformSequenceWithRanges ceenv comp @@ -2687,26 +2703,16 @@ and isSimpleExpr ceenv comp = | SynExpr.DoBang _ -> false | _ -> true -/// Report language feature error for each range expression in a sequence -and reportRangeExpressionsNotSupported ceenv expr = - match expr with - | SynExpr.IndexRange(_, _, _, _, _, m) -> - checkLanguageFeatureAndRecover ceenv.cenv.g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m - | SynExpr.Sequential(_, true, e1, e2, _, _) -> - reportRangeExpressionsNotSupported ceenv e1 - reportRangeExpressionsNotSupported ceenv e2 - | _ -> () - /// Transform a single expression to Yield or YieldFrom based on whether it's a range and TransformExprToYieldOrYieldFrom ceenv expr = let m = expr.Range - + let ``yield!`` rewrittenRange = SynExpr.YieldOrReturnFrom((true, false), rewrittenRange, m, { YieldOrReturnFromKeyword = m }) - + let ``yield`` rewrittenRange = SynExpr.YieldOrReturn((true, false), rewrittenRange, m, { YieldOrReturnKeyword = m }) - + // If there is no YieldFrom defined on the builder, use Yield; // create a YieldOrReturn expression and let the CE machinery handle it. match RewriteRangeExpr expr with diff --git a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs index a10fb054cf9..d8c8bf860c2 100644 --- a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs @@ -451,7 +451,7 @@ let TcSequenceExpression (cenv: TcFileState) env tpenv comp (overallTy: OverallT delayedExpr, tpenv let private TcMixedSequencesWithRanges cenv env tpenv overallTy elems m = - let transformedBody = transformMixedListWithRangesToSeqExpr elems m + let transformedBody = insertImplicitYieldsAndYieldBangs elems m TcSequenceExpression cenv env tpenv transformedBody overallTy m let TcSequenceExpressionEntry (cenv: TcFileState) env (overallTy: OverallTy) tpenv (hasBuilder, comp) m = From ba9f733ff3db5117e6484c7b21b369842bd2c907 Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Sat, 14 Jun 2025 00:22:31 +0100 Subject: [PATCH 29/39] yield! 1..10 --- .../CheckArrayOrListComputedExpressions.fs | 43 +++++++++++++++++ .../CheckComputationExpressions.fs | 20 ++++++++ .../Expressions/CheckExpressionsOps.fs | 36 +++++++++++++++ .../Expressions/CheckSequenceExpressions.fs | 21 +++++++++ .../MixedSequenceExpressionTests.fs | 46 +++++++++++++++++++ .../SequenceExpressions12.fs | 17 +++++++ .../SequenceExpressions13.fs | 17 +++++++ 7 files changed, 200 insertions(+) create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions12.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions13.fs diff --git a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs index cd6c7335d26..6b717ba2dcc 100644 --- a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs @@ -173,6 +173,49 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT TcExprUndelayed cenv overallTy env tpenv replacementExpr | _ -> + let containsExplicitYields = + let rec hasYieldBang expr cont = + match expr with + | SynExpr.YieldOrReturnFrom _ -> cont true + | SynExpr.Sequential(_, _, e1, e2, _, _) -> + hasYieldBang e1 (fun e1Has -> if e1Has then cont true else hasYieldBang e2 cont) + | _ -> cont false + + hasYieldBang comp id + + // Transform mixed expressions with explicit yields to ensure all elements are properly yielded + let comp = + if + containsExplicitYields + && g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions + then + match comp with + | SynExpr.Sequential _ -> + // Extract the elements from the sequential expression + let rec getElems expr acc = + match expr with + | SynExpr.Sequential(_, true, e1, e2, _, _) -> getElems e2 (e1 :: acc) + | e -> List.rev (e :: acc) + + let elems = getElems comp [] + transformMixedListWithExplicitYields elems m + | _ -> comp + else if containsExplicitYields then + // Check if any element is a range expression (tail recursive) + let rec hasRangeInMixedYield expr cont = + match expr with + | SynExpr.IndexRange _ -> cont true + | SynExpr.Sequential(_, _, e1, e2, _, _) -> + hasRangeInMixedYield e1 (fun e1Has -> if e1Has then cont true else hasRangeInMixedYield e2 cont) + | _ -> cont false + + if hasRangeInMixedYield comp id then + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m + + comp + else + comp + let genCollElemTy = NewInferenceType g let genCollTy = (if isArray then mkArrayType else mkListTy) cenv.g genCollElemTy diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index 717113dff06..cab7eead90f 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -2247,6 +2247,26 @@ let rec TryTranslateComputationExpression Some(translatedCtxt callExpr) | SynExpr.YieldOrReturnFrom((true, _), synYieldExpr, _, { YieldOrReturnFromKeyword = m }) -> + let isRangeExpr = + match synYieldExpr with + | SynExpr.IndexRange _ -> true + | _ -> false + + if + isRangeExpr + && not (ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions) + then + checkLanguageFeatureAndRecover + ceenv.cenv.g.langVersion + LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions + synYieldExpr.Range + + // Rewrite range expressions in yield! to their sequence form + let synYieldExpr = + match RewriteRangeExpr synYieldExpr with + | Some rewrittenExpr -> rewrittenExpr + | None -> synYieldExpr + let yieldFromExpr = mkSourceExpr synYieldExpr ceenv.sourceMethInfo ceenv.builderValName diff --git a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs index 6f2001f1a44..2839317a33a 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs @@ -425,3 +425,39 @@ let transformMixedListWithRangesToSeqExpr elems m = | elem :: elems -> loop elems (cont << ``;`` (``yield`` elem)) loop elems id + +/// Transforms mixed lists/arrays that contain explicit yield! expressions. +/// E.g., [1..10; 19; yield! 20..30] becomes [yield! 1..10; yield 19; yield! 20..30] +let transformMixedListWithExplicitYields elems m = + let (|RangeExpr|_|) = RewriteRangeExpr + + let ``yield!`` rewritten (orig: SynExpr) = + SynExpr.YieldOrReturnFrom( + (true, false), + rewritten, + orig.Range, + { + YieldOrReturnFromKeyword = orig.Range + } + ) + + let ``yield`` (orig: SynExpr) = + SynExpr.YieldOrReturn((true, false), orig, orig.Range, { YieldOrReturnKeyword = orig.Range }) + + let ``;`` expr1 expr2 = + SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, expr1, expr2, m, SynExprSequentialTrivia.Zero) + + let rec transformExpr expr cont = + match expr with + | RangeExpr rangeExpr -> cont (``yield!`` rangeExpr expr) + | SynExpr.YieldOrReturnFrom _ -> cont expr + | SynExpr.YieldOrReturn _ -> cont expr + | _ -> cont (``yield`` expr) + + let rec loop elems cont = + match elems with + | [] -> cont (SynExpr.Const(SynConst.Unit, m)) + | [ elem ] -> transformExpr elem cont + | elem :: elems -> transformExpr elem (fun transformedElem -> loop elems (fun restExpr -> cont (``;`` transformedElem restExpr))) + + loop elems id diff --git a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs index a10fb054cf9..1b99f0ddfb3 100644 --- a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs @@ -364,6 +364,27 @@ let TcSequenceExpression (cenv: TcFileState) env tpenv comp (overallTy: OverallT | SynExpr.YieldOrReturnFrom(flags = (isYield, _); expr = synYieldExpr; trivia = { YieldOrReturnFromKeyword = m }) -> let env = { env with eIsControlFlow = false } + + let isRangeExpr = + match synYieldExpr with + | SynExpr.IndexRange _ -> true + | _ -> false + + if + isRangeExpr + && not (cenv.g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions) + then + checkLanguageFeatureAndRecover + cenv.g.langVersion + LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions + synYieldExpr.Range + + // Rewrite range expressions in yield! to their sequence form + let synYieldExpr = + match RewriteRangeExpr synYieldExpr with + | Some rewrittenExpr -> rewrittenExpr + | None -> synYieldExpr + let resultExpr, genExprTy, tpenv = TcExprOfUnknownType cenv env tpenv synYieldExpr if not isYield then diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs index 47c8629ddd9..91572b5459a 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs @@ -315,6 +315,52 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions11.fs # SequenceExpressions11.fs [] let ``Preview: SequenceExpressions11 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions12.fs # SequenceExpressions12.fs + [] + let ``Version 9: SequenceExpressions12 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 18, Line 3, Col 23, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + ] + + // SOURCE=SequenceExpressions12.fs # SequenceExpressions12.fs + [] + let ``Preview: SequenceExpressions12 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions13.fs # SequenceExpressions13.fs + [] + let ``Version 9: SequenceExpressions13 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 18, Line 3, Col 23, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 5, Col 38, Line 5, Col 44, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 9, Col 9, Line 9, Col 37, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 9, Col 11, Line 9, Col 16, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 9, Col 29, Line 9, Col 35, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 10, Col 22, Line 10, Col 27, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 10, Col 40, Line 10, Col 46, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 11, Col 19, Line 11, Col 24, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 11, Col 37, Line 11, Col 43, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + ] + + // SOURCE=SequenceExpressions13.fs # SequenceExpressions13.fs + [] + let ``Preview: SequenceExpressions13 fs`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions12.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions12.fs new file mode 100644 index 00000000000..a3c010c5fbe --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions12.fs @@ -0,0 +1,17 @@ +module MixedRangeVersionTest + +let a = [ yield! 1..10 ] + +let b = [ yield! [1..10] ] + +let c = seq { yield! seq { 1..10 } } + +let d = [ 1..10 ] +let e = seq { 1..10 } +let f = [| 1..10 |] + +if a <> d then failwithf $"a = d failed got {a}" +if b <> List.ofSeq e then failwithf $"b = d failed got {b}" +if Array.ofSeq c <> f then failwithf $"f = d failed got {f}" + +printfn "All sequence tests passed!" \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions13.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions13.fs new file mode 100644 index 00000000000..e7e713f8a9c --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions13.fs @@ -0,0 +1,17 @@ +module MixedRangeVersionTest + +let a = [ yield! 1..10; 19; yield! [20..30] ] + +let b = [ yield! [1..10]; 19; yield! 20..30 ] + +let c = seq { yield! seq { 1..10 }; 19; yield! seq { 20..30 } } + +let d = [ 1..10; 19; yield! 20..30 ] +let e = seq { yield! 1..10; 19; yield! 20..30 } +let f = [| yield! 1..10; 19; yield! 20..30 |] + +if a <> d then failwithf $"a = d failed got {a}" +if b <> List.ofSeq e then failwithf $"b = d failed got {b}" +if Array.ofSeq c <> f then failwithf $"f = d failed got {f}" + +printfn "All sequence tests passed!" \ No newline at end of file From 79b2e669ae3f211179881976c42c42e33fea5ae8 Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Sat, 14 Jun 2025 00:55:47 +0100 Subject: [PATCH 30/39] yield! 1..10 --- .../CheckArrayOrListComputedExpressions.fs | 34 +++++++------------ .../CheckComputationExpressions.fs | 9 +++-- .../Expressions/CheckExpressionsOps.fs | 17 ++++++++++ .../Expressions/CheckSequenceExpressions.fs | 9 +++-- .../MixedSequenceExpressionTests.fs | 16 +++++++++ .../SequenceExpressions14.fs | 16 +++++++++ 6 files changed, 74 insertions(+), 27 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions14.fs diff --git a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs index 6c50bc7af94..6670431882a 100644 --- a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs @@ -173,20 +173,22 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT TcExprUndelayed cenv overallTy env tpenv replacementExpr | _ -> - let containsExplicitYields = - let rec hasYieldBang expr cont = + let containsRangeMixedWithYields = + let rec hasRangeAndYield expr hasRange hasYield cont = match expr with - | SynExpr.YieldOrReturnFrom _ -> cont true + | SynExpr.IndexRange _ -> cont true hasYield + | SynExpr.YieldOrReturnFrom _ -> cont hasRange true | SynExpr.Sequential(_, _, e1, e2, _, _) -> - hasYieldBang e1 (fun e1Has -> if e1Has then cont true else hasYieldBang e2 cont) - | _ -> cont false - - hasYieldBang comp id - + hasRangeAndYield e1 hasRange hasYield (fun r1 y1 -> + hasRangeAndYield e2 r1 y1 cont) + | _ -> cont hasRange hasYield + + hasRangeAndYield comp false false (fun r y -> r && y) + // Transform mixed expressions with explicit yields to ensure all elements are properly yielded let comp = if - containsExplicitYields + containsRangeMixedWithYields && g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions then match comp with @@ -200,18 +202,8 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT let elems = getElems comp [] transformMixedListWithExplicitYields elems m | _ -> comp - else if containsExplicitYields then - // Check if any element is a range expression (tail recursive) - let rec hasRangeInMixedYield expr cont = - match expr with - | SynExpr.IndexRange _ -> cont true - | SynExpr.Sequential(_, _, e1, e2, _, _) -> - hasRangeInMixedYield e1 (fun e1Has -> if e1Has then cont true else hasRangeInMixedYield e2 cont) - | _ -> cont false - - if hasRangeInMixedYield comp id then - checkLanguageFeatureAndRecover g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m - + else if containsRangeMixedWithYields then + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m comp else comp diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index b90cd9ec97d..dc85f54a09f 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -2284,9 +2284,12 @@ let rec TryTranslateComputationExpression // Rewrite range expressions in yield! to their sequence form let synYieldExpr = - match RewriteRangeExpr synYieldExpr with - | Some rewrittenExpr -> rewrittenExpr - | None -> synYieldExpr + if isRangeExpr then + match RewriteRangeExpr synYieldExpr with + | Some rewrittenExpr -> rewrittenExpr + | None -> synYieldExpr + else + synYieldExpr let yieldFromExpr = mkSourceExpr synYieldExpr ceenv.sourceMethInfo ceenv.builderValName diff --git a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs index 59deefc09d5..a3fb06ea2e9 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs @@ -452,6 +452,23 @@ let transformMixedListWithExplicitYields elems m = | RangeExpr rangeExpr -> cont (``yield!`` rangeExpr expr) | SynExpr.YieldOrReturnFrom _ -> cont expr | SynExpr.YieldOrReturn _ -> cont expr + | SynExpr.IfThenElse(ifExpr, thenExpr, elseExprOpt, spIfToThen, isFromErrorRecovery, range, trivia) -> + transformExpr thenExpr (fun transformedThen -> + match elseExprOpt with + | Some elseExpr -> + transformExpr elseExpr (fun transformedElse -> + cont ( + SynExpr.IfThenElse( + ifExpr, + transformedThen, + Some transformedElse, + spIfToThen, + isFromErrorRecovery, + range, + trivia + ) + )) + | None -> cont (SynExpr.IfThenElse(ifExpr, transformedThen, None, spIfToThen, isFromErrorRecovery, range, trivia))) | _ -> cont (``yield`` expr) let rec loop elems cont = diff --git a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs index 9fed9f70f66..94ebca31240 100644 --- a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs @@ -381,9 +381,12 @@ let TcSequenceExpression (cenv: TcFileState) env tpenv comp (overallTy: OverallT // Rewrite range expressions in yield! to their sequence form let synYieldExpr = - match RewriteRangeExpr synYieldExpr with - | Some rewrittenExpr -> rewrittenExpr - | None -> synYieldExpr + if isRangeExpr then + match RewriteRangeExpr synYieldExpr with + | Some rewrittenExpr -> rewrittenExpr + | None -> synYieldExpr + else + synYieldExpr let resultExpr, genExprTy, tpenv = TcExprOfUnknownType cenv env tpenv synYieldExpr diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs index 91572b5459a..258d7ec26c2 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs @@ -361,6 +361,22 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions13.fs # SequenceExpressions13.fs [] let ``Preview: SequenceExpressions13 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions14.fs # SequenceExpressions14.fs + [] + let ``Version 9: SequenceExpressions14 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions13.fs # SequenceExpressions13.fs + [] + let ``Preview: SequenceExpressions14 fs`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions14.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions14.fs new file mode 100644 index 00000000000..2995b7d4fbd --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions14.fs @@ -0,0 +1,16 @@ +module BackwardCompatTest + +let makeCustomAttributes() = + [| + if true then + yield "attr1" + yield! ["attr2"; "attr3"] + yield! ["attr4"] + |] + +let attrs = makeCustomAttributes() +let expected = [|"attr1"; "attr2"; "attr3"; "attr4"|] + +if attrs <> expected then failwithf $"attrs failed: got {attrs}" + +printfn "Backward compatibility test passed!" \ No newline at end of file From d8816867184dcbac4f40c4ac2b8acf78f342d5d4 Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Sat, 14 Jun 2025 15:33:55 +0100 Subject: [PATCH 31/39] format --- .../Expressions/CheckArrayOrListComputedExpressions.fs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs index 6670431882a..cdf8fae28a1 100644 --- a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs @@ -179,12 +179,11 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT | SynExpr.IndexRange _ -> cont true hasYield | SynExpr.YieldOrReturnFrom _ -> cont hasRange true | SynExpr.Sequential(_, _, e1, e2, _, _) -> - hasRangeAndYield e1 hasRange hasYield (fun r1 y1 -> - hasRangeAndYield e2 r1 y1 cont) + hasRangeAndYield e1 hasRange hasYield (fun r1 y1 -> hasRangeAndYield e2 r1 y1 cont) | _ -> cont hasRange hasYield - + hasRangeAndYield comp false false (fun r y -> r && y) - + // Transform mixed expressions with explicit yields to ensure all elements are properly yielded let comp = if From 43babe79b47bdd573be88b05abcd912f8ec8cc59 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Sat, 14 Jun 2025 22:17:42 +0100 Subject: [PATCH 32/39] Update src/Compiler/Checking/Expressions/CheckExpressionsOps.fs Co-authored-by: Brian Rourke Boll --- .../CheckArrayOrListComputedExpressions.fs | 2 +- .../Expressions/CheckExpressionsOps.fs | 106 +++++++++--------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs index cdf8fae28a1..81f55e2a2c5 100644 --- a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs @@ -199,7 +199,7 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT | e -> List.rev (e :: acc) let elems = getElems comp [] - transformMixedListWithExplicitYields elems m + insertImplicitYieldsAndYieldBangs elems m | _ -> comp else if containsRangeMixedWithYields then checkLanguageFeatureAndRecover g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m diff --git a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs index a3fb06ea2e9..b14ad1aaca6 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs @@ -395,11 +395,17 @@ let inline mkOptionalParamTyBasedOnAttribute (g: TcGlobals.TcGlobals) tyarg attr else mkOptionTy g tyarg -/// Adds implicit `yield!` before ranges in a mixed list/array comprehension. -/// E.g., [-3; 1..10; 19] becomes [yield -3; yield! seq { 1..10 }; yield 19] +/// Adds implicit `yield!` before ranges in a mixed list/array/seq comprehension if necessary. +/// E.g., [-3; 1..10; 19] becomes [yield -3; yield! (..) 1 10; yield 19] let insertImplicitYieldsAndYieldBangs elems m = let (|RangeExpr|_|) = RewriteRangeExpr + let (|IfThenElseExpr|_|) expr = + match expr with + | SynExpr.IfThenElse(ifExpr, thenExpr, elseExpr, spIfToThen, isFromErrorRecovery, range, trivia) -> + ValueSome(thenExpr, elseExpr, (ifExpr, spIfToThen, isFromErrorRecovery, range, trivia)) + | _ -> ValueNone + let ``yield!`` rewritten (orig: SynExpr) = SynExpr.YieldOrReturnFrom( (true, false), @@ -413,68 +419,62 @@ let insertImplicitYieldsAndYieldBangs elems m = let ``yield`` (orig: SynExpr) = SynExpr.YieldOrReturn((true, false), orig, orig.Range, { YieldOrReturnKeyword = orig.Range }) + let ``if then`` (ifExpr, spIfToThen, isFromErrorRecovery, m, trivia) thenExpr = + SynExpr.IfThenElse(ifExpr, thenExpr, None, spIfToThen, isFromErrorRecovery, m, trivia) + + let ``if then else`` (ifExpr, spIfToThen, isFromErrorRecovery, m, trivia) thenExpr elseExpr = + SynExpr.IfThenElse(ifExpr, thenExpr, Some elseExpr, spIfToThen, isFromErrorRecovery, m, trivia) + + let ``match`` (dbg, expr, m, trivia) clauses = + SynExpr.Match(dbg, expr, clauses, m, trivia) + + let ``match!`` (dbg, expr, m, trivia) clauses = + SynExpr.MatchBang(dbg, expr, clauses, m, trivia) + let ``;`` expr1 expr2 = SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, expr1, expr2, m, SynExprSequentialTrivia.Zero) - let rec loop elems cont = + let rec loopElems elems cont = match elems with | [] -> cont (SynExpr.Const(SynConst.Unit, m)) + | [ elem & RangeExpr rangeExpr ] -> cont (``yield!`` rangeExpr elem) + + | [ elem & SynExpr.YieldOrReturn _ ] + | [ elem & SynExpr.YieldOrReturnFrom _ ] -> cont elem + + | [ IfThenElseExpr(thenExpr, None, info) ] -> loopElems [ thenExpr ] (cont << ``if then`` info) + | [ IfThenElseExpr(thenExpr, Some elseExpr, info) ] -> + loopElems [ thenExpr ] (fun thenExpr -> loopElems [ elseExpr ] (cont << ``if then else`` info thenExpr)) + + | [ SynExpr.Match(dbg, expr, clauses, m, trivia) ] -> loopMatchClauses [] clauses (cont << ``match`` (dbg, expr, m, trivia)) + | [ SynExpr.MatchBang(dbg, expr, clauses, m, trivia) ] -> loopMatchClauses [] clauses (cont << ``match!`` (dbg, expr, m, trivia)) + | [ elem ] -> cont (``yield`` elem) - | (elem & RangeExpr rangeExpr) :: elems -> loop elems (cont << ``;`` (``yield!`` rangeExpr elem)) - | elem :: elems -> loop elems (cont << ``;`` (``yield`` elem)) - loop elems id + | (elem & RangeExpr rangeExpr) :: elems -> loopElems elems (cont << ``;`` (``yield!`` rangeExpr elem)) -/// Transforms mixed lists/arrays that contain explicit yield! expressions. -/// E.g., [1..10; 19; yield! 20..30] becomes [yield! 1..10; yield 19; yield! 20..30] -let transformMixedListWithExplicitYields elems m = - let (|RangeExpr|_|) = RewriteRangeExpr + | (elem & SynExpr.YieldOrReturn _) :: elems + | (elem & SynExpr.YieldOrReturnFrom _) :: elems -> loopElems elems (cont << ``;`` elem) - let ``yield!`` rewritten (orig: SynExpr) = - SynExpr.YieldOrReturnFrom( - (true, false), - rewritten, - orig.Range, - { - YieldOrReturnFromKeyword = orig.Range - } - ) + | IfThenElseExpr(thenExpr, None, info) :: elems -> + loopElems [ thenExpr ] (fun thenExpr -> loopElems elems (cont << ``;`` (``if then`` info thenExpr))) + | IfThenElseExpr(thenExpr, Some elseExpr, info) :: elems -> + loopElems [ thenExpr ] (fun thenExpr -> + loopElems [ elseExpr ] (fun elseExpr -> loopElems elems (cont << ``;`` (``if then else`` info thenExpr elseExpr)))) - let ``yield`` (orig: SynExpr) = - SynExpr.YieldOrReturn((true, false), orig, orig.Range, { YieldOrReturnKeyword = orig.Range }) + | SynExpr.Match(dbg, expr, clauses, m, trivia) :: elems -> + loopMatchClauses [] clauses (fun clauses -> loopElems elems (cont << ``;`` (``match`` (dbg, expr, m, trivia) clauses))) + | SynExpr.MatchBang(dbg, expr, clauses, m, trivia) :: elems -> + loopMatchClauses [] clauses (fun clauses -> loopElems elems (cont << ``;`` (``match!`` (dbg, expr, m, trivia) clauses))) - let ``;`` expr1 expr2 = - SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, expr1, expr2, m, SynExprSequentialTrivia.Zero) + | elem :: elems -> loopElems elems (cont << ``;`` (``yield`` elem)) - let rec transformExpr expr cont = - match expr with - | RangeExpr rangeExpr -> cont (``yield!`` rangeExpr expr) - | SynExpr.YieldOrReturnFrom _ -> cont expr - | SynExpr.YieldOrReturn _ -> cont expr - | SynExpr.IfThenElse(ifExpr, thenExpr, elseExprOpt, spIfToThen, isFromErrorRecovery, range, trivia) -> - transformExpr thenExpr (fun transformedThen -> - match elseExprOpt with - | Some elseExpr -> - transformExpr elseExpr (fun transformedElse -> - cont ( - SynExpr.IfThenElse( - ifExpr, - transformedThen, - Some transformedElse, - spIfToThen, - isFromErrorRecovery, - range, - trivia - ) - )) - | None -> cont (SynExpr.IfThenElse(ifExpr, transformedThen, None, spIfToThen, isFromErrorRecovery, range, trivia))) - | _ -> cont (``yield`` expr) - - let rec loop elems cont = - match elems with - | [] -> cont (SynExpr.Const(SynConst.Unit, m)) - | [ elem ] -> transformExpr elem cont - | elem :: elems -> transformExpr elem (fun transformedElem -> loop elems (fun restExpr -> cont (``;`` transformedElem restExpr))) + and loopMatchClauses acc clauses cont = + match clauses with + | [] -> cont (List.rev acc) + | SynMatchClause(pat, whenExpr, resultExpr, m, dbg, trivia) :: clauses -> + loopElems [ resultExpr ] (fun resultExpr -> + loopMatchClauses (SynMatchClause(pat, whenExpr, resultExpr, m, dbg, trivia) :: acc) clauses cont) - loop elems id + loopElems elems id From 824a033adea8f8f61cbc11452f9b6cd0083cfb20 Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Sun, 15 Jun 2025 00:39:12 +0100 Subject: [PATCH 33/39] more test --- .../CheckComputationExpressions.fs | 14 ++ .../Expressions/CheckSequenceExpressions.fs | 14 ++ .../E_SequenceExpressions02.fs | 34 +++ .../MixedSequenceExpressionTests.fs | 236 +++++++++++++++++- .../SequenceExpressions15.fs | 22 ++ .../SequenceExpressions16.fs | 39 +++ 6 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/E_SequenceExpressions02.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions15.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions16.fs diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index dc85f54a09f..89f4138d1df 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -2333,6 +2333,20 @@ let rec TryTranslateComputationExpression if ceenv.isQuery && not isYield then error (Error(FSComp.SR.tcReturnMayNotBeUsedInQueries (), m)) + let synYieldOrReturnExpr = + match synYieldOrReturnExpr with + | SynExpr.IndexRange _ when isYield -> + if not (ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions) then + checkLanguageFeatureAndRecover + ceenv.cenv.g.langVersion + LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions + synYieldOrReturnExpr.Range + + match RewriteRangeExpr synYieldOrReturnExpr with + | Some rewrittenExpr -> rewrittenExpr + | None -> synYieldOrReturnExpr + | _ -> synYieldOrReturnExpr + requireBuilderMethod methName m cenv ceenv.env ceenv.ad ceenv.builderTy m let yieldOrReturnCall = diff --git a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs index 94ebca31240..8011642ed2e 100644 --- a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs @@ -413,6 +413,20 @@ let TcSequenceExpression (cenv: TcFileState) env tpenv comp (overallTy: OverallT if not isYield then errorR (Error(FSComp.SR.tcSeqResultsUseYield (), m)) + let synYieldExpr = + match synYieldExpr with + | SynExpr.IndexRange _ -> + if not (cenv.g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions) then + checkLanguageFeatureAndRecover + cenv.g.langVersion + LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions + synYieldExpr.Range + + match RewriteRangeExpr synYieldExpr with + | Some rewrittenExpr -> rewrittenExpr + | None -> synYieldExpr + | _ -> synYieldExpr + UnifyTypes cenv env synYieldExpr.Range genOuterTy (mkSeqTy cenv.g genResultTy) let resultExpr, tpenv = TcExprFlex cenv flex true genResultTy env tpenv synYieldExpr diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/E_SequenceExpressions02.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/E_SequenceExpressions02.fs new file mode 100644 index 00000000000..79003c6dcf4 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/E_SequenceExpressions02.fs @@ -0,0 +1,34 @@ +module MixedRangeVersionTest + +let a: int list = [ yield 1..10 ] +let a1: int list = [ yield! 1..10 ] + +let b: int list = [ yield [1..10] ] +let b: int list = [ yield! [1..10] ] + +let c: int seq = seq { yield seq { 1..10 } } +let c1: int seq = seq { yield! seq { 1..10 } } + +let d: int list = [ if true then yield 1 else yield 1..10] +let d1: int list = [ if true then yield 1 else yield! 1..10] +let d2: int list = [ if true then yield 1..10] +let d3: int list = [ if true then yield! 1..10] + +let e: int list = [if true then yield 1 else yield [1..10]] +let e1: int list = [if true then yield 1 else yield! [1..10]] +let e2 : int list = [if true then yield [1..10]] +let e3 : int list = [if true then yield! [1..10]] + +let g: int seq = seq { if true then yield 1 else yield seq { 1..10 } } +let g1: int seq = seq { if true then yield 1 else yield! seq { 1..10 } } +let g2: int seq = seq { if true then yield seq { 1..10 } } +let g3: int seq = seq { if true then yield! seq { 1..10 } } + +let h: int list = [ match true with | true -> yield 1 | false -> yield 1..10] +let h1: int list = [ match true with | true -> yield 1 | false -> yield! 1..10] + +let i: int list = [ match true with | true -> yield 1 | false -> yield [1..10]] +let i1: int list = [ match true with | true -> yield 1 | false -> yield! [1..10]] + +let j: int seq = seq { match true with | true -> yield 1 | false -> yield seq { 1..10 } } +let j1: int seq = seq { match true with | true -> yield 1 | false -> yield! seq { 1..10 } } \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs index 258d7ec26c2..7913d83c291 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs @@ -380,4 +380,238 @@ let f = [|-3; 1..10; 19|] compilation |> withLangVersionPreview |> verifyCompileAndRun - |> shouldSucceed \ No newline at end of file + |> shouldSucceed + + // SOURCE=E_SequenceExpressions02.fs # E_SequenceExpressions02.fs + [] + let ``Version 9: E_SequenceExpressions01 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 27, Line 3, Col 32, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 1, Line 3, Col 27, Line 3, Col 32, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 3, Col 27, Line 3, Col 32, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 3350, Line 4, Col 29, Line 4, Col 34, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 1, Line 6, Col 27, Line 6, Col 34, "This expression was expected to have type + 'int' +but here has type + ''a list' "); + (Error 1, Line 9, Col 30, Line 9, Col 43, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 9, Col 30, Line 9, Col 43, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 3350, Line 12, Col 53, Line 12, Col 58, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 1, Line 12, Col 53, Line 12, Col 58, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 12, Col 53, Line 12, Col 58, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 3350, Line 13, Col 55, Line 13, Col 60, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 14, Col 41, Line 14, Col 46, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 1, Line 14, Col 41, Line 14, Col 46, "This expression was expected to have type +'int' +but here has type +''a seq' "); + (Error 1, Line 14, Col 41, Line 14, Col 46, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 3350, Line 15, Col 42, Line 15, Col 47, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 1, Line 17, Col 53, Line 17, Col 60, "This expression was expected to have type + 'int' +but here has type + ''a list' "); + (Error 1, Line 19, Col 42, Line 19, Col 49, "This expression was expected to have type + 'int' +but here has type + ''a list' "); + (Error 1, Line 22, Col 56, Line 22, Col 69, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 22, Col 56, Line 22, Col 69, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 1, Line 24, Col 44, Line 24, Col 57, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 24, Col 44, Line 24, Col 57, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 3350, Line 27, Col 72, Line 27, Col 77, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 1, Line 27, Col 72, Line 27, Col 77, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 27, Col 72, Line 27, Col 77, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 3350, Line 28, Col 74, Line 28, Col 79, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 1, Line 30, Col 72, Line 30, Col 79, "This expression was expected to have type + 'int' +but here has type + ''a list' "); + (Error 1, Line 33, Col 75, Line 33, Col 88, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 33, Col 75, Line 33, Col 88, "This expression was expected to have type + 'int' +but here has type + 'int seq' ") + ] + + // SOURCE=E_SequenceExpressions02.fs # E_SequenceExpressions02.fs + [] + let ``Preview: E_SequenceExpressions02 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 1, Line 3, Col 27, Line 3, Col 32, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 3, Col 27, Line 3, Col 32, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 1, Line 6, Col 27, Line 6, Col 34, "This expression was expected to have type + 'int' +but here has type + ''a list' "); + (Error 1, Line 9, Col 30, Line 9, Col 43, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 9, Col 30, Line 9, Col 43, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 1, Line 12, Col 53, Line 12, Col 58, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 12, Col 53, Line 12, Col 58, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 1, Line 14, Col 41, Line 14, Col 46, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 14, Col 41, Line 14, Col 46, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 1, Line 17, Col 53, Line 17, Col 60, "This expression was expected to have type + 'int' +but here has type + ''a list' ") + (Error 1, Line 19, Col 42, Line 19, Col 49, "This expression was expected to have type + 'int' +but here has type + ''a list' "); + (Error 1, Line 22, Col 56, Line 22, Col 69, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 22, Col 56, Line 22, Col 69, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 1, Line 24, Col 44, Line 24, Col 57, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 24, Col 44, Line 24, Col 57, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 1, Line 27, Col 72, Line 27, Col 77, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 27, Col 72, Line 27, Col 77, "This expression was expected to have type + 'int' +but here has type + 'int seq' "); + (Error 1, Line 30, Col 72, Line 30, Col 79, "This expression was expected to have type + 'int' +but here has type + ''a list' "); + (Error 1, Line 33, Col 75, Line 33, Col 88, "This expression was expected to have type + 'int' +but here has type + ''a seq' "); + (Error 1, Line 33, Col 75, Line 33, Col 88, "This expression was expected to have type + 'int' +but here has type + 'int seq' ") + ] + + // SOURCE=SequenceExpressions15.fs # SequenceExpressions15.fs + [] + let ``Preview: SequenceExpressions15 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions15.fs # SequenceExpressions15.fs + [] + let ``Version 9: SequenceExpressions15 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 19, Line 3, Col 23, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 4, Col 23, Line 4, Col 27, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 5, Col 20, Line 5, Col 24, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 9, Col 29, Line 9, Col 33, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 10, Col 32, Line 10, Col 36, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 11, Col 31, Line 11, Col 35, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + ] + + // SOURCE=SequenceExpressions16.fs # SequenceExpressions16.fs + [] + let ``Preview: SequenceExpressions16 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions16.fs # SequenceExpressions16.fs + [] + let ``Version 9: SequenceExpressions16 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 28, Line 3, Col 33, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 8, Col 54, Line 8, Col 59, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 9, Col 42, Line 9, Col 47, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 17, Col 73, Line 17, Col 78, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + ] \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions15.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions15.fs new file mode 100644 index 00000000000..8b85e5dfc46 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions15.fs @@ -0,0 +1,22 @@ +module YieldVsYieldBang + +let a1 = [ yield! 1..5 ] +let a2 = seq { yield! 1..5 } +let a3 = [| yield! 1..5 |] + +// let b1: int list = [ yield 1..5 ] // Would give type error + +let c1: int list = [ yield! 1..5 ] +let c2: int seq = seq { yield! 1..5 } +let c3: int array = [| yield! 1..5 |] + +let expected = [1; 2; 3; 4; 5] + +if a1 <> expected then failwithf $"a1 failed: got {a1}" +if List.ofSeq a2 <> expected then failwithf $"a2 failed: got {List.ofSeq a2}" +if List.ofArray a3 <> expected then failwithf $"a3 failed: got {List.ofArray a3}" +if c1 <> expected then failwithf $"c1 failed: got {c1}" +if List.ofSeq c2 <> expected then failwithf $"c2 failed: got {List.ofSeq c2}" +if List.ofArray c3 <> expected then failwithf $"c3 failed: got {List.ofArray c3}" + +printfn "yield vs yield! tests passed!" \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions16.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions16.fs new file mode 100644 index 00000000000..98466908767 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions16.fs @@ -0,0 +1,39 @@ +module MixedRangeVersionTest + +let a: int list = [ yield! 1..10 ] +let a1: int list = [ yield! [1..10] ] + +let b: int seq = seq { yield! seq { 1..10 } } + +let c: int list = [ if true then yield 1 else yield! 1..10] +let c1: int list = [ if true then yield! 1..10] + +let d: int list = [if true then yield 1 else yield! [1..10]] +let d1 : int list = [if true then yield! [1..10]] + +let e: int seq = seq { if true then yield 1 else yield! seq { 1..10 } } +let e1: int seq = seq { if true then yield! seq { 1..10 } } + +let f: int list = [ match true with | true -> yield 1 | false -> yield! 1..10] + +let f1: int list = [ match true with | true -> yield 1 | false -> yield! [1..10]] + +let g: int seq = seq { match true with | true -> yield 1 | false -> yield! seq { 1..10 } } + +let expected = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] +let expectedOne = [1] + +if a <> expected then failwithf $"a failed: got {a}" +if a1 <> expected then failwithf $"a1 failed: got {a1}" +if List.ofSeq b <> expected then failwithf $"b failed: got {List.ofSeq b}" +if c <> expectedOne then failwithf $"c failed: got {c}" +if c1 <> expected then failwithf $"c1 failed: got {c1}" +if d <> expectedOne then failwithf $"d failed: got {d}" +if d1 <> expected then failwithf $"d1 failed: got {d1}" +if List.ofSeq e <> expectedOne then failwithf $"e failed: got {List.ofSeq e}" +if List.ofSeq e1 <> expected then failwithf $"e1 failed: got {List.ofSeq e1}" +if f <> expectedOne then failwithf $"f failed: got {f}" +if f1 <> expectedOne then failwithf $"f1 failed: got {f1}" +if List.ofSeq g <> expectedOne then failwithf $"g failed: got {List.ofSeq g}" + +printfn "yield vs yield! tests passed!" \ No newline at end of file From 2135780f3d02590d233a0b2cd0d7f7fd703ab0d8 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Mon, 16 Jun 2025 20:42:50 +0200 Subject: [PATCH 34/39] more tests --- .../MixedSequenceExpressionTests.fs | 22 ++++++++ .../SequenceExpressions17.fs | 55 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions17.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs index 7913d83c291..bdb72154f3b 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs @@ -614,4 +614,26 @@ but here has type (Error 3350, Line 8, Col 54, Line 8, Col 59, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 3350, Line 9, Col 42, Line 9, Col 47, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 3350, Line 17, Col 73, Line 17, Col 78, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + ] + + // SOURCE=SequenceExpressions17.fs # SequenceExpressions17.fs + [] + let ``Preview: SequenceExpressions17 fs`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions17.fs # SequenceExpressions17.fs + [] + let ``Version 9: SequenceExpressions17 fs`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 751, Line 15, Col 23, Line 15, Col 28, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 18, Col 27, Line 18, Col 32, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 41, Col 18, Line 41, Col 23, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 49, Col 24, Line 49, Col 29, "Incomplete expression or invalid use of indexer syntax") ] \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions17.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions17.fs new file mode 100644 index 00000000000..810d3818043 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions17.fs @@ -0,0 +1,55 @@ +module MixedRangeVersionTest + +let f p q r = + [ + if p then + if q then 3 + if p then + if q then + if r then 3 + ] + +let f1 p q r = + [ + if p then + if q then 1..10 + if p then + if q then + if r then 1..10 + ] + +let f2 x (|P|_|) (|Q|_|) (|R|_|) = + [ + match x with + | P _ -> 3 + | _ -> () + + match x with + | P y -> + match y with + | Q z -> + match z with + | R -> 3 + | _ -> () + | _ -> () + | _ -> () + ] + +let f x (|P|_|) (|Q|_|) (|R|_|) = + [ + match x with + | P _ -> 1..10 + | _ -> () + + match x with + | P y -> + match y with + | Q z -> + match z with + | R -> 1..10 + | _ -> () + | _ -> () + | _ -> () + ] + +printfn "yield vs yield! tests passed!" \ No newline at end of file From 297ba9326a6fab43ba4779cb409ad46f941c573d Mon Sep 17 00:00:00 2001 From: edgargonzalez Date: Wed, 18 Jun 2025 14:21:34 +0200 Subject: [PATCH 35/39] update tests --- .../Language/SequenceExpressions/SequenceExpressions17.fs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions17.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions17.fs index 810d3818043..6f3c9bf8ca8 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions17.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions17.fs @@ -12,10 +12,10 @@ let f p q r = let f1 p q r = [ if p then - if q then 1..10 + if q then yield! 1..10 if p then if q then - if r then 1..10 + if r then yield! 1..10 ] let f2 x (|P|_|) (|Q|_|) (|R|_|) = @@ -38,7 +38,7 @@ let f2 x (|P|_|) (|Q|_|) (|R|_|) = let f x (|P|_|) (|Q|_|) (|R|_|) = [ match x with - | P _ -> 1..10 + | P _ -> yield! 1..10 | _ -> () match x with @@ -46,7 +46,7 @@ let f x (|P|_|) (|Q|_|) (|R|_|) = match y with | Q z -> match z with - | R -> 1..10 + | R -> yield! 1..10 | _ -> () | _ -> () | _ -> () From afa9aebb877eeb7adfac6404382039ca56e921b4 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Mon, 25 Aug 2025 17:29:09 +0100 Subject: [PATCH 36/39] fix build --- .../Expressions/CheckComputationExpressions.fs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index 1f5025e64b9..6d0a9ae79eb 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -958,12 +958,8 @@ let requireBuilderMethod methodName ceenv m1 m2 = if not (hasBuilderMethod ceenv m1 methodName) then error (Error(FSComp.SR.tcRequireBuilderMethod methodName, m2)) -/// Checks if a builder method exists (without reporting an error) -let hasBuilderMethod methodName cenv env ad builderTy m = - not (isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad methodName builderTy)) - /// -/// Try translate the syntax sugar +/// Try to translate the syntax sugar /// /// Computation expression context (carrying caches, environments, ranges, etc) /// Flag if it's initial check @@ -1636,9 +1632,9 @@ let rec TryTranslateComputationExpression && containsRangeExpressions then let builderSupportsMixedRanges ceenv m = - hasBuilderMethod "Yield" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m - && hasBuilderMethod "Combine" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m - && hasBuilderMethod "Delay" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m + hasBuilderMethod ceenv m "Yield" + && hasBuilderMethod ceenv m "Combine" + && hasBuilderMethod ceenv m "Delay" if builderSupportsMixedRanges ceenv m then let transformSequenceWithRanges ceenv expr = @@ -2854,7 +2850,7 @@ and TransformExprToYieldOrYieldFrom ceenv expr = // create a YieldOrReturn expression and let the CE machinery handle it. match RewriteRangeExpr expr with | Some rewrittenRange -> - if hasBuilderMethod "YieldFrom" ceenv.cenv ceenv.env ceenv.ad ceenv.builderTy m then + if hasBuilderMethod ceenv m "YieldFrom" then ``yield!`` rewrittenRange else ``yield`` rewrittenRange From f90338fda2422f0e60d3da9aaae8b83bbca3227d Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Mon, 25 Aug 2025 18:15:15 +0100 Subject: [PATCH 37/39] fix tests --- .../SequenceExpressions/MixedSequenceExpressionTests.fs | 8 ++++---- .../Language/SequenceExpressions/SequenceExpressions17.fs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs index bdb72154f3b..3b08761e3bd 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs @@ -632,8 +632,8 @@ but here has type |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 751, Line 15, Col 23, Line 15, Col 28, "Incomplete expression or invalid use of indexer syntax"); - (Error 751, Line 18, Col 27, Line 18, Col 32, "Incomplete expression or invalid use of indexer syntax"); - (Error 751, Line 41, Col 18, Line 41, Col 23, "Incomplete expression or invalid use of indexer syntax"); - (Error 751, Line 49, Col 24, Line 49, Col 29, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 15, Col 30, Line 15, Col 35, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 18, Col 34, Line 18, Col 39, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 41, Col 25, Line 41, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 49, Col 31, Line 49, Col 36, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") ] \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions17.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions17.fs index 6f3c9bf8ca8..39fbaa196b8 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions17.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions17.fs @@ -35,7 +35,7 @@ let f2 x (|P|_|) (|Q|_|) (|R|_|) = | _ -> () ] -let f x (|P|_|) (|Q|_|) (|R|_|) = +let f3 x (|P|_|) (|Q|_|) (|R|_|) = [ match x with | P _ -> yield! 1..10 From fae433999ebd3b7e1b5895fba4c1a1f1d06d15f4 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Mon, 25 Aug 2025 21:50:54 +0100 Subject: [PATCH 38/39] split tests --- .../MixedSequenceExpressionTests.fs | 246 ++++++++++++------ .../SequenceExpressions00.fs | 10 + .../SequenceExpressions02.fs | 18 +- .../SequenceExpressions02a.fs | 8 + .../SequenceExpressions02b.fs | 8 + .../SequenceExpressions02c.fs | 8 + .../SequenceExpressions02d.fs | 8 + .../SequenceExpressions18.fs | 8 + .../SequenceExpressions19.fs | 9 + .../SequenceExpressions20.fs | 8 + 10 files changed, 244 insertions(+), 87 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions00.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02a.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02b.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02c.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02d.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions18.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions19.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions20.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs index 3b08761e3bd..05a1f367881 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs @@ -20,19 +20,10 @@ module MixedSequenceExpressionTests = |> withOptions ["--nowarn:988"] |> compileAndRun - [] - let ``Version 90: Mixed ranges and values require preview language version``() = - FSharp """ -module MixedRangeVersionTest - -let a = seq { yield! seq { 1..10 }; 19 } -let b = [-3; yield! [1..10]] -let c = [|-3; yield! [|1..10|]; 19|] - -let d = seq { 1..10; 19 } -let e = [-3; 1..10] -let f = [|-3; 1..10; 19|] - """ + // SOURCE=SequenceExpressions00.fs # SequenceExpressions00.fs + [] + let ``Version 9: Mixed ranges and values without preview should fail (baseline comparison)`` compilation = + compilation |> withLangVersion90 |> verifyCompile |> shouldFail @@ -45,45 +36,90 @@ let f = [|-3; 1..10; 19|] (Error 751, Line 10, Col 15, Line 10, Col 20, "Incomplete expression or invalid use of indexer syntax") ] - [] - let ``Preview: Mixed ranges and values require preview language version``() = - FSharp """ -module MixedRangeVersionTest + // SOURCE=SequenceExpressions00.fs # SequenceExpressions00.fs + [] + let ``Preview: Mixed ranges and values compile in all collection forms (baseline comparison)`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompile + |> shouldSucceed + + // SOURCE=SequenceExpressions02a.fs # SequenceExpressions02a.fs + [] + let ``Version 9: List literal mixing a single ascending range with a leading value (02a)`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 12, Line 3, Col 23, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 3, Col 17, Line 3, Col 22, "Incomplete expression or invalid use of indexer syntax") + ] -let a = seq { yield! seq { 1..10 }; 19 } -let b = [-3; yield! [1..10]] -let c = [|-3; yield! [|1..10|]; 19|] + // SOURCE=SequenceExpressions02a.fs # SequenceExpressions02a.fs + [] + let ``Preview: List literal mixing a single ascending range with a leading value (02a)`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed -let d = seq { 1..10; 19 } -let e = [-3; 1..10] -let f = [|-3; 1..10; 19|] - """ + // SOURCE=SequenceExpressions02b.fs # SequenceExpressions02b.fs + [] + let ``Version 9: List literal mixing a range in the middle of values (02b)`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 12, Line 3, Col 27, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 3, Col 17, Line 3, Col 22, "Incomplete expression or invalid use of indexer syntax") + ] + + // SOURCE=SequenceExpressions02b.fs # SequenceExpressions02b.fs + [] + let ``Preview: List literal mixing a range in the middle of values (02b)`` compilation = + compilation |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions02c.fs # SequenceExpressions02c.fs + [] + let ``Version 9: List literal with multiple ranges and trailing value (02c)`` compilation = + compilation + |> withLangVersion90 |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 12, Line 3, Col 28, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 3, Col 13, Line 3, Col 17, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 3, Col 19, Line 3, Col 23, "Incomplete expression or invalid use of indexer syntax") + ] + + // SOURCE=SequenceExpressions02c.fs # SequenceExpressions02c.fs + [] + let ``Preview: List literal with multiple ranges and trailing value (02c)`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun |> shouldSucceed - - // SOURCE=SequenceExpressions02.fs # SequenceExpressions02.fs - [] - let ``Version 9: SequenceExpressions02 fs`` compilation = + + // SOURCE=SequenceExpressions02d.fs # SequenceExpressions02d.fs + [] + let ``Version 9: List literal with stepped range between values (02d)`` compilation = compilation |> withLangVersion90 |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 3, Col 13, Line 3, Col 24, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 3, Col 18, Line 3, Col 23, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 7, Col 13, Line 7, Col 28, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 7, Col 18, Line 7, Col 23, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 11, Col 13, Line 11, Col 29, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 11, Col 14, Line 11, Col 18, "Incomplete expression or invalid use of indexer syntax") - (Error 751, Line 11, Col 20, Line 11, Col 24, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 15, Col 13, Line 15, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 15, Col 17, Line 15, Col 25, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 3, Col 12, Line 3, Col 29, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 3, Col 16, Line 3, Col 24, "Incomplete expression or invalid use of indexer syntax") ] - // SOURCE=SequenceExpressions02.fs # SequenceExpressions02.fs - [] - let ``Preview: SequenceExpressions02 fs`` compilation = + // SOURCE=SequenceExpressions02d.fs # SequenceExpressions02d.fs + [] + let ``Preview: List literal with stepped range between values (02d)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -91,7 +127,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions03.fs # SequenceExpressions03.fs [] - let ``Preview: SequenceExpressions03 fs`` compilation = + let ``Preview: seq builder: ranges as splices are accepted (03)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -99,7 +135,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions03.fs # SequenceExpressions03.fs [] - let ``Version 9: SequenceExpressions03 fs`` compilation = + let ``Version 9: seq builder: ranges without preview should fail (03)`` compilation = compilation |> withLangVersion90 |> verifyCompile @@ -122,7 +158,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions04.fs # SequenceExpressions04.fs [] - let ``Preview: SequenceExpressions04 fs`` compilation = + let ``Preview: seq builder: ranges in branches etc. accepted (04)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -130,7 +166,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions04.fs # SequenceExpressions04.fs [] - let ``Version 9: SequenceExpressions04 fs`` compilation = + let ``Version 9: seq builder: ranges without preview should fail (04)`` compilation = compilation |> withLangVersion90 |> verifyCompile @@ -147,7 +183,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions05.fs # SequenceExpressions05.fs [] - let ``Preview: SequenceExpressions05 fs`` compilation = + let ``Preview: seq builder: mixing ranges with values compiles and runs (05)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -155,7 +191,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions05.fs # SequenceExpressions05.fs [] - let ``Version 9: SequenceExpressions05 fs`` compilation = + let ``Version 9: seq builder: mixing ranges with values requires preview (05)`` compilation = compilation |> withLangVersion90 |> verifyCompile @@ -169,7 +205,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions06.fs # SequenceExpressions06.fs [] - let ``Preview: SequenceExpressions06 fs`` compilation = + let ``Preview: Type inference across list/array/seq with mixed ranges (06)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -177,7 +213,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions06.fs # SequenceExpressions06.fs [] - let ``Version 9: SequenceExpressions06 fs`` compilation = + let ``Version 9: Type inference with mixed ranges requires preview (06)`` compilation = compilation |> withLangVersion90 |> verifyCompile @@ -195,7 +231,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions07.fs # SequenceExpressions07.fs [] - let ``Preview: SequenceExpressions07 fs`` compilation = + let ``Preview: Custom CE builder splices built-in ranges via YieldFrom (07)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -204,7 +240,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions07.fs # SequenceExpressions07.fs [] - let ``Version 9: SequenceExpressions07 fs`` compilation = + let ``Version 9: Custom CE with mixed ranges requires preview (07)`` compilation = compilation |> withLangVersion90 |> verifyCompile @@ -222,23 +258,23 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions08.fs # SequenceExpressions08.fs [] - let ``Version 9: SequenceExpressions08 fs`` compilation = + let ``Version 9: Equivalence examples require preview (08)`` compilation = compilation |> withLangVersion90 |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 7, Col 13, Line 7, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); - (Error 751, Line 7, Col 15, Line 7, Col 20, "Incomplete expression or invalid use of indexer syntax"); - (Error 3350, Line 8, Col 9, Line 8, Col 20, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); - (Error 751, Line 8, Col 14, Line 8, Col 19, "Incomplete expression or invalid use of indexer syntax"); - (Error 3350, Line 9, Col 9, Line 9, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 7, Col 13, Line 7, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 7, Col 15, Line 7, Col 20, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 8, Col 9, Line 8, Col 20, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 8, Col 14, Line 8, Col 19, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 9, Col 9, Line 9, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 9, Col 15, Line 9, Col 20, "Incomplete expression or invalid use of indexer syntax") ] // SOURCE=SequenceExpressions08.fs # SequenceExpressions08.fs [] - let ``Preview: SequenceExpressions08 fs`` compilation = + let ``Preview: Equivalence: direct ranges equal explicit yield! in seq/list/array (08)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -246,7 +282,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions09.fs # SequenceExpressions09.fs [] - let ``Preview: SequenceExpressions09 fs`` compilation = + let ``Preview: Non-interference: custom (..) operator is not treated as range (09)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -254,7 +290,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions09.fs # SequenceExpressions09.fs [] - let ``Version 9: SequenceExpressions09 fs`` compilation = + let ``Version 9: Non-interference: custom (..) operator is not treated as range (09)`` compilation = compilation |> withLangVersion90 |> verifyCompileAndRun @@ -262,7 +298,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions10.fs # SequenceExpressions10.fs [] - let ``Version 9: SequenceExpressions10 fs`` compilation = + let ``Version 9: Mixed ranges and values across seq/list/array blocks require preview (10)`` compilation = compilation |> withLangVersion90 |> verifyCompile @@ -284,7 +320,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions10.fs # SequenceExpressions10.fs [] - let ``Preview: SequenceExpressions10 fs`` compilation = + let ``Preview: Mixed ranges and values across seq/list/array blocks compile and match explicit yield! (10)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -292,7 +328,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions11.fs # SequenceExpressions11.fs [] - let ``Version 9: SequenceExpressions11 fs`` compilation = + let ``Version 9: Stepped ranges mixed with values require preview (11)`` compilation = compilation |> withLangVersion90 |> verifyCompile @@ -314,7 +350,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions11.fs # SequenceExpressions11.fs [] - let ``Preview: SequenceExpressions11 fs`` compilation = + let ``Preview: Stepped ranges mixed with values compile and match explicit yield! (11)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -322,7 +358,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions12.fs # SequenceExpressions12.fs [] - let ``Version 9: SequenceExpressions12 fs`` compilation = + let ``Version 9: Single direct range in list/seq/array requires preview (12)`` compilation = compilation |> withLangVersion90 |> verifyCompile @@ -333,7 +369,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions12.fs # SequenceExpressions12.fs [] - let ``Preview: SequenceExpressions12 fs`` compilation = + let ``Preview: Single direct range in list/seq/array equals explicit yield! (12)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -341,7 +377,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions13.fs # SequenceExpressions13.fs [] - let ``Version 9: SequenceExpressions13 fs`` compilation = + let ``Version 9: Interleaving ranges and values requires preview (13)`` compilation = compilation |> withLangVersion90 |> verifyCompile @@ -360,7 +396,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions13.fs # SequenceExpressions13.fs [] - let ``Preview: SequenceExpressions13 fs`` compilation = + let ``Preview: Interleaving ranges and values equals explicit forms (13)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -368,7 +404,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions14.fs # SequenceExpressions14.fs [] - let ``Version 9: SequenceExpressions14 fs`` compilation = + let ``Version 9: No ranges: existing yield/yield! behavior unchanged (14)`` compilation = compilation |> withLangVersion90 |> verifyCompileAndRun @@ -376,7 +412,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=SequenceExpressions13.fs # SequenceExpressions13.fs [] - let ``Preview: SequenceExpressions14 fs`` compilation = + let ``Preview: No ranges: existing yield/yield! behavior unchanged (14)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -384,7 +420,7 @@ let f = [|-3; 1..10; 19|] // SOURCE=E_SequenceExpressions02.fs # E_SequenceExpressions02.fs [] - let ``Version 9: E_SequenceExpressions01 fs`` compilation = + let ``Version 9: Invalid 'yield range' vs 'yield! range' typing diagnostics (E_02)`` compilation = compilation |> withLangVersion90 |> verifyCompile @@ -482,7 +518,7 @@ but here has type // SOURCE=E_SequenceExpressions02.fs # E_SequenceExpressions02.fs [] - let ``Preview: E_SequenceExpressions02 fs`` compilation = + let ``Preview: Invalid 'yield range' vs 'yield! range' typing diagnostics (E_02)`` compilation = compilation |> withLangVersionPreview |> verifyCompile @@ -572,7 +608,7 @@ but here has type // SOURCE=SequenceExpressions15.fs # SequenceExpressions15.fs [] - let ``Preview: SequenceExpressions15 fs`` compilation = + let ``Preview: yield vs yield! ranges baseline (15)`` compilation = compilation |> withLangVersionPreview |> verifyCompileAndRun @@ -580,7 +616,7 @@ but here has type // SOURCE=SequenceExpressions15.fs # SequenceExpressions15.fs [] - let ``Version 9: SequenceExpressions15 fs`` compilation = + let ``Version 9: yield vs yield! baseline compilation behavior (15)`` compilation = compilation |> withLangVersion90 |> verifyCompile @@ -636,4 +672,66 @@ but here has type (Error 3350, Line 18, Col 34, Line 18, Col 39, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 3350, Line 41, Col 25, Line 41, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 3350, Line 49, Col 31, Line 49, Col 36, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - ] \ No newline at end of file + ] + + // SOURCE=SequenceExpressions18.fs # SequenceExpressions18.fs + [] + let ``Preview: char ranges mixed with values compile and run`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions18.fs # SequenceExpressions18.fs + [] + let ``Version 9: char ranges mixed with values require preview`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 16, Line 3, Col 33, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 3, Col 18, Line 3, Col 26, "Incomplete expression or invalid use of indexer syntax") + ] + + // SOURCE=SequenceExpressions19.fs # SequenceExpressions19.fs + [] + let ``Preview: bigint ranges mixed with values compile and run`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions19.fs # SequenceExpressions19.fs + [] + let ``Version 9: bigint ranges mixed with values require preview`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 4, Col 12, Line 4, Col 31, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 4, Col 14, Line 4, Col 24, "Incomplete expression or invalid use of indexer syntax") + ] + + // SOURCE=SequenceExpressions20.fs # SequenceExpressions20.fs + [] + let ``Preview: empty and singleton ranges preserve order`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + + // SOURCE=SequenceExpressions20.fs # SequenceExpressions20.fs + [] + let ``Version 9: empty and singleton ranges inside list literals require preview`` compilation = + compilation + |> withLangVersion90 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 3350, Line 3, Col 12, Line 3, Col 38, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 751, Line 3, Col 17, Line 3, Col 21, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 3, Col 23, Line 3, Col 27, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 3, Col 29, Line 3, Col 33, "Incomplete expression or invalid use of indexer syntax") + ] diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions00.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions00.fs new file mode 100644 index 00000000000..ce3fb1443d6 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions00.fs @@ -0,0 +1,10 @@ + +module MixedRangeVersionTest + +let a = seq { yield! seq { 1..10 }; 19 } +let b = [-3; yield! [1..10]] +let c = [|-3; yield! [|1..10|]; 19|] + +let d = seq { 1..10; 19 } +let e = [-3; 1..10] +let f = [|-3; 1..10; 19|] diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02.fs index 69427e47cb7..98576ac716c 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02.fs @@ -1,19 +1,11 @@ module MixedRangeListTests -let test1 = [-3; 1..10] -let expected1 = [-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10] -if test1 <> expected1 then failwith $"test1 failed: got {test1}" +// This aggregated file is now split into SequenceExpressions02a.fs..02d.fs. +// Keeping a trivial test here to maintain references where needed. -let test2 = [-3; 1..10; 19] -let expected2 = [-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 19] -if test2 <> expected2 then failwith $"test2 failed: got {test2}" +let test = [0] +let expected = [0] -let test3 = [1..3; 5..7; 10] -let expected3 = [1; 2; 3; 5; 6; 7; 10] -if test3 <> expected3 then failwith $"test3 failed: got {test3}" - -let test4 = [0; 2..2..10; 15] -let expected4 = [0; 2; 4; 6; 8; 10; 15] -if test4 <> expected4 then failwith $"test4 failed: got {test4}" +if test <> expected then failwith $"test failed: got {test}" printfn "All list tests passed!" \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02a.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02a.fs new file mode 100644 index 00000000000..a0a66b83526 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02a.fs @@ -0,0 +1,8 @@ +module MixedRangeListTest01 + +let test = [-3; 1..10] +let expected = [-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10] + +if test <> expected then failwith $"test failed: got {test}" + +printfn "All list tests passed!" \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02b.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02b.fs new file mode 100644 index 00000000000..98384aaed9d --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02b.fs @@ -0,0 +1,8 @@ +module MixedRangeListTest02 + +let test = [-3; 1..10; 19] +let expected = [-3; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 19] + +if test <> expected then failwith $"test failed: got {test}" + +printfn "All list tests passed!" \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02c.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02c.fs new file mode 100644 index 00000000000..89fca24084a --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02c.fs @@ -0,0 +1,8 @@ +module MixedRangeListTest03 + +let test = [1..3; 5..7; 10] +let expected = [1; 2; 3; 5; 6; 7; 10] + +if test <> expected then failwith $"test failed: got {test}" + +printfn "All list tests passed!" \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02d.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02d.fs new file mode 100644 index 00000000000..bd95c934f10 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions02d.fs @@ -0,0 +1,8 @@ +module MixedRangeListTest04 + +let test = [0; 2..2..10; 15] +let expected = [0; 2; 4; 6; 8; 10; 15] + +if test <> expected then failwith $"test failed: got {test}" + +printfn "All list tests passed!" \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions18.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions18.fs new file mode 100644 index 00000000000..c05b2893c6a --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions18.fs @@ -0,0 +1,8 @@ +module CharRangesTest + +let test = seq { 'a'..'c'; 'Z' } |> Seq.toArray +let expected = [| 'a'; 'b'; 'c'; 'Z' |] + +if test <> expected then failwith $"test failed: got {test}" + +printfn "All list tests passed!" diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions19.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions19.fs new file mode 100644 index 00000000000..4e7863d73fc --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions19.fs @@ -0,0 +1,9 @@ +module BigIntRangesTest +open System.Numerics + +let test = [ 0I..2I..6I; 10I ] +let expected = [0I;2I;4I;6I;10I] + +if test <> expected then failwith $"test failed: got {test}" + +printfn "All list tests passed!" diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions20.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions20.fs new file mode 100644 index 00000000000..928797117ea --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions20.fs @@ -0,0 +1,8 @@ +module EmptyRangesTest + +let test = [ 0; 1..0; 2..2; 3..1; 4 ] +let expected = [0;2;4] + +if test <> expected then failwith $"test failed: got {test}" + +printfn "All list tests passed!" From a06809452d5207c10065846f268b1b5b6adc737d Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Mon, 25 Aug 2025 22:47:56 +0100 Subject: [PATCH 39/39] use better range --- .../CheckArrayOrListComputedExpressions.fs | 44 +++--- .../CheckComputationExpressions.fs | 34 ++--- .../Expressions/CheckSequenceExpressions.fs | 53 ++++---- .../MixedSequenceExpressionTests.fs | 127 ++++++++++-------- 4 files changed, 142 insertions(+), 116 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs index 81f55e2a2c5..9ff4c6d4eb9 100644 --- a/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckArrayOrListComputedExpressions.fs @@ -99,20 +99,22 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT errorR (Deprecated(FSComp.SR.tcExpressionWithIfRequiresParenthesis (), m)) | _ -> () - let containsRangeExpressions = - elems - |> List.exists (function - | SynExpr.IndexRange _ -> true - | _ -> false) - - if - containsRangeExpressions - && g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions - then + if g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions then tcMixedSequencesWithRanges cenv env overallTy tpenv isArray elems m else - if containsRangeExpressions then - checkLanguageFeatureAndRecover cenv.g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m + let reportRangeExpressionsNotSupported expr = + let rec loop exprs = + match exprs with + | [] -> () + | SynExpr.IndexRange(_, _, _, _, _, m) :: exprs -> + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m + loop exprs + | SynExpr.Sequential(_, true, e1, e2, _, _) :: exprs -> loop (e1 :: e2 :: exprs) + | _ :: exprs -> loop exprs + + loop [ expr ] + + reportRangeExpressionsNotSupported comp let replacementExpr = // These are to improve parsing/processing speed for parser tables by converting to an array blob ASAP @@ -201,10 +203,22 @@ let TcArrayOrListComputedExpression (cenv: TcFileState) env (overallTy: OverallT let elems = getElems comp [] insertImplicitYieldsAndYieldBangs elems m | _ -> comp - else if containsRangeMixedWithYields then - checkLanguageFeatureAndRecover g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m - comp else + // Report language feature error for each range expression in a sequence + let reportRangeExpressionsNotSupported expr = + let rec loop exprs = + match exprs with + | [] -> () + | SynExpr.IndexRange(_, _, _, _, _, m) :: exprs -> + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m + loop exprs + | SynExpr.Sequential(_, true, e1, e2, _, _) :: exprs -> loop (e1 :: e2 :: exprs) + | _ :: exprs -> loop exprs + + loop [ expr ] + + reportRangeExpressionsNotSupported comp + comp let genCollElemTy = NewInferenceType g diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index 6d0a9ae79eb..d0fdaca9a73 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -2309,28 +2309,19 @@ let rec TryTranslateComputationExpression Some(translatedCtxt callExpr) | SynExpr.YieldOrReturnFrom((true, _), synYieldExpr, _, { YieldOrReturnFromKeyword = m }) -> - let isRangeExpr = - match synYieldExpr with - | SynExpr.IndexRange _ -> true - | _ -> false - - if - isRangeExpr - && not (ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions) - then - checkLanguageFeatureAndRecover - ceenv.cenv.g.langVersion - LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions - synYieldExpr.Range - // Rewrite range expressions in yield! to their sequence form let synYieldExpr = - if isRangeExpr then + match synYieldExpr with + | SynExpr.IndexRange _ -> + checkLanguageFeatureAndRecover + ceenv.cenv.g.langVersion + LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions + synYieldExpr.Range + match RewriteRangeExpr synYieldExpr with | Some rewrittenExpr -> rewrittenExpr | None -> synYieldExpr - else - synYieldExpr + | _ -> synYieldExpr let yieldFromExpr = mkSourceExpr synYieldExpr ceenv.sourceMethInfo ceenv.builderValName @@ -2395,11 +2386,10 @@ let rec TryTranslateComputationExpression let synYieldOrReturnExpr = match synYieldOrReturnExpr with | SynExpr.IndexRange _ when isYield -> - if not (ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions) then - checkLanguageFeatureAndRecover - ceenv.cenv.g.langVersion - LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions - synYieldOrReturnExpr.Range + checkLanguageFeatureAndRecover + ceenv.cenv.g.langVersion + LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions + synYieldOrReturnExpr.Range match RewriteRangeExpr synYieldOrReturnExpr with | Some rewrittenExpr -> rewrittenExpr diff --git a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs index 68969b1e14e..c739231a641 100644 --- a/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs @@ -365,28 +365,18 @@ let TcSequenceExpression (cenv: TcFileState) env tpenv comp (overallTy: OverallT | SynExpr.YieldOrReturnFrom(flags = (isYield, _); expr = synYieldExpr; trivia = { YieldOrReturnFromKeyword = m }) -> let env = { env with eIsControlFlow = false } - let isRangeExpr = + let synYieldExpr = match synYieldExpr with - | SynExpr.IndexRange _ -> true - | _ -> false - - if - isRangeExpr - && not (cenv.g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions) - then - checkLanguageFeatureAndRecover - cenv.g.langVersion - LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions - synYieldExpr.Range + | SynExpr.IndexRange _ -> + checkLanguageFeatureAndRecover + g.langVersion + LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions + synYieldExpr.Range - // Rewrite range expressions in yield! to their sequence form - let synYieldExpr = - if isRangeExpr then match RewriteRangeExpr synYieldExpr with | Some rewrittenExpr -> rewrittenExpr | None -> synYieldExpr - else - synYieldExpr + | _ -> synYieldExpr let resultExpr, genExprTy, tpenv = TcExprOfUnknownType cenv env tpenv synYieldExpr @@ -416,11 +406,10 @@ let TcSequenceExpression (cenv: TcFileState) env tpenv comp (overallTy: OverallT let synYieldExpr = match synYieldExpr with | SynExpr.IndexRange _ -> - if not (cenv.g.langVersion.SupportsFeature LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions) then - checkLanguageFeatureAndRecover - cenv.g.langVersion - LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions - synYieldExpr.Range + checkLanguageFeatureAndRecover + cenv.g.langVersion + LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions + synYieldExpr.Range match RewriteRangeExpr synYieldExpr with | Some rewrittenExpr -> rewrittenExpr @@ -519,8 +508,24 @@ let TcSequenceExpressionEntry (cenv: TcFileState) env (overallTy: OverallTy) tpe else // Check if ranges are present but feature is disabled if containsRanges then - // Report error for mixed ranges when feature is disabled - checkLanguageFeatureAndRecover cenv.g.langVersion LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions m + // Report language feature error for each range expression in a sequence + let reportRangeExpressionsNotSupported expr = + let rec loop exprs = + match exprs with + | [] -> () + | SynExpr.IndexRange(_, _, _, _, _, m) :: exprs -> + checkLanguageFeatureAndRecover + cenv.g.langVersion + LanguageFeature.AllowMixedRangesAndValuesInSeqExpressions + m + + loop exprs + | SynExpr.Sequential(_, true, e1, e2, _, _) :: exprs -> loop (e1 :: e2 :: exprs) + | _ :: exprs -> loop exprs + + loop [ expr ] + + reportRangeExpressionsNotSupported comp // No ranges, use regular handling TcSequenceExpression cenv env tpenv comp overallTy m diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs index 05a1f367881..f617b4f90ef 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/MixedSequenceExpressionTests.fs @@ -28,11 +28,11 @@ module MixedSequenceExpressionTests = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 8, Col 13, Line 8, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 8, Col 15, Line 8, Col 20, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 8, Col 15, Line 8, Col 20, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 9, Col 9, Line 9, Col 20, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 9, Col 14, Line 9, Col 19, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 9, Col 14, Line 9, Col 19, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 10, Col 9, Line 10, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 10, Col 15, Line 10, Col 20, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 10, Col 15, Line 10, Col 20, "Incomplete expression or invalid use of indexer syntax") ] @@ -52,7 +52,7 @@ module MixedSequenceExpressionTests = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 3, Col 12, Line 3, Col 23, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 3, Col 17, Line 3, Col 22, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 751, Line 3, Col 17, Line 3, Col 22, "Incomplete expression or invalid use of indexer syntax") ] @@ -72,7 +72,7 @@ module MixedSequenceExpressionTests = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 3, Col 12, Line 3, Col 27, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 3, Col 17, Line 3, Col 22, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 3, Col 17, Line 3, Col 22, "Incomplete expression or invalid use of indexer syntax") ] @@ -92,7 +92,8 @@ module MixedSequenceExpressionTests = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 3, Col 12, Line 3, Col 28, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 3, Col 13, Line 3, Col 17, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 3, Col 19, Line 3, Col 23, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 3, Col 13, Line 3, Col 17, "Incomplete expression or invalid use of indexer syntax") (Error 751, Line 3, Col 19, Line 3, Col 23, "Incomplete expression or invalid use of indexer syntax") ] @@ -113,7 +114,7 @@ module MixedSequenceExpressionTests = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 3, Col 12, Line 3, Col 29, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 3, Col 16, Line 3, Col 24, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 751, Line 3, Col 16, Line 3, Col 24, "Incomplete expression or invalid use of indexer syntax") ] @@ -141,18 +142,19 @@ module MixedSequenceExpressionTests = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 3, Col 13, Line 3, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 3, Col 19, Line 3, Col 24, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 7, Col 13, Line 7, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 7, Col 19, Line 7, Col 24, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 11, Col 13, Line 11, Col 31, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 11, Col 15, Line 11, Col 19, "Incomplete expression or invalid use of indexer syntax") - (Error 751, Line 11, Col 21, Line 11, Col 25, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 15, Col 13, Line 15, Col 32, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 15, Col 18, Line 15, Col 26, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 19, Col 13, Line 19, Col 28, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 19, Col 18, Line 19, Col 22, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 23, Col 13, Line 23, Col 28, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 3, Col 19, Line 3, Col 24, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 3, Col 19, Line 3, Col 24, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 7, Col 19, Line 7, Col 24, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 7, Col 19, Line 7, Col 24, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 11, Col 15, Line 11, Col 19, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 11, Col 21, Line 11, Col 25, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 11, Col 15, Line 11, Col 19, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 11, Col 21, Line 11, Col 25, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 15, Col 18, Line 15, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 15, Col 18, Line 15, Col 26, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 19, Col 18, Line 19, Col 22, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 19, Col 18, Line 19, Col 22, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 23, Col 18, Line 23, Col 22, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 751, Line 23, Col 18, Line 23, Col 22, "Incomplete expression or invalid use of indexer syntax") ] @@ -172,12 +174,13 @@ module MixedSequenceExpressionTests = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 3, Col 17, Line 3, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 3, Col 19, Line 3, Col 24, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 7, Col 17, Line 7, Col 37, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 7, Col 23, Line 7, Col 27, "Incomplete expression or invalid use of indexer syntax") - (Error 751, Line 7, Col 29, Line 7, Col 35, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 11, Col 17, Line 11, Col 36, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 3, Col 19, Line 3, Col 24, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 3, Col 19, Line 3, Col 24, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 7, Col 23, Line 7, Col 27, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 7, Col 29, Line 7, Col 35, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 7, Col 23, Line 7, Col 27, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 7, Col 29, Line 7, Col 35, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 11, Col 22, Line 11, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 751, Line 11, Col 22, Line 11, Col 30, "Incomplete expression or invalid use of indexer syntax") ] @@ -197,9 +200,9 @@ module MixedSequenceExpressionTests = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 3, Col 17, Line 3, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 3, Col 19, Line 3, Col 24, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 3, Col 19, Line 3, Col 24, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 7, Col 17, Line 7, Col 36, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 7, Col 22, Line 7, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 7, Col 22, Line 7, Col 30, "Incomplete expression or invalid use of indexer syntax") ] @@ -219,13 +222,13 @@ module MixedSequenceExpressionTests = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 3, Col 23, Line 3, Col 33, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 3, Col 24, Line 3, Col 28, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 3, Col 24, Line 3, Col 28, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 4, Col 24, Line 4, Col 36, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 4, Col 26, Line 4, Col 30, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 4, Col 26, Line 4, Col 30, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 5, Col 27, Line 5, Col 39, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 5, Col 29, Line 5, Col 33, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 5, Col 29, Line 5, Col 33, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 8, Col 5, Line 8, Col 27, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 8, Col 6, Line 8, Col 19, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 8, Col 6, Line 8, Col 19, "Incomplete expression or invalid use of indexer syntax") ] @@ -264,11 +267,11 @@ module MixedSequenceExpressionTests = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 7, Col 13, Line 7, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 7, Col 15, Line 7, Col 20, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 7, Col 15, Line 7, Col 20, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 8, Col 9, Line 8, Col 20, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 8, Col 14, Line 8, Col 19, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 8, Col 14, Line 8, Col 19, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 9, Col 9, Line 9, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 9, Col 15, Line 9, Col 20, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 9, Col 15, Line 9, Col 20, "Incomplete expression or invalid use of indexer syntax") ] @@ -304,17 +307,23 @@ module MixedSequenceExpressionTests = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 3, Col 13, Line 10, Col 2, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 5, Col 5, Line 5, Col 9, "Incomplete expression or invalid use of indexer syntax") - (Error 751, Line 7, Col 5, Line 7, Col 11, "Incomplete expression or invalid use of indexer syntax") - (Error 751, Line 9, Col 5, Line 9, Col 11, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 12, Col 9, Line 19, Col 2, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 14, Col 5, Line 14, Col 9, "Incomplete expression or invalid use of indexer syntax") - (Error 751, Line 16, Col 5, Line 16, Col 11, "Incomplete expression or invalid use of indexer syntax") - (Error 751, Line 18, Col 5, Line 18, Col 11, "Incomplete expression or invalid use of indexer syntax") - (Error 3350, Line 20, Col 9, Line 27, Col 3, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 22, Col 5, Line 22, Col 9, "Incomplete expression or invalid use of indexer syntax") - (Error 751, Line 24, Col 5, Line 24, Col 11, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 5, Col 5, Line 5, Col 9, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 7, Col 5, Line 7, Col 11, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 9, Col 5, Line 9, Col 11, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 5, Col 5, Line 5, Col 9, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 7, Col 5, Line 7, Col 11, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 9, Col 5, Line 9, Col 11, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 14, Col 5, Line 14, Col 9, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 16, Col 5, Line 16, Col 11, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 18, Col 5, Line 18, Col 11, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 14, Col 5, Line 14, Col 9, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 16, Col 5, Line 16, Col 11, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 18, Col 5, Line 18, Col 11, "Incomplete expression or invalid use of indexer syntax"); + (Error 3350, Line 22, Col 5, Line 22, Col 9, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 24, Col 5, Line 24, Col 11, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 26, Col 5, Line 26, Col 11, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 22, Col 5, Line 22, Col 9, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 24, Col 5, Line 24, Col 11, "Incomplete expression or invalid use of indexer syntax"); (Error 751, Line 26, Col 5, Line 26, Col 11, "Incomplete expression or invalid use of indexer syntax") ] @@ -334,18 +343,24 @@ module MixedSequenceExpressionTests = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 3, Col 13, Line 10, Col 2, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 5, Col 5, Line 5, Col 13, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 7, Col 5, Line 7, Col 11, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 9, Col 5, Line 9, Col 14, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 751, Line 5, Col 5, Line 5, Col 13, "Incomplete expression or invalid use of indexer syntax"); (Error 751, Line 7, Col 5, Line 7, Col 11, "Incomplete expression or invalid use of indexer syntax"); (Error 751, Line 9, Col 5, Line 9, Col 14, "Incomplete expression or invalid use of indexer syntax"); - (Error 3350, Line 12, Col 9, Line 19, Col 2, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 14, Col 5, Line 14, Col 13, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 16, Col 5, Line 16, Col 11, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 18, Col 5, Line 18, Col 14, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 751, Line 14, Col 5, Line 14, Col 13, "Incomplete expression or invalid use of indexer syntax"); (Error 751, Line 16, Col 5, Line 16, Col 11, "Incomplete expression or invalid use of indexer syntax"); (Error 751, Line 18, Col 5, Line 18, Col 14, "Incomplete expression or invalid use of indexer syntax"); - (Error 3350, Line 20, Col 9, Line 27, Col 3, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 22, Col 5, Line 22, Col 13, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 24, Col 5, Line 24, Col 11, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 26, Col 5, Line 26, Col 14, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 751, Line 22, Col 5, Line 22, Col 13, "Incomplete expression or invalid use of indexer syntax"); (Error 751, Line 24, Col 5, Line 24, Col 11, "Incomplete expression or invalid use of indexer syntax"); - (Error 751, Line 26, Col 5, Line 26, Col 14, "Incomplete expression or invalid use of indexer syntax") + (Error 751, Line 26, Col 5, Line 26, Col 14, "Incomplete expression or invalid use of indexer syntax") ] // SOURCE=SequenceExpressions11.fs # SequenceExpressions11.fs @@ -385,7 +400,7 @@ module MixedSequenceExpressionTests = |> withDiagnostics [ (Error 3350, Line 3, Col 18, Line 3, Col 23, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 3350, Line 5, Col 38, Line 5, Col 44, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); - (Error 3350, Line 9, Col 9, Line 9, Col 37, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 9, Col 11, Line 9, Col 16, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 751, Line 9, Col 11, Line 9, Col 16, "Incomplete expression or invalid use of indexer syntax"); (Error 3350, Line 9, Col 29, Line 9, Col 35, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); (Error 3350, Line 10, Col 22, Line 10, Col 27, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); @@ -690,7 +705,7 @@ but here has type |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 3, Col 16, Line 3, Col 33, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 3, Col 18, Line 3, Col 26, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 3, Col 18, Line 3, Col 26, "Incomplete expression or invalid use of indexer syntax") ] @@ -710,7 +725,7 @@ but here has type |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 4, Col 12, Line 4, Col 31, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") + (Error 3350, Line 4, Col 14, Line 4, Col 24, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") (Error 751, Line 4, Col 14, Line 4, Col 24, "Incomplete expression or invalid use of indexer syntax") ] @@ -730,8 +745,10 @@ but here has type |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 3350, Line 3, Col 12, Line 3, Col 38, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater.") - (Error 751, Line 3, Col 17, Line 3, Col 21, "Incomplete expression or invalid use of indexer syntax") - (Error 751, Line 3, Col 23, Line 3, Col 27, "Incomplete expression or invalid use of indexer syntax") + (Error 3350, Line 3, Col 17, Line 3, Col 21, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 3, Col 23, Line 3, Col 27, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 3350, Line 3, Col 29, Line 3, Col 33, "Feature 'Allow mixed ranges and values in sequence expressions, e.g. seq { 1..10; 20 }' is not available in F# 9.0. Please use language version 'PREVIEW' or greater."); + (Error 751, Line 3, Col 17, Line 3, Col 21, "Incomplete expression or invalid use of indexer syntax"); + (Error 751, Line 3, Col 23, Line 3, Col 27, "Incomplete expression or invalid use of indexer syntax"); (Error 751, Line 3, Col 29, Line 3, Col 33, "Incomplete expression or invalid use of indexer syntax") ]