From 3beb7679a1735aaea5c590c0f2716cbc5e2b68b6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 12:29:27 +0000 Subject: [PATCH 01/12] Initial plan From 5ba3745171912ad94e2e5fbcc28a7f1023b8b451 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:01:49 +0000 Subject: [PATCH 02/12] Add --disableLanguageFeature CLI option with tests - Added TryParseFeature method to LanguageVersion to parse feature names from strings - Added disabledLanguageFeatures field to TcConfigBuilder to store disabled features - Added SupportsFeature method to TcConfigBuilder that checks both langVersion and disabled features - Added --disableLanguageFeature CLI option in CompilerOptions (repeatable) - Added error message for unrecognized feature names (error 3879) - Created comprehensive tests for the new functionality Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- src/Compiler/Driver/CompilerConfig.fs | 7 ++ src/Compiler/Driver/CompilerConfig.fsi | 4 + src/Compiler/Driver/CompilerOptions.fs | 15 +++ src/Compiler/FSComp.txt | 2 + src/Compiler/Facilities/LanguageFeatures.fs | 96 +++++++++++++++++++ src/Compiler/Facilities/LanguageFeatures.fsi | 3 + src/Compiler/xlf/FSComp.txt.cs.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.de.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.es.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.fr.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.it.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.ja.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.ko.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.pl.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.ru.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.tr.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 10 ++ src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 10 ++ .../fsc/disableLanguageFeature.fs | 69 +++++++++++++ .../FSharp.Compiler.ComponentTests.fsproj | 1 + 21 files changed, 327 insertions(+) create mode 100644 tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/disableLanguageFeature.fs diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index 5bd5c5266ce..f42b885298b 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -644,6 +644,8 @@ type TcConfigBuilder = mutable langVersion: LanguageVersion + mutable disabledLanguageFeatures: Set + mutable xmlDocInfoLoader: IXmlDocumentationInfoLoader option mutable exiter: Exiter @@ -836,6 +838,7 @@ type TcConfigBuilder = pathMap = PathMap.empty applyLineDirectives = true langVersion = LanguageVersion.Default + disabledLanguageFeatures = Set.empty implicitIncludeDir = implicitIncludeDir defaultFSharpBinariesDir = defaultFSharpBinariesDir reduceMemoryUsage = reduceMemoryUsage @@ -984,6 +987,10 @@ type TcConfigBuilder = WarnOn = ListSet.insert (=) n tcConfigB.diagnosticsOptions.WarnOn } + member tcConfigB.SupportsFeature(feature: LanguageFeature) = + tcConfigB.langVersion.SupportsFeature(feature) + && not (tcConfigB.disabledLanguageFeatures.Contains(feature)) + member tcConfigB.AddIncludePath(m, path, pathIncludedFrom) = let absolutePath = ComputeMakePathAbsolute pathIncludedFrom path diff --git a/src/Compiler/Driver/CompilerConfig.fsi b/src/Compiler/Driver/CompilerConfig.fsi index 646b4477be3..e21d0c07641 100644 --- a/src/Compiler/Driver/CompilerConfig.fsi +++ b/src/Compiler/Driver/CompilerConfig.fsi @@ -512,6 +512,8 @@ type TcConfigBuilder = mutable langVersion: LanguageVersion + mutable disabledLanguageFeatures: Set + mutable xmlDocInfoLoader: IXmlDocumentationInfoLoader option mutable exiter: Exiter @@ -548,6 +550,8 @@ type TcConfigBuilder = member TurnWarningOn: range * string -> unit + member SupportsFeature: LanguageFeature -> bool + member AddIncludePath: range * string * string -> unit member AddCompilerToolsByPath: string -> unit diff --git a/src/Compiler/Driver/CompilerOptions.fs b/src/Compiler/Driver/CompilerOptions.fs index a62dad75eac..217b107ceaf 100644 --- a/src/Compiler/Driver/CompilerOptions.fs +++ b/src/Compiler/Driver/CompilerOptions.fs @@ -1182,6 +1182,21 @@ let languageFlags tcConfigB = Some(FSComp.SR.optsSetLangVersion ()) ) + // -disableLanguageFeature: Disable a specific language feature by name (repeatable) + CompilerOption( + "disableLanguageFeature", + tagString, + OptionStringList(fun featureName -> + match LanguageVersion.TryParseFeature(featureName) with + | Some feature -> + tcConfigB.disabledLanguageFeatures <- tcConfigB.disabledLanguageFeatures.Add(feature) + | None -> + error (Error(FSComp.SR.optsUnrecognizedLanguageFeature featureName, rangeCmdArgs)) + ), + None, + Some(FSComp.SR.optsDisableLanguageFeature ()) + ) + CompilerOption( "checked", tagNone, diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 512e9b4dca7..4d0b5c2257d 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1570,6 +1570,8 @@ optsCheckNulls,"Enable nullness declarations and checks (%s by default)" fSharpBannerVersion,"%s for F# %s" optsGetLangVersions,"Display the allowed values for language version." optsSetLangVersion,"Specify language version such as 'latest' or 'preview'." +optsDisableLanguageFeature,"Disable a specific language feature by name." +3879,optsUnrecognizedLanguageFeature,"Unrecognized language feature name: '%s'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'." optsSupportedLangVersions,"Supported language versions:" optsStrictIndentation,"Override indentation rules implied by the language version (%s by default)" nativeResourceFormatError,"Stream does not begin with a null resource and is not in '.RES' format." diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index 4b032db713f..bdcd8a26930 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -422,6 +422,102 @@ type LanguageVersion(versionText) = | true, v -> versionToString v | _ -> invalidArg "feature" "Internal error: Unable to find feature." + /// Try to parse a feature name string to a LanguageFeature option + static member TryParseFeature(featureName: string) = + let normalized = featureName.Trim().ToLowerInvariant() + + match normalized with + | "singleunderscorepattern" -> Some LanguageFeature.SingleUnderscorePattern + | "wildcardinforloop" -> Some LanguageFeature.WildCardInForLoop + | "relaxwhitespace" -> Some LanguageFeature.RelaxWhitespace + | "relaxwhitespace2" -> Some LanguageFeature.RelaxWhitespace2 + | "strictindentation" -> Some LanguageFeature.StrictIndentation + | "nameof" -> Some LanguageFeature.NameOf + | "implicityield" -> Some LanguageFeature.ImplicitYield + | "opentypedeclaration" -> Some LanguageFeature.OpenTypeDeclaration + | "dotlessfloat32literal" -> Some LanguageFeature.DotlessFloat32Literal + | "packagemanagement" -> Some LanguageFeature.PackageManagement + | "fromendslicing" -> Some LanguageFeature.FromEndSlicing + | "fixedindexslice3d4d" -> Some LanguageFeature.FixedIndexSlice3d4d + | "andbang" -> Some LanguageFeature.AndBang + | "resumablestatemachines" -> Some LanguageFeature.ResumableStateMachines + | "nullableoptionalinterop" -> Some LanguageFeature.NullableOptionalInterop + | "defaultinterfacememberconsumption" -> Some LanguageFeature.DefaultInterfaceMemberConsumption + | "witnesspassing" -> Some LanguageFeature.WitnessPassing + | "additionaltypedirectedconversions" -> Some LanguageFeature.AdditionalTypeDirectedConversions + | "interfaceswithmultiplegenericinstantiation" -> Some LanguageFeature.InterfacesWithMultipleGenericInstantiation + | "stringinterpolation" -> Some LanguageFeature.StringInterpolation + | "overloadsforcustomoperations" -> Some LanguageFeature.OverloadsForCustomOperations + | "expandedmeasurables" -> Some LanguageFeature.ExpandedMeasurables + | "nullnesschecking" -> Some LanguageFeature.NullnessChecking + | "structactivepattern" -> Some LanguageFeature.StructActivePattern + | "printfbinaryformat" -> Some LanguageFeature.PrintfBinaryFormat + | "indexernotationwithoutdot" -> Some LanguageFeature.IndexerNotationWithoutDot + | "refcellnotationinformationals" -> Some LanguageFeature.RefCellNotationInformationals + | "usebindingvaluediscard" -> Some LanguageFeature.UseBindingValueDiscard + | "unionispropertiesvisible" -> Some LanguageFeature.UnionIsPropertiesVisible + | "nonvariablepatternstorightofaspatterns" -> Some LanguageFeature.NonVariablePatternsToRightOfAsPatterns + | "attributestorightofmodulekeyword" -> Some LanguageFeature.AttributesToRightOfModuleKeyword + | "mlcompatrevisions" -> Some LanguageFeature.MLCompatRevisions + | "betterexceptionprinting" -> Some LanguageFeature.BetterExceptionPrinting + | "delegatetypenameresolutionfix" -> Some LanguageFeature.DelegateTypeNameResolutionFix + | "reallylonglists" -> Some LanguageFeature.ReallyLongLists + | "errorondeprecatedrequirequalifiedaccess" -> Some LanguageFeature.ErrorOnDeprecatedRequireQualifiedAccess + | "requiredpropertiessupport" -> Some LanguageFeature.RequiredPropertiesSupport + | "initpropertiessupport" -> Some LanguageFeature.InitPropertiesSupport + | "lowercaseduwhenrequirequalifiedaccess" -> Some LanguageFeature.LowercaseDUWhenRequireQualifiedAccess + | "interfaceswithabstractstaticmembers" -> Some LanguageFeature.InterfacesWithAbstractStaticMembers + | "selftypeconstraints" -> Some LanguageFeature.SelfTypeConstraints + | "accessorfunctionshorthand" -> Some LanguageFeature.AccessorFunctionShorthand + | "matchnotallowedforunioncasewithnodata" -> Some LanguageFeature.MatchNotAllowedForUnionCaseWithNoData + | "csharpextensionattributenotrequired" -> Some LanguageFeature.CSharpExtensionAttributeNotRequired + | "errorfornonvirtualmembersoverrides" -> Some LanguageFeature.ErrorForNonVirtualMembersOverrides + | "warningwheninliningmethodimplnoinlinemarkedfunction" -> Some LanguageFeature.WarningWhenInliningMethodImplNoInlineMarkedFunction + | "escapedotnetformattablestrings" -> Some LanguageFeature.EscapeDotnetFormattableStrings + | "arithmeticinliterals" -> Some LanguageFeature.ArithmeticInLiterals + | "errorreportingonstaticclasses" -> Some LanguageFeature.ErrorReportingOnStaticClasses + | "trywithinseqexpression" -> Some LanguageFeature.TryWithInSeqExpression + | "warningwhencopyandupdaterecordchangesallfields" -> Some LanguageFeature.WarningWhenCopyAndUpdateRecordChangesAllFields + | "staticmembersininterfaces" -> Some LanguageFeature.StaticMembersInInterfaces + | "noninlineliteralsasprintfformat" -> Some LanguageFeature.NonInlineLiteralsAsPrintfFormat + | "nestedcopyandupdate" -> Some LanguageFeature.NestedCopyAndUpdate + | "extendedstringinterpolation" -> Some LanguageFeature.ExtendedStringInterpolation + | "warningwhenmultiplerecdtypechoice" -> Some LanguageFeature.WarningWhenMultipleRecdTypeChoice + | "improvedimpliedargumentnames" -> Some LanguageFeature.ImprovedImpliedArgumentNames + | "diagnosticforobjinference" -> Some LanguageFeature.DiagnosticForObjInference + | "constraintintersectiononflexibletypes" -> Some LanguageFeature.ConstraintIntersectionOnFlexibleTypes + | "staticletinrecordsdustemptypes" -> Some LanguageFeature.StaticLetInRecordsDusEmptyTypes + | "warningwhentailrecattributebutnontailrecusage" -> Some LanguageFeature.WarningWhenTailRecAttributeButNonTailRecUsage + | "unmanagedconstraintcsharpinterop" -> Some LanguageFeature.UnmanagedConstraintCsharpInterop + | "whilebang" -> Some LanguageFeature.WhileBang + | "reusesamefieldssinstructunions" -> Some LanguageFeature.ReuseSameFieldsInStructUnions + | "extendedfixedbindings" -> Some LanguageFeature.ExtendedFixedBindings + | "preferstringgetpinnablereference" -> Some LanguageFeature.PreferStringGetPinnableReference + | "preferextensionmethodoverplainproperty" -> Some LanguageFeature.PreferExtensionMethodOverPlainProperty + | "warningindexedpropertiesgetsetsametype" -> Some LanguageFeature.WarningIndexedPropertiesGetSetSameType + | "warningwhentailcallattrononrec" -> Some LanguageFeature.WarningWhenTailCallAttrOnNonRec + | "booleanreturningandreturntypedirectedpartialactivepattern" -> Some LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern + | "enforceattributetargets" -> Some LanguageFeature.EnforceAttributeTargets + | "lowerinterpolatedstringtoconcat" -> Some LanguageFeature.LowerInterpolatedStringToConcat + | "lowerintegralrangestofastloops" -> Some LanguageFeature.LowerIntegralRangesToFastLoops + | "allowaccessmodifierstautopropertiesgettersandsetters" -> Some LanguageFeature.AllowAccessModifiersToAutoPropertiesGettersAndSetters + | "lowersimplemappingsincomprehensionstofastloops" -> Some LanguageFeature.LowerSimpleMappingsInComprehensionsToFastLoops + | "parsedhashdirectiveargumentnonquotes" -> Some LanguageFeature.ParsedHashDirectiveArgumentNonQuotes + | "emptybodiedcomputationexpressions" -> Some LanguageFeature.EmptyBodiedComputationExpressions + | "allowobjectexpressionwithoutoverrides" -> Some LanguageFeature.AllowObjectExpressionWithoutOverrides + | "dontwarnunuppercaseidentifiersinbindingpatterns" -> Some LanguageFeature.DontWarnOnUppercaseIdentifiersInBindingPatterns + | "usetypesubsumptioncache" -> Some LanguageFeature.UseTypeSubsumptionCache + | "deprecateplaceswheresecanbemitted" -> Some LanguageFeature.DeprecatePlacesWhereSeqCanBeOmitted + | "supportvalueoptionsasoptionalparameters" -> Some LanguageFeature.SupportValueOptionsAsOptionalParameters + | "warnwhenunitpassedtoobjarg" -> Some LanguageFeature.WarnWhenUnitPassedToObjArg + | "usebangbindingvaluediscard" -> Some LanguageFeature.UseBangBindingValueDiscard + | "betteranonymousrecordparsing" -> Some LanguageFeature.BetterAnonymousRecordParsing + | "scopednowarn" -> Some LanguageFeature.ScopedNowarn + | "erroroninvaliddeclsintypedefinitions" -> Some LanguageFeature.ErrorOnInvalidDeclsInTypeDefinitions + | "allowtypedletuseandbang" -> Some LanguageFeature.AllowTypedLetUseAndBang + | "returnfromfinal" -> Some LanguageFeature.ReturnFromFinal + | _ -> None + override x.Equals(yobj: obj) = match yobj with | :? LanguageVersion as y -> x.SpecifiedVersion = y.SpecifiedVersion diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index 1217b83baf6..1fe10935b05 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -136,4 +136,7 @@ type LanguageVersion = /// Get a version string associated with the given feature. static member GetFeatureVersionString: feature: LanguageFeature -> string + /// Try to parse a feature name string to a LanguageFeature option + static member TryParseFeature: featureName: string -> LanguageFeature option + static member Default: LanguageVersion diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 244be90e142..d2def776c73 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -1027,6 +1027,11 @@ Compress interface and optimization data files ({0} by default) + + Disable a specific language feature by name. + Disable a specific language feature by name. + + Display the allowed values for language version. Zobrazí povolené hodnoty pro jazykovou verzi. @@ -1107,6 +1112,11 @@ Neplatná hodnota „{0}“ pro --interfacedata, platná hodnota je: none, file, compress. + + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Nerozpoznaná hodnota {0} pro parametr --langversion; seznam možností zobrazíte zadáním --langversion:? diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index d1b1782d093..d27bee9d3d0 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -1027,6 +1027,11 @@ Compress interface and optimization data files ({0} by default) + + Disable a specific language feature by name. + Disable a specific language feature by name. + + Display the allowed values for language version. Anzeigen der zulässigen Werte für die Sprachversion. @@ -1107,6 +1112,11 @@ Ungültiger Wert „{0}“ für --interfacedata. Gültige Werte sind: none, file, compress. + + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Unbekannter Wert "{0}" für "--langversion". Verwenden Sie "--langversion:?", um die vollständige Liste anzuzeigen. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index cd311cc7fc5..75e4afde129 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -1027,6 +1027,11 @@ Compress interface and optimization data files ({0} by default) + + Disable a specific language feature by name. + Disable a specific language feature by name. + + Display the allowed values for language version. Muestra los valores permitidos para la versión del lenguaje. @@ -1107,6 +1112,11 @@ Valor no válido '{0}' para --interfacedata; los valores válidos son: none, file, compress. + + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Valor no reconocido "{0}" para --langversion, use --langversion:? para una lista completa diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index e05e9ecdf6c..b2d7d88ec62 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -1027,6 +1027,11 @@ Compress interface and optimization data files ({0} by default) + + Disable a specific language feature by name. + Disable a specific language feature by name. + + Display the allowed values for language version. Affichez les valeurs autorisées pour la version du langage. @@ -1107,6 +1112,11 @@ Valeur non valide '{0}' pour --interfacedata. Les valeurs valides sont : none, file, compress. + + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Valeur non reconnue '{0}' pour --langversion use --langversion:? pour la liste complète diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index a25fd816046..19b3d68cd05 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -1027,6 +1027,11 @@ Compress interface and optimization data files ({0} by default) + + Disable a specific language feature by name. + Disable a specific language feature by name. + + Display the allowed values for language version. Visualizzare i valori consentiti per la versione della lingua. @@ -1107,6 +1112,11 @@ Valore non valido '{0}' per --interfacedata. Valori validi sono: none, file, compress. + + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Valore '{0}' non riconosciuto per --langversion. Per l'elenco completo usare --langversion:? diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 87b7d40df1e..0235f484aba 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -1027,6 +1027,11 @@ Compress interface and optimization data files ({0} by default) + + Disable a specific language feature by name. + Disable a specific language feature by name. + + Display the allowed values for language version. 言語バージョンで許可されている値を表示します。 @@ -1107,6 +1112,11 @@ --interfacedata の値 '{0}' が無効です。有効な値は none、file、compress です。 + + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list --langversion の値 '{0}' が認識されません。完全なリストについては、--langversion:? を使用してください diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index f2fe6e20f97..1288727a5a9 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -1027,6 +1027,11 @@ Compress interface and optimization data files ({0} by default) + + Disable a specific language feature by name. + Disable a specific language feature by name. + + Display the allowed values for language version. 언어 버전에 허용되는 값을 표시합니다. @@ -1107,6 +1112,11 @@ --interfacedata에 대한 '{0}' 값이 잘못되었습니다. 올바른 값은 none, file, compress입니다. + + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list 전체 목록에 대한 --langversion use --langversion:?의 인식할 수 없는 값 '{0}'입니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 23a194ff258..b290decae60 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -1027,6 +1027,11 @@ Compress interface and optimization data files ({0} by default) + + Disable a specific language feature by name. + Disable a specific language feature by name. + + Display the allowed values for language version. Wyświetl dozwolone wartości dla wersji językowej. @@ -1107,6 +1112,11 @@ Nieprawidłowa wartość „{0}” dla parametru --interfacedata, prawidłowa wartość to: none, file, compress. + + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Nierozpoznana wartość „{0}” dla parametru –langversion; podaj parametr –langversion:?, aby uzyskać pełną listę diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 503fc0f073f..09241c13e21 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -1027,6 +1027,11 @@ Compress interface and optimization data files ({0} by default) + + Disable a specific language feature by name. + Disable a specific language feature by name. + + Display the allowed values for language version. Exiba os valores permitidos para a versão do idioma. @@ -1107,6 +1112,11 @@ Valor inválido '{0}' para --interfacedata, o valor válido é: none, file, compact. + + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Valor não reconhecido '{0}' para --langversion use --langversion:? para a lista completa diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 7013fb0bc83..41e913c2084 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -1027,6 +1027,11 @@ Compress interface and optimization data files ({0} by default) + + Disable a specific language feature by name. + Disable a specific language feature by name. + + Display the allowed values for language version. Отображение допустимых значений для версии языка. @@ -1107,6 +1112,11 @@ Недопустимое значение "{0}" для --interfacedata. Допустимые значения: none, file, compress. + + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Не удалось распознать значение "{0}" для параметра --langversion. Для получения полного списка допустимых значений выполните команду use --langversion:? diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 49d2a295b45..b0d5ecf2c51 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -1027,6 +1027,11 @@ Compress interface and optimization data files ({0} by default) + + Disable a specific language feature by name. + Disable a specific language feature by name. + + Display the allowed values for language version. Dil sürümü için izin verilen değerleri görüntüleyin. @@ -1107,6 +1112,11 @@ --interfacedata için geçersiz '{0}' değeri, geçerli değerler: none, file, compress. + + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list --langversion için '{0}' değeri tanınmıyor. Tam liste için --langversion:? kullanın diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 3fc65eebc96..6e1e0dd5f23 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -1027,6 +1027,11 @@ Compress interface and optimization data files ({0} by default) + + Disable a specific language feature by name. + Disable a specific language feature by name. + + Display the allowed values for language version. 显示语言版本的允许值。 @@ -1107,6 +1112,11 @@ --interfacedata 的值 "{0}" 无效,有效值为: none、file、compress。 + + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list --langversion 的值“{0}”无法识别,使用 --langversion:? 获取完整列表。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 07fea0efd23..c35f53bbc76 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -1027,6 +1027,11 @@ Compress interface and optimization data files ({0} by default) + + Disable a specific language feature by name. + Disable a specific language feature by name. + + Display the allowed values for language version. 顯示語言版本的允許值。 @@ -1107,6 +1112,11 @@ --interfacedata 的 '{0}' 值無效,有效值為: none、file、compress。 + + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list 對 --langversion 為無法識別的值 '{0}',對完整清單使用 --langversion:? diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/disableLanguageFeature.fs b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/disableLanguageFeature.fs new file mode 100644 index 00000000000..d28f251970a --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/disableLanguageFeature.fs @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace CompilerOptions.Fsc + +open Xunit +open FSharp.Test +open FSharp.Test.Compiler + +module disableLanguageFeature = + + [] + let ``disableLanguageFeature with valid feature name should compile successfully``() = + FSharp """ +printfn "Hello, World" + """ + |> asExe + |> withOptions ["--disableLanguageFeature:NameOf"] + |> compile + |> shouldSucceed + |> ignore + + [] + let ``disableLanguageFeature should disable NameOf feature``() = + FSharp """ +let x = 5 +let name = nameof(x) + """ + |> asExe + |> withOptions ["--langversion:latest"; "--disableLanguageFeature:NameOf"] + |> compile + |> shouldFail + |> ignore + + [] + let ``disableLanguageFeature with invalid feature name should fail``() = + FSharp """ +printfn "Hello, World" + """ + |> asExe + |> withOptions ["--disableLanguageFeature:InvalidFeatureName"] + |> compile + |> shouldFail + |> withErrorCode 3879 + |> withDiagnosticMessageMatches "Unrecognized language feature name" + |> ignore + + [] + let ``disableLanguageFeature can be used multiple times``() = + FSharp """ +let x = 5 +let name = nameof(x) + """ + |> asExe + |> withOptions ["--langversion:latest"; "--disableLanguageFeature:NameOf"; "--disableLanguageFeature:StringInterpolation"] + |> compile + |> shouldFail + |> ignore + + [] + let ``disableLanguageFeature is case insensitive``() = + FSharp """ +let x = 5 +let name = nameof(x) + """ + |> asExe + |> withOptions ["--langversion:latest"; "--disableLanguageFeature:nameof"] + |> compile + |> shouldFail + |> ignore diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 8f5ace7aade..e7b3f4ddee9 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -299,6 +299,7 @@ + From 7f3bcf898638a33f3aa7a6038a976782900acf91 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:08:44 +0000 Subject: [PATCH 03/12] Apply code formatting and update release notes - Applied fantomas formatting to modified files - Added release notes entry for the new --disableLanguageFeature CLI switch Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- docs/release-notes/.FSharp.Compiler.Service/11.0.0.md | 1 + src/Compiler/Driver/CompilerConfig.fs | 2 +- src/Compiler/Driver/CompilerOptions.fs | 7 ++----- src/Compiler/Facilities/LanguageFeatures.fs | 8 +++++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.0.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.0.md index 4d9542cf94e..6c5754cf7aa 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.0.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.0.md @@ -20,6 +20,7 @@ * Add FSharpCodeCompletionOptions ([PR #19030](https://github.com/dotnet/fsharp/pull/19030)) * Type checker: recover on checking binding parameter constraints ([#19046](https://github.com/dotnet/fsharp/pull/19046)) * Debugger: provide breakpoint ranges for short lambdas ([#19067](https://github.com/dotnet/fsharp/pull/19067)) +* Add `--disableLanguageFeature` command line switch to selectively disable specific F# language features ([PR #NNNNN](https://github.com/dotnet/fsharp/pull/NNNNN)) ### Changed diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index f42b885298b..6d8b4e5c4fa 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -988,7 +988,7 @@ type TcConfigBuilder = } member tcConfigB.SupportsFeature(feature: LanguageFeature) = - tcConfigB.langVersion.SupportsFeature(feature) + tcConfigB.langVersion.SupportsFeature(feature) && not (tcConfigB.disabledLanguageFeatures.Contains(feature)) member tcConfigB.AddIncludePath(m, path, pathIncludedFrom) = diff --git a/src/Compiler/Driver/CompilerOptions.fs b/src/Compiler/Driver/CompilerOptions.fs index 217b107ceaf..ca149a546ac 100644 --- a/src/Compiler/Driver/CompilerOptions.fs +++ b/src/Compiler/Driver/CompilerOptions.fs @@ -1188,11 +1188,8 @@ let languageFlags tcConfigB = tagString, OptionStringList(fun featureName -> match LanguageVersion.TryParseFeature(featureName) with - | Some feature -> - tcConfigB.disabledLanguageFeatures <- tcConfigB.disabledLanguageFeatures.Add(feature) - | None -> - error (Error(FSComp.SR.optsUnrecognizedLanguageFeature featureName, rangeCmdArgs)) - ), + | Some feature -> tcConfigB.disabledLanguageFeatures <- tcConfigB.disabledLanguageFeatures.Add(feature) + | None -> error (Error(FSComp.SR.optsUnrecognizedLanguageFeature featureName, rangeCmdArgs))), None, Some(FSComp.SR.optsDisableLanguageFeature ()) ) diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index bdcd8a26930..d88504b8cf6 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -425,7 +425,7 @@ type LanguageVersion(versionText) = /// Try to parse a feature name string to a LanguageFeature option static member TryParseFeature(featureName: string) = let normalized = featureName.Trim().ToLowerInvariant() - + match normalized with | "singleunderscorepattern" -> Some LanguageFeature.SingleUnderscorePattern | "wildcardinforloop" -> Some LanguageFeature.WildCardInForLoop @@ -496,11 +496,13 @@ type LanguageVersion(versionText) = | "preferextensionmethodoverplainproperty" -> Some LanguageFeature.PreferExtensionMethodOverPlainProperty | "warningindexedpropertiesgetsetsametype" -> Some LanguageFeature.WarningIndexedPropertiesGetSetSameType | "warningwhentailcallattrononrec" -> Some LanguageFeature.WarningWhenTailCallAttrOnNonRec - | "booleanreturningandreturntypedirectedpartialactivepattern" -> Some LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern + | "booleanreturningandreturntypedirectedpartialactivepattern" -> + Some LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern | "enforceattributetargets" -> Some LanguageFeature.EnforceAttributeTargets | "lowerinterpolatedstringtoconcat" -> Some LanguageFeature.LowerInterpolatedStringToConcat | "lowerintegralrangestofastloops" -> Some LanguageFeature.LowerIntegralRangesToFastLoops - | "allowaccessmodifierstautopropertiesgettersandsetters" -> Some LanguageFeature.AllowAccessModifiersToAutoPropertiesGettersAndSetters + | "allowaccessmodifierstautopropertiesgettersandsetters" -> + Some LanguageFeature.AllowAccessModifiersToAutoPropertiesGettersAndSetters | "lowersimplemappingsincomprehensionstofastloops" -> Some LanguageFeature.LowerSimpleMappingsInComprehensionsToFastLoops | "parsedhashdirectiveargumentnonquotes" -> Some LanguageFeature.ParsedHashDirectiveArgumentNonQuotes | "emptybodiedcomputationexpressions" -> Some LanguageFeature.EmptyBodiedComputationExpressions From 7dacc206ad10dd61434331a286da65697d453845 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:19:41 +0000 Subject: [PATCH 04/12] Fix --disableLanguageFeature to work with LanguageVersion directly - Modified LanguageVersion to hold disabled features and check them in SupportsFeature - Added SetDisabledFeatures method to LanguageVersion - Updated both langversion and disableLanguageFeature options to call SetDisabledFeatures - This ensures disabled features are respected regardless of option order - Applied code formatting Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- src/Compiler/Driver/CompilerConfig.fs | 1 - src/Compiler/Driver/CompilerOptions.fs | 8 ++++++-- src/Compiler/Facilities/LanguageFeatures.fs | 14 +++++++++++--- src/Compiler/Facilities/LanguageFeatures.fsi | 3 +++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index 6d8b4e5c4fa..e833fb2c9de 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -989,7 +989,6 @@ type TcConfigBuilder = member tcConfigB.SupportsFeature(feature: LanguageFeature) = tcConfigB.langVersion.SupportsFeature(feature) - && not (tcConfigB.disabledLanguageFeatures.Contains(feature)) member tcConfigB.AddIncludePath(m, path, pathIncludedFrom) = let absolutePath = ComputeMakePathAbsolute pathIncludedFrom path diff --git a/src/Compiler/Driver/CompilerOptions.fs b/src/Compiler/Driver/CompilerOptions.fs index ca149a546ac..b69a715e832 100644 --- a/src/Compiler/Driver/CompilerOptions.fs +++ b/src/Compiler/Driver/CompilerOptions.fs @@ -1177,7 +1177,9 @@ let languageFlags tcConfigB = CompilerOption( "langversion", tagLangVersionValues, - OptionString(fun switch -> tcConfigB.langVersion <- setLanguageVersion switch), + OptionString(fun switch -> + tcConfigB.langVersion <- setLanguageVersion switch + tcConfigB.langVersion.SetDisabledFeatures(tcConfigB.disabledLanguageFeatures)), None, Some(FSComp.SR.optsSetLangVersion ()) ) @@ -1188,7 +1190,9 @@ let languageFlags tcConfigB = tagString, OptionStringList(fun featureName -> match LanguageVersion.TryParseFeature(featureName) with - | Some feature -> tcConfigB.disabledLanguageFeatures <- tcConfigB.disabledLanguageFeatures.Add(feature) + | Some feature -> + tcConfigB.disabledLanguageFeatures <- tcConfigB.disabledLanguageFeatures.Add(feature) + tcConfigB.langVersion.SetDisabledFeatures(tcConfigB.disabledLanguageFeatures) | None -> error (Error(FSComp.SR.optsUnrecognizedLanguageFeature featureName, rangeCmdArgs))), None, Some(FSComp.SR.optsDisableLanguageFeature ()) diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index d88504b8cf6..de1ab74b888 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -279,11 +279,19 @@ type LanguageVersion(versionText) = let specifiedString = versionToString specified + let mutable disabledFeatures: Set = Set.empty + /// Check if this feature is supported by the selected langversion member _.SupportsFeature featureId = - match features.TryGetValue featureId with - | true, v -> v <= specified - | false, _ -> false + if disabledFeatures.Contains featureId then + false + else + match features.TryGetValue featureId with + | true, v -> v <= specified + | false, _ -> false + + /// Set the disabled features for this language version + member _.SetDisabledFeatures(disabled: Set) = disabledFeatures <- disabled /// Has preview been explicitly specified member _.IsExplicitlySpecifiedAs50OrBefore() = diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index 1fe10935b05..679c41b89c1 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -115,6 +115,9 @@ type LanguageVersion = /// Does the selected LanguageVersion support the specified feature member SupportsFeature: LanguageFeature -> bool + /// Set the disabled features for this language version + member SetDisabledFeatures: Set -> unit + /// Get the list of valid versions static member ValidVersions: string[] From 2852d9cc9d4a06ff0c016b669d2fc7e9247acfcd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 15:05:03 +0000 Subject: [PATCH 05/12] Remove unused SupportsFeature method from TcConfigBuilder As requested, removed the SupportsFeature method from TcConfigBuilder since it's not used anywhere and is redundant - callers can directly use langVersion.SupportsFeature() Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- src/Compiler/Driver/CompilerConfig.fs | 3 --- src/Compiler/Driver/CompilerConfig.fsi | 2 -- 2 files changed, 5 deletions(-) diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index e833fb2c9de..15fe1522fd4 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -987,9 +987,6 @@ type TcConfigBuilder = WarnOn = ListSet.insert (=) n tcConfigB.diagnosticsOptions.WarnOn } - member tcConfigB.SupportsFeature(feature: LanguageFeature) = - tcConfigB.langVersion.SupportsFeature(feature) - member tcConfigB.AddIncludePath(m, path, pathIncludedFrom) = let absolutePath = ComputeMakePathAbsolute pathIncludedFrom path diff --git a/src/Compiler/Driver/CompilerConfig.fsi b/src/Compiler/Driver/CompilerConfig.fsi index e21d0c07641..162228bcf96 100644 --- a/src/Compiler/Driver/CompilerConfig.fsi +++ b/src/Compiler/Driver/CompilerConfig.fsi @@ -550,8 +550,6 @@ type TcConfigBuilder = member TurnWarningOn: range * string -> unit - member SupportsFeature: LanguageFeature -> bool - member AddIncludePath: range * string * string -> unit member AddCompilerToolsByPath: string -> unit From cc299237c46da4bee7a03ee86838e71ccab269cf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 15:29:59 +0000 Subject: [PATCH 06/12] Refactor to use immutable LanguageVersion with reflection-based feature parsing - Changed LanguageVersion to use immutable array of disabled features instead of mutable set - Added optional constructor parameter for disabled features array - Added WithDisabledFeatures method that returns a new LanguageVersion instance - Replaced manual feature name mapping with reflection-based TryParseFeature using BindingFlags.NonPublic - Updated CompilerOptions to use immutable pattern with Array.append - Changed disabledLanguageFeatures in TcConfigBuilder from Set to array - Updated tests to use typecheck instead of compile and assert exact error codes - Applied code formatting Addresses feedback from @T-Gro about making the design immutable and using reflection. Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- src/Compiler/Driver/CompilerConfig.fs | 4 +- src/Compiler/Driver/CompilerConfig.fsi | 2 +- src/Compiler/Driver/CompilerOptions.fs | 9 +- src/Compiler/Facilities/LanguageFeatures.fs | 116 +++--------------- src/Compiler/Facilities/LanguageFeatures.fsi | 6 +- .../fsc/disableLanguageFeature.fs | 21 ++-- 6 files changed, 36 insertions(+), 122 deletions(-) diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index 15fe1522fd4..27dc2b8ae8c 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -644,7 +644,7 @@ type TcConfigBuilder = mutable langVersion: LanguageVersion - mutable disabledLanguageFeatures: Set + mutable disabledLanguageFeatures: LanguageFeature array mutable xmlDocInfoLoader: IXmlDocumentationInfoLoader option @@ -838,7 +838,7 @@ type TcConfigBuilder = pathMap = PathMap.empty applyLineDirectives = true langVersion = LanguageVersion.Default - disabledLanguageFeatures = Set.empty + disabledLanguageFeatures = [||] implicitIncludeDir = implicitIncludeDir defaultFSharpBinariesDir = defaultFSharpBinariesDir reduceMemoryUsage = reduceMemoryUsage diff --git a/src/Compiler/Driver/CompilerConfig.fsi b/src/Compiler/Driver/CompilerConfig.fsi index 162228bcf96..d741c8d9832 100644 --- a/src/Compiler/Driver/CompilerConfig.fsi +++ b/src/Compiler/Driver/CompilerConfig.fsi @@ -512,7 +512,7 @@ type TcConfigBuilder = mutable langVersion: LanguageVersion - mutable disabledLanguageFeatures: Set + mutable disabledLanguageFeatures: LanguageFeature array mutable xmlDocInfoLoader: IXmlDocumentationInfoLoader option diff --git a/src/Compiler/Driver/CompilerOptions.fs b/src/Compiler/Driver/CompilerOptions.fs index b69a715e832..84e8dc798b5 100644 --- a/src/Compiler/Driver/CompilerOptions.fs +++ b/src/Compiler/Driver/CompilerOptions.fs @@ -1178,8 +1178,9 @@ let languageFlags tcConfigB = "langversion", tagLangVersionValues, OptionString(fun switch -> - tcConfigB.langVersion <- setLanguageVersion switch - tcConfigB.langVersion.SetDisabledFeatures(tcConfigB.disabledLanguageFeatures)), + let newVersion = setLanguageVersion switch + // Preserve disabled features when updating version + tcConfigB.langVersion <- newVersion.WithDisabledFeatures(tcConfigB.disabledLanguageFeatures)), None, Some(FSComp.SR.optsSetLangVersion ()) ) @@ -1191,8 +1192,8 @@ let languageFlags tcConfigB = OptionStringList(fun featureName -> match LanguageVersion.TryParseFeature(featureName) with | Some feature -> - tcConfigB.disabledLanguageFeatures <- tcConfigB.disabledLanguageFeatures.Add(feature) - tcConfigB.langVersion.SetDisabledFeatures(tcConfigB.disabledLanguageFeatures) + tcConfigB.disabledLanguageFeatures <- Array.append tcConfigB.disabledLanguageFeatures [| feature |] + tcConfigB.langVersion <- tcConfigB.langVersion.WithDisabledFeatures(tcConfigB.disabledLanguageFeatures) | None -> error (Error(FSComp.SR.optsUnrecognizedLanguageFeature featureName, rangeCmdArgs))), None, Some(FSComp.SR.optsDisableLanguageFeature ()) diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index de1ab74b888..cd3e5cf7bb7 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -107,7 +107,7 @@ type LanguageFeature = | ReturnFromFinal /// LanguageVersion management -type LanguageVersion(versionText) = +type LanguageVersion(versionText, ?disabledFeaturesArray: LanguageFeature array) = // When we increment language versions here preview is higher than current RTM version static let languageVersion46 = 4.6m @@ -279,19 +279,19 @@ type LanguageVersion(versionText) = let specifiedString = versionToString specified - let mutable disabledFeatures: Set = Set.empty + let disabledFeatures: LanguageFeature array = defaultArg disabledFeaturesArray [||] /// Check if this feature is supported by the selected langversion member _.SupportsFeature featureId = - if disabledFeatures.Contains featureId then + if Array.contains featureId disabledFeatures then false else match features.TryGetValue featureId with | true, v -> v <= specified | false, _ -> false - /// Set the disabled features for this language version - member _.SetDisabledFeatures(disabled: Set) = disabledFeatures <- disabled + /// Create a new LanguageVersion with updated disabled features + member _.WithDisabledFeatures(disabled: LanguageFeature array) = LanguageVersion(versionText, disabled) /// Has preview been explicitly specified member _.IsExplicitlySpecifiedAs50OrBefore() = @@ -430,103 +430,17 @@ type LanguageVersion(versionText) = | true, v -> versionToString v | _ -> invalidArg "feature" "Internal error: Unable to find feature." - /// Try to parse a feature name string to a LanguageFeature option + /// Try to parse a feature name string to a LanguageFeature option using reflection static member TryParseFeature(featureName: string) = - let normalized = featureName.Trim().ToLowerInvariant() - - match normalized with - | "singleunderscorepattern" -> Some LanguageFeature.SingleUnderscorePattern - | "wildcardinforloop" -> Some LanguageFeature.WildCardInForLoop - | "relaxwhitespace" -> Some LanguageFeature.RelaxWhitespace - | "relaxwhitespace2" -> Some LanguageFeature.RelaxWhitespace2 - | "strictindentation" -> Some LanguageFeature.StrictIndentation - | "nameof" -> Some LanguageFeature.NameOf - | "implicityield" -> Some LanguageFeature.ImplicitYield - | "opentypedeclaration" -> Some LanguageFeature.OpenTypeDeclaration - | "dotlessfloat32literal" -> Some LanguageFeature.DotlessFloat32Literal - | "packagemanagement" -> Some LanguageFeature.PackageManagement - | "fromendslicing" -> Some LanguageFeature.FromEndSlicing - | "fixedindexslice3d4d" -> Some LanguageFeature.FixedIndexSlice3d4d - | "andbang" -> Some LanguageFeature.AndBang - | "resumablestatemachines" -> Some LanguageFeature.ResumableStateMachines - | "nullableoptionalinterop" -> Some LanguageFeature.NullableOptionalInterop - | "defaultinterfacememberconsumption" -> Some LanguageFeature.DefaultInterfaceMemberConsumption - | "witnesspassing" -> Some LanguageFeature.WitnessPassing - | "additionaltypedirectedconversions" -> Some LanguageFeature.AdditionalTypeDirectedConversions - | "interfaceswithmultiplegenericinstantiation" -> Some LanguageFeature.InterfacesWithMultipleGenericInstantiation - | "stringinterpolation" -> Some LanguageFeature.StringInterpolation - | "overloadsforcustomoperations" -> Some LanguageFeature.OverloadsForCustomOperations - | "expandedmeasurables" -> Some LanguageFeature.ExpandedMeasurables - | "nullnesschecking" -> Some LanguageFeature.NullnessChecking - | "structactivepattern" -> Some LanguageFeature.StructActivePattern - | "printfbinaryformat" -> Some LanguageFeature.PrintfBinaryFormat - | "indexernotationwithoutdot" -> Some LanguageFeature.IndexerNotationWithoutDot - | "refcellnotationinformationals" -> Some LanguageFeature.RefCellNotationInformationals - | "usebindingvaluediscard" -> Some LanguageFeature.UseBindingValueDiscard - | "unionispropertiesvisible" -> Some LanguageFeature.UnionIsPropertiesVisible - | "nonvariablepatternstorightofaspatterns" -> Some LanguageFeature.NonVariablePatternsToRightOfAsPatterns - | "attributestorightofmodulekeyword" -> Some LanguageFeature.AttributesToRightOfModuleKeyword - | "mlcompatrevisions" -> Some LanguageFeature.MLCompatRevisions - | "betterexceptionprinting" -> Some LanguageFeature.BetterExceptionPrinting - | "delegatetypenameresolutionfix" -> Some LanguageFeature.DelegateTypeNameResolutionFix - | "reallylonglists" -> Some LanguageFeature.ReallyLongLists - | "errorondeprecatedrequirequalifiedaccess" -> Some LanguageFeature.ErrorOnDeprecatedRequireQualifiedAccess - | "requiredpropertiessupport" -> Some LanguageFeature.RequiredPropertiesSupport - | "initpropertiessupport" -> Some LanguageFeature.InitPropertiesSupport - | "lowercaseduwhenrequirequalifiedaccess" -> Some LanguageFeature.LowercaseDUWhenRequireQualifiedAccess - | "interfaceswithabstractstaticmembers" -> Some LanguageFeature.InterfacesWithAbstractStaticMembers - | "selftypeconstraints" -> Some LanguageFeature.SelfTypeConstraints - | "accessorfunctionshorthand" -> Some LanguageFeature.AccessorFunctionShorthand - | "matchnotallowedforunioncasewithnodata" -> Some LanguageFeature.MatchNotAllowedForUnionCaseWithNoData - | "csharpextensionattributenotrequired" -> Some LanguageFeature.CSharpExtensionAttributeNotRequired - | "errorfornonvirtualmembersoverrides" -> Some LanguageFeature.ErrorForNonVirtualMembersOverrides - | "warningwheninliningmethodimplnoinlinemarkedfunction" -> Some LanguageFeature.WarningWhenInliningMethodImplNoInlineMarkedFunction - | "escapedotnetformattablestrings" -> Some LanguageFeature.EscapeDotnetFormattableStrings - | "arithmeticinliterals" -> Some LanguageFeature.ArithmeticInLiterals - | "errorreportingonstaticclasses" -> Some LanguageFeature.ErrorReportingOnStaticClasses - | "trywithinseqexpression" -> Some LanguageFeature.TryWithInSeqExpression - | "warningwhencopyandupdaterecordchangesallfields" -> Some LanguageFeature.WarningWhenCopyAndUpdateRecordChangesAllFields - | "staticmembersininterfaces" -> Some LanguageFeature.StaticMembersInInterfaces - | "noninlineliteralsasprintfformat" -> Some LanguageFeature.NonInlineLiteralsAsPrintfFormat - | "nestedcopyandupdate" -> Some LanguageFeature.NestedCopyAndUpdate - | "extendedstringinterpolation" -> Some LanguageFeature.ExtendedStringInterpolation - | "warningwhenmultiplerecdtypechoice" -> Some LanguageFeature.WarningWhenMultipleRecdTypeChoice - | "improvedimpliedargumentnames" -> Some LanguageFeature.ImprovedImpliedArgumentNames - | "diagnosticforobjinference" -> Some LanguageFeature.DiagnosticForObjInference - | "constraintintersectiononflexibletypes" -> Some LanguageFeature.ConstraintIntersectionOnFlexibleTypes - | "staticletinrecordsdustemptypes" -> Some LanguageFeature.StaticLetInRecordsDusEmptyTypes - | "warningwhentailrecattributebutnontailrecusage" -> Some LanguageFeature.WarningWhenTailRecAttributeButNonTailRecUsage - | "unmanagedconstraintcsharpinterop" -> Some LanguageFeature.UnmanagedConstraintCsharpInterop - | "whilebang" -> Some LanguageFeature.WhileBang - | "reusesamefieldssinstructunions" -> Some LanguageFeature.ReuseSameFieldsInStructUnions - | "extendedfixedbindings" -> Some LanguageFeature.ExtendedFixedBindings - | "preferstringgetpinnablereference" -> Some LanguageFeature.PreferStringGetPinnableReference - | "preferextensionmethodoverplainproperty" -> Some LanguageFeature.PreferExtensionMethodOverPlainProperty - | "warningindexedpropertiesgetsetsametype" -> Some LanguageFeature.WarningIndexedPropertiesGetSetSameType - | "warningwhentailcallattrononrec" -> Some LanguageFeature.WarningWhenTailCallAttrOnNonRec - | "booleanreturningandreturntypedirectedpartialactivepattern" -> - Some LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern - | "enforceattributetargets" -> Some LanguageFeature.EnforceAttributeTargets - | "lowerinterpolatedstringtoconcat" -> Some LanguageFeature.LowerInterpolatedStringToConcat - | "lowerintegralrangestofastloops" -> Some LanguageFeature.LowerIntegralRangesToFastLoops - | "allowaccessmodifierstautopropertiesgettersandsetters" -> - Some LanguageFeature.AllowAccessModifiersToAutoPropertiesGettersAndSetters - | "lowersimplemappingsincomprehensionstofastloops" -> Some LanguageFeature.LowerSimpleMappingsInComprehensionsToFastLoops - | "parsedhashdirectiveargumentnonquotes" -> Some LanguageFeature.ParsedHashDirectiveArgumentNonQuotes - | "emptybodiedcomputationexpressions" -> Some LanguageFeature.EmptyBodiedComputationExpressions - | "allowobjectexpressionwithoutoverrides" -> Some LanguageFeature.AllowObjectExpressionWithoutOverrides - | "dontwarnunuppercaseidentifiersinbindingpatterns" -> Some LanguageFeature.DontWarnOnUppercaseIdentifiersInBindingPatterns - | "usetypesubsumptioncache" -> Some LanguageFeature.UseTypeSubsumptionCache - | "deprecateplaceswheresecanbemitted" -> Some LanguageFeature.DeprecatePlacesWhereSeqCanBeOmitted - | "supportvalueoptionsasoptionalparameters" -> Some LanguageFeature.SupportValueOptionsAsOptionalParameters - | "warnwhenunitpassedtoobjarg" -> Some LanguageFeature.WarnWhenUnitPassedToObjArg - | "usebangbindingvaluediscard" -> Some LanguageFeature.UseBangBindingValueDiscard - | "betteranonymousrecordparsing" -> Some LanguageFeature.BetterAnonymousRecordParsing - | "scopednowarn" -> Some LanguageFeature.ScopedNowarn - | "erroroninvaliddeclsintypedefinitions" -> Some LanguageFeature.ErrorOnInvalidDeclsInTypeDefinitions - | "allowtypedletuseandbang" -> Some LanguageFeature.AllowTypedLetUseAndBang - | "returnfromfinal" -> Some LanguageFeature.ReturnFromFinal - | _ -> None + let normalized = featureName.Trim() + + Microsoft.FSharp.Reflection.FSharpType.GetUnionCases( + typeof, + System.Reflection.BindingFlags.Public + ||| System.Reflection.BindingFlags.NonPublic + ) + |> Array.tryFind (fun case -> System.String.Equals(case.Name, normalized, System.StringComparison.OrdinalIgnoreCase)) + |> Option.map (fun case -> Microsoft.FSharp.Reflection.FSharpValue.MakeUnion(case, [||]) :?> LanguageFeature) override x.Equals(yobj: obj) = match yobj with diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index 679c41b89c1..74f52b9fbb6 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -101,7 +101,7 @@ type LanguageFeature = type LanguageVersion = /// Create a LanguageVersion management object - new: string -> LanguageVersion + new: string * ?disabledFeaturesArray: LanguageFeature array -> LanguageVersion /// Get the list of valid versions static member ContainsVersion: string -> bool @@ -115,8 +115,8 @@ type LanguageVersion = /// Does the selected LanguageVersion support the specified feature member SupportsFeature: LanguageFeature -> bool - /// Set the disabled features for this language version - member SetDisabledFeatures: Set -> unit + /// Create a new LanguageVersion with updated disabled features + member WithDisabledFeatures: LanguageFeature array -> LanguageVersion /// Get the list of valid versions static member ValidVersions: string[] diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/disableLanguageFeature.fs b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/disableLanguageFeature.fs index d28f251970a..8d91d347b83 100644 --- a/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/disableLanguageFeature.fs +++ b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/disableLanguageFeature.fs @@ -9,13 +9,12 @@ open FSharp.Test.Compiler module disableLanguageFeature = [] - let ``disableLanguageFeature with valid feature name should compile successfully``() = + let ``disableLanguageFeature with valid feature name should typecheck successfully``() = FSharp """ printfn "Hello, World" """ - |> asExe |> withOptions ["--disableLanguageFeature:NameOf"] - |> compile + |> typecheck |> shouldSucceed |> ignore @@ -25,10 +24,11 @@ printfn "Hello, World" let x = 5 let name = nameof(x) """ - |> asExe |> withOptions ["--langversion:latest"; "--disableLanguageFeature:NameOf"] - |> compile + |> typecheck |> shouldFail + |> withErrorCode 39 + |> withDiagnosticMessageMatches "The value or constructor 'nameof' is not defined" |> ignore [] @@ -36,9 +36,8 @@ let name = nameof(x) FSharp """ printfn "Hello, World" """ - |> asExe |> withOptions ["--disableLanguageFeature:InvalidFeatureName"] - |> compile + |> typecheck |> shouldFail |> withErrorCode 3879 |> withDiagnosticMessageMatches "Unrecognized language feature name" @@ -50,10 +49,10 @@ printfn "Hello, World" let x = 5 let name = nameof(x) """ - |> asExe |> withOptions ["--langversion:latest"; "--disableLanguageFeature:NameOf"; "--disableLanguageFeature:StringInterpolation"] - |> compile + |> typecheck |> shouldFail + |> withErrorCode 39 |> ignore [] @@ -62,8 +61,8 @@ let name = nameof(x) let x = 5 let name = nameof(x) """ - |> asExe |> withOptions ["--langversion:latest"; "--disableLanguageFeature:nameof"] - |> compile + |> typecheck |> shouldFail + |> withErrorCode 39 |> ignore From e818424c1161487ecd4f55827b48ca0e696f33f0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 16:59:43 +0000 Subject: [PATCH 07/12] Fix null handling and use Set for disabledLanguageFeatures - Added null check in TryParseFeature using Option.bind before downcasting - Changed disabledLanguageFeatures from array to Set in CompilerConfig (better semantics) - Updated CompilerOptions to use Set.add and convert to array when calling WithDisabledFeatures - Applied code formatting Addresses comments from @T-Gro about null handling and using Set in the builder. Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- src/Compiler/Driver/CompilerConfig.fs | 4 ++-- src/Compiler/Driver/CompilerConfig.fsi | 2 +- src/Compiler/Driver/CompilerOptions.fs | 6 +++--- src/Compiler/Facilities/LanguageFeatures.fs | 8 +++++++- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs index 27dc2b8ae8c..15fe1522fd4 100644 --- a/src/Compiler/Driver/CompilerConfig.fs +++ b/src/Compiler/Driver/CompilerConfig.fs @@ -644,7 +644,7 @@ type TcConfigBuilder = mutable langVersion: LanguageVersion - mutable disabledLanguageFeatures: LanguageFeature array + mutable disabledLanguageFeatures: Set mutable xmlDocInfoLoader: IXmlDocumentationInfoLoader option @@ -838,7 +838,7 @@ type TcConfigBuilder = pathMap = PathMap.empty applyLineDirectives = true langVersion = LanguageVersion.Default - disabledLanguageFeatures = [||] + disabledLanguageFeatures = Set.empty implicitIncludeDir = implicitIncludeDir defaultFSharpBinariesDir = defaultFSharpBinariesDir reduceMemoryUsage = reduceMemoryUsage diff --git a/src/Compiler/Driver/CompilerConfig.fsi b/src/Compiler/Driver/CompilerConfig.fsi index d741c8d9832..162228bcf96 100644 --- a/src/Compiler/Driver/CompilerConfig.fsi +++ b/src/Compiler/Driver/CompilerConfig.fsi @@ -512,7 +512,7 @@ type TcConfigBuilder = mutable langVersion: LanguageVersion - mutable disabledLanguageFeatures: LanguageFeature array + mutable disabledLanguageFeatures: Set mutable xmlDocInfoLoader: IXmlDocumentationInfoLoader option diff --git a/src/Compiler/Driver/CompilerOptions.fs b/src/Compiler/Driver/CompilerOptions.fs index 84e8dc798b5..ef6c659afa5 100644 --- a/src/Compiler/Driver/CompilerOptions.fs +++ b/src/Compiler/Driver/CompilerOptions.fs @@ -1180,7 +1180,7 @@ let languageFlags tcConfigB = OptionString(fun switch -> let newVersion = setLanguageVersion switch // Preserve disabled features when updating version - tcConfigB.langVersion <- newVersion.WithDisabledFeatures(tcConfigB.disabledLanguageFeatures)), + tcConfigB.langVersion <- newVersion.WithDisabledFeatures(Set.toArray tcConfigB.disabledLanguageFeatures)), None, Some(FSComp.SR.optsSetLangVersion ()) ) @@ -1192,8 +1192,8 @@ let languageFlags tcConfigB = OptionStringList(fun featureName -> match LanguageVersion.TryParseFeature(featureName) with | Some feature -> - tcConfigB.disabledLanguageFeatures <- Array.append tcConfigB.disabledLanguageFeatures [| feature |] - tcConfigB.langVersion <- tcConfigB.langVersion.WithDisabledFeatures(tcConfigB.disabledLanguageFeatures) + tcConfigB.disabledLanguageFeatures <- Set.add feature tcConfigB.disabledLanguageFeatures + tcConfigB.langVersion <- tcConfigB.langVersion.WithDisabledFeatures(Set.toArray tcConfigB.disabledLanguageFeatures) | None -> error (Error(FSComp.SR.optsUnrecognizedLanguageFeature featureName, rangeCmdArgs))), None, Some(FSComp.SR.optsDisableLanguageFeature ()) diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index cd3e5cf7bb7..ccd7df7647d 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -440,7 +440,13 @@ type LanguageVersion(versionText, ?disabledFeaturesArray: LanguageFeature array) ||| System.Reflection.BindingFlags.NonPublic ) |> Array.tryFind (fun case -> System.String.Equals(case.Name, normalized, System.StringComparison.OrdinalIgnoreCase)) - |> Option.map (fun case -> Microsoft.FSharp.Reflection.FSharpValue.MakeUnion(case, [||]) :?> LanguageFeature) + |> Option.bind (fun case -> + let union = Microsoft.FSharp.Reflection.FSharpValue.MakeUnion(case, [||]) + + if isNull union then + None + else + Some(union :?> LanguageFeature)) override x.Equals(yobj: obj) = match yobj with From 7c0dc12c93db0ca8bd50c7c61e12f4208d07d3df Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 17:04:02 +0000 Subject: [PATCH 08/12] Update help baseline with --disableLanguageFeature option Updated compiler_help_output.bsl to include the new --disableLanguageFeature CLI option in help output. Addresses comment from @T-Gro about updating help tests. Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- .../CompilerOptions/fsc/misc/compiler_help_output.bsl | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/misc/compiler_help_output.bsl b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/misc/compiler_help_output.bsl index beafa217722..92f2b0ac5d4 100644 --- a/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/misc/compiler_help_output.bsl +++ b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/misc/compiler_help_output.bsl @@ -80,6 +80,7 @@ Copyright (c) Microsoft Corporation. All Rights Reserved. - LANGUAGE - --langversion:? Display the allowed values for language version. --langversion:{version|latest|preview} Specify language version such as 'latest' or 'preview'. +--disableLanguageFeature: Disable a specific language feature by name. --checked[+|-] Generate overflow checks (off by default) --define: Define conditional compilation symbols (Short form: -d) --mlcompatibility Ignore ML compatibility warnings From aa32b6def51dfd84d079a6c003ce5015ca2841ed Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 17:08:59 +0000 Subject: [PATCH 09/12] Add DisabledLanguageFeatures MSBuild property support - Added disabledLanguageFeatures field to Fsc task - Added DisabledLanguageFeatures property (takes ITaskItem array) - Updated command line builder to pass each feature with --disableLanguageFeature flag - Follows same pattern as other MSBuild properties This allows .fsproj files to use: NameOf;StringInterpolation Partial implementation of comment 2627788945 from @T-Gro. Still need to update .targets files. Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- src/FSharp.Build/Fsc.fs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/FSharp.Build/Fsc.fs b/src/FSharp.Build/Fsc.fs index 8274812fcb2..62934bfe85f 100644 --- a/src/FSharp.Build/Fsc.fs +++ b/src/FSharp.Build/Fsc.fs @@ -42,6 +42,7 @@ type public Fsc() as this = let mutable highEntropyVA: bool = false let mutable keyFile: string MaybeNull = null let mutable langVersion: string MaybeNull = null + let mutable disabledLanguageFeatures: ITaskItem[] = [||] let mutable noFramework = false let mutable noInterfaceData = false let mutable noOptimizationData = false @@ -152,6 +153,9 @@ type public Fsc() as this = builder.AppendSwitchIfNotNull("--langversion:", langVersion) + for item in disabledLanguageFeatures do + builder.AppendSwitchIfNotNull("--disableLanguageFeature:", item.ItemSpec) + // NoFramework if noFramework then builder.AppendSwitch("--noframework") @@ -463,6 +467,10 @@ type public Fsc() as this = with get () = langVersion and set (s) = langVersion <- s + member _.DisabledLanguageFeatures + with get () = disabledLanguageFeatures + and set (a) = disabledLanguageFeatures <- a + member _.LCID with get () = vslcid and set (p) = vslcid <- p From 2eaf0460440f3332ea617044d2e772b77d8c1ecc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Dec 2025 08:53:02 +0000 Subject: [PATCH 10/12] Pass DisabledLanguageFeatures property to Fsc task in targets file Added DisabledLanguageFeatures property to the Fsc task invocation in Microsoft.FSharp.Targets, following the same pattern as LangVersion. This completes the MSBuild integration allowing .fsproj files to use: Or as a semicolon-delimited property when split into items by MSBuild. Addresses comment 2627788945 from @T-Gro. Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- src/FSharp.Build/Microsoft.FSharp.Targets | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FSharp.Build/Microsoft.FSharp.Targets b/src/FSharp.Build/Microsoft.FSharp.Targets index a1385f6aff2..9049f2f7118 100644 --- a/src/FSharp.Build/Microsoft.FSharp.Targets +++ b/src/FSharp.Build/Microsoft.FSharp.Targets @@ -371,6 +371,7 @@ this file. HighEntropyVA="$(HighEntropyVA)" KeyFile="$(KeyOriginatorFile)" LangVersion="$(LangVersion)" + DisabledLanguageFeatures="@(DisabledLanguageFeatures)" LCID="$(LCID)" NoFramework="true" NoInterfaceData="$(NoInterfaceData)" From 9da0e1b0cf900ffa00435869c6c73b9ba92912a4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 18 Dec 2025 12:44:38 +0000 Subject: [PATCH 11/12] Move release notes to correct file (.Language/preview.md) Moved the --disableLanguageFeature feature entry from .FSharp.Compiler.Service/11.0.0.md to .Language/preview.md as it's a language feature, not a compiler service API change. Used placeholder PR number "TBD" since gh CLI requires GH_TOKEN environment variable which is not available. Addresses comment 2630841469 from @T-Gro. Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- docs/release-notes/.FSharp.Compiler.Service/11.0.0.md | 1 - docs/release-notes/.Language/preview.md | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.0.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.0.md index 6c5754cf7aa..4d9542cf94e 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.0.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.0.md @@ -20,7 +20,6 @@ * Add FSharpCodeCompletionOptions ([PR #19030](https://github.com/dotnet/fsharp/pull/19030)) * Type checker: recover on checking binding parameter constraints ([#19046](https://github.com/dotnet/fsharp/pull/19046)) * Debugger: provide breakpoint ranges for short lambdas ([#19067](https://github.com/dotnet/fsharp/pull/19067)) -* Add `--disableLanguageFeature` command line switch to selectively disable specific F# language features ([PR #NNNNN](https://github.com/dotnet/fsharp/pull/NNNNN)) ### Changed diff --git a/docs/release-notes/.Language/preview.md b/docs/release-notes/.Language/preview.md index e5c2b65704f..6dfe549ee6f 100644 --- a/docs/release-notes/.Language/preview.md +++ b/docs/release-notes/.Language/preview.md @@ -11,6 +11,7 @@ * Allow `let!`, `use!`, `and!` type annotations without requiring parentheses (([PR #18508](https://github.com/dotnet/fsharp/pull/18508) and [PR #18682](https://github.com/dotnet/fsharp/pull/18682))) * Exception names are now validated for illegal characters using the same mechanism as types/modules/namespaces ([Issue #18763](https://github.com/dotnet/fsharp/issues/18763)) * Support tail calls in computation expressions ([PR #18804](https://github.com/dotnet/fsharp/pull/18804)) +* Add `--disableLanguageFeature` CLI switch and MSBuild property to selectively disable specific F# language features on a per-project basis. ([PR #TBD](https://github.com/dotnet/fsharp/pull/TBD)) ### Fixed From 2e3f35cb3c4e2ba488f648b922e53652ac343184 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 15:11:46 +0000 Subject: [PATCH 12/12] Fix nullness warning in TryParseFeature by using box before downcast Changed the null check pattern from matching on union directly to matching on box union. This satisfies the nullness analysis by ensuring the null check happens on the boxed value before downcasting, eliminating the FS3264 nullness warning. Fixes build error reported in comment 3675368950. Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- src/Compiler/Facilities/LanguageFeatures.fs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index ccd7df7647d..d21bf7b27dd 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -443,10 +443,9 @@ type LanguageVersion(versionText, ?disabledFeaturesArray: LanguageFeature array) |> Option.bind (fun case -> let union = Microsoft.FSharp.Reflection.FSharpValue.MakeUnion(case, [||]) - if isNull union then - None - else - Some(union :?> LanguageFeature)) + match box union with + | null -> None + | obj -> Some(obj :?> LanguageFeature)) override x.Equals(yobj: obj) = match yobj with