From c3eb162ec7bcf7449ca54b2218ab0d0c4d67c1d0 Mon Sep 17 00:00:00 2001 From: "Kevin Ransom (msft)" Date: Wed, 9 Oct 2024 15:44:18 -0700 Subject: [PATCH 01/22] Revert PR - Make the interaction between #line and #nowarn directives consistent (#17859) * merge * revert Reverting PR - Make the interaction between #line and #nowarn directives consistent --- buildtools/fslex/fslex.fsproj | 1 + buildtools/fsyacc/fsyacc.fsproj | 1 + buildtools/fsyacc/fsyaccdriver.fs | 2 - .../.FSharp.Compiler.Service/9.0.100.md | 1 - src/Compiler/AbstractIL/ilpars.fsy | 1 - src/Compiler/Driver/CompilerDiagnostics.fs | 25 +++++---- src/Compiler/Driver/CompilerDiagnostics.fsi | 3 +- src/Compiler/Driver/ParseAndCheckInputs.fs | 4 +- src/Compiler/Driver/fsc.fs | 2 +- src/Compiler/FSComp.txt | 3 +- src/Compiler/FSharp.Compiler.Service.fsproj | 2 + src/Compiler/Facilities/LanguageFeatures.fs | 3 -- src/Compiler/Facilities/LanguageFeatures.fsi | 1 - src/Compiler/Service/IncrementalBuild.fs | 2 +- src/Compiler/Service/TransparentCompiler.fs | 7 +-- src/Compiler/pars.fsy | 1 - src/Compiler/pppars.fsy | 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 -- .../CompilerDirectives/Nowarn.fs | 51 ------------------- .../FSharp.Compiler.ComponentTests.fsproj | 1 - 32 files changed, 26 insertions(+), 151 deletions(-) delete mode 100644 tests/FSharp.Compiler.ComponentTests/CompilerDirectives/Nowarn.fs diff --git a/buildtools/fslex/fslex.fsproj b/buildtools/fslex/fslex.fsproj index 5dfef2f0e31..b450de1668d 100644 --- a/buildtools/fslex/fslex.fsproj +++ b/buildtools/fslex/fslex.fsproj @@ -5,6 +5,7 @@ $(FSharpNetCoreProductTargetFramework) true LatestMajor + $(NoWarn);64;1182;1204 diff --git a/buildtools/fsyacc/fsyacc.fsproj b/buildtools/fsyacc/fsyacc.fsproj index 1ff8a110759..5f97b762e03 100644 --- a/buildtools/fsyacc/fsyacc.fsproj +++ b/buildtools/fsyacc/fsyacc.fsproj @@ -5,6 +5,7 @@ $(FSharpNetCoreProductTargetFramework) true LatestMajor + $(NoWarn);64;1182;1204 diff --git a/buildtools/fsyacc/fsyaccdriver.fs b/buildtools/fsyacc/fsyaccdriver.fs index f46e607f93a..c9ca12e4710 100644 --- a/buildtools/fsyacc/fsyaccdriver.fs +++ b/buildtools/fsyacc/fsyaccdriver.fs @@ -199,8 +199,6 @@ let writeSpecToFile (generatorState: GeneratorState) (spec: ParserSpec) (compile writer.WriteLineInterface "module %s" s; writer.WriteLine "#nowarn \"64\";; // turn off warnings that type variables used in production annotations are instantiated to concrete type"; - writer.WriteLine "#nowarn \"1182\" // the generated code often has unused variable 'parseState'" - writer.WriteLine "#nowarn \"3261\" // the generated code would need to properly annotate nulls, e.g. changing System.Object to `obj|null`"; for s in generatorState.opens do writer.WriteLine "open %s" s; diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md index 1455a1f0479..d9ee0fa5f76 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md @@ -1,6 +1,5 @@ ### Fixed -* Fix a bug in the interaction between ``#line` and `#nowarn` directives ([PR #17649](https://github.com/dotnet/fsharp/pull/17649)) * Fix wrong TailCall warning ([Issue #17604](https://github.com/dotnet/fsharp/issues/17604), [PR #17637](https://github.com/dotnet/fsharp/pull/17637)) * Compiler hangs when compiling inline recursive invocation ([Issue #17376](https://github.com/dotnet/fsharp/issues/17376), [PR #17394](https://github.com/dotnet/fsharp/pull/17394)) * Fix reporting IsFromComputationExpression only for CE builder type constructors and let bindings. ([PR #17375](https://github.com/dotnet/fsharp/pull/17375)) diff --git a/src/Compiler/AbstractIL/ilpars.fsy b/src/Compiler/AbstractIL/ilpars.fsy index b8380364f6b..ca06f6570be 100644 --- a/src/Compiler/AbstractIL/ilpars.fsy +++ b/src/Compiler/AbstractIL/ilpars.fsy @@ -2,7 +2,6 @@ %{ -#nowarn "64" // turn off warnings that type variables used in production annotations are instantiated to concrete type #nowarn "1182" // the generated code often has unused variable "parseState" #nowarn "3261" // the generated code would need to properly annotate nulls, e.g. changing System.Object to `obj|null` diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs index c73b8e5d197..1c50ca26781 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fs +++ b/src/Compiler/Driver/CompilerDiagnostics.fs @@ -24,7 +24,6 @@ open FSharp.Compiler.ConstraintSolver open FSharp.Compiler.DiagnosticMessage open FSharp.Compiler.Diagnostics open FSharp.Compiler.DiagnosticsLogger -open FSharp.Compiler.Features open FSharp.Compiler.Infos open FSharp.Compiler.IO open FSharp.Compiler.Lexhelp @@ -2300,13 +2299,17 @@ type PhasedDiagnostic with // Scoped #nowarn pragmas /// Build an DiagnosticsLogger that delegates to another DiagnosticsLogger but filters warnings turned off by the given pragma declarations +// +// NOTE: we allow a flag to turn of strict file checking. This is because file names sometimes don't match due to use of +// #line directives, e.g. for pars.fs/pars.fsy. In this case we just test by line number - in most cases this is sufficient +// because we install a filtering error handler on a file-by-file basis for parsing and type-checking. +// However this is indicative of a more systematic problem where source-line +// sensitive operations (lexfilter and warning filtering) do not always +// interact well with #line directives. type DiagnosticsLoggerFilteringByScopedPragmas - (langVersion: LanguageVersion, scopedPragmas, diagnosticOptions: FSharpDiagnosticOptions, diagnosticsLogger: DiagnosticsLogger) = + (checkFile, scopedPragmas, diagnosticOptions: FSharpDiagnosticOptions, diagnosticsLogger: DiagnosticsLogger) = inherit DiagnosticsLogger("DiagnosticsLoggerFilteringByScopedPragmas") - let needCompatibilityWithEarlierInconsistentInteraction = - not (langVersion.SupportsFeature LanguageFeature.ConsistentNowarnLineDirectiveInteraction) - let mutable realErrorPresent = false override _.DiagnosticSink(diagnostic: PhasedDiagnostic, severity) = @@ -2320,10 +2323,12 @@ type DiagnosticsLoggerFilteringByScopedPragmas match diagnostic.Range with | Some m -> scopedPragmas - |> List.exists (fun (ScopedPragma.WarningOff(pragmaRange, warningNumFromPragma)) -> + |> List.exists (fun pragma -> + let (ScopedPragma.WarningOff(pragmaRange, warningNumFromPragma)) = pragma + warningNum = warningNumFromPragma - && (needCompatibilityWithEarlierInconsistentInteraction - || m.FileIndex = pragmaRange.FileIndex && posGeq m.Start pragmaRange.Start)) + && (not checkFile || m.FileIndex = pragmaRange.FileIndex) + && posGeq m.Start pragmaRange.Start) |> not | None -> true @@ -2339,5 +2344,5 @@ type DiagnosticsLoggerFilteringByScopedPragmas override _.CheckForRealErrorsIgnoringWarnings = realErrorPresent -let GetDiagnosticsLoggerFilteringByScopedPragmas (langVersion, scopedPragmas, diagnosticOptions, diagnosticsLogger) = - DiagnosticsLoggerFilteringByScopedPragmas(langVersion, scopedPragmas, diagnosticOptions, diagnosticsLogger) :> DiagnosticsLogger +let GetDiagnosticsLoggerFilteringByScopedPragmas (checkFile, scopedPragmas, diagnosticOptions, diagnosticsLogger) = + DiagnosticsLoggerFilteringByScopedPragmas(checkFile, scopedPragmas, diagnosticOptions, diagnosticsLogger) :> DiagnosticsLogger diff --git a/src/Compiler/Driver/CompilerDiagnostics.fsi b/src/Compiler/Driver/CompilerDiagnostics.fsi index 7c5acef17d4..6139da434cf 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fsi +++ b/src/Compiler/Driver/CompilerDiagnostics.fsi @@ -7,7 +7,6 @@ open System.Text open FSharp.Compiler.CompilerConfig open FSharp.Compiler.Diagnostics open FSharp.Compiler.DiagnosticsLogger -open FSharp.Compiler.Features open FSharp.Compiler.Syntax open FSharp.Compiler.Text @@ -85,7 +84,7 @@ type PhasedDiagnostic with /// Get a diagnostics logger that filters the reporting of warnings based on scoped pragma information val GetDiagnosticsLoggerFilteringByScopedPragmas: - langVersion: LanguageVersion * + checkFile: bool * scopedPragmas: ScopedPragma list * diagnosticOptions: FSharpDiagnosticOptions * diagnosticsLogger: DiagnosticsLogger -> diff --git a/src/Compiler/Driver/ParseAndCheckInputs.fs b/src/Compiler/Driver/ParseAndCheckInputs.fs index d5d18d79651..a6804bfe746 100644 --- a/src/Compiler/Driver/ParseAndCheckInputs.fs +++ b/src/Compiler/Driver/ParseAndCheckInputs.fs @@ -511,7 +511,7 @@ let ParseInput finally // OK, now commit the errors, since the ScopedPragmas will (hopefully) have been scraped let filteringDiagnosticsLogger = - GetDiagnosticsLoggerFilteringByScopedPragmas(lexbuf.LanguageVersion, scopedPragmas, diagnosticOptions, diagnosticsLogger) + GetDiagnosticsLoggerFilteringByScopedPragmas(false, scopedPragmas, diagnosticOptions, diagnosticsLogger) delayLogger.CommitDelayedDiagnostics filteringDiagnosticsLogger @@ -1429,7 +1429,7 @@ let CheckOneInput // Within a file, equip loggers to locally filter w.r.t. scope pragmas in each input let DiagnosticsLoggerForInput (tcConfig: TcConfig, input: ParsedInput, oldLogger) = - GetDiagnosticsLoggerFilteringByScopedPragmas(tcConfig.langVersion, input.ScopedPragmas, tcConfig.diagnosticsOptions, oldLogger) + GetDiagnosticsLoggerFilteringByScopedPragmas(false, input.ScopedPragmas, tcConfig.diagnosticsOptions, oldLogger) /// Typecheck a single file (or interactive entry into F# Interactive) let CheckOneInputEntry (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt) tcState input = diff --git a/src/Compiler/Driver/fsc.fs b/src/Compiler/Driver/fsc.fs index 9dccdec826d..ac4ee179538 100644 --- a/src/Compiler/Driver/fsc.fs +++ b/src/Compiler/Driver/fsc.fs @@ -745,7 +745,7 @@ let main2 yield! pragmas ] - GetDiagnosticsLoggerFilteringByScopedPragmas(tcConfig.langVersion, scopedPragmas, tcConfig.diagnosticsOptions, oldLogger) + GetDiagnosticsLoggerFilteringByScopedPragmas(true, scopedPragmas, tcConfig.diagnosticsOptions, oldLogger) SetThreadDiagnosticsLoggerNoUnwind diagnosticsLogger diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 2e391fa5515..b5a50afc7c0 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1783,5 +1783,4 @@ featureEmptyBodiedComputationExpressions,"Support for computation expressions wi featureAllowAccessModifiersToAutoPropertiesGettersAndSetters,"Allow access modifiers to auto properties getters and setters" 3871,tcAccessModifiersNotAllowedInSRTPConstraint,"Access modifiers cannot be applied to an SRTP constraint." featureAllowObjectExpressionWithoutOverrides,"Allow object expressions without overrides" -3872,tcPartialActivePattern,"Multi-case partial active patterns are not supported. Consider using a single-case partial active pattern or a full active pattern." -featureConsistentNowarnLineDirectiveInteraction,"The interaction between #nowarn and #line is now consistent." +3872,tcPartialActivePattern,"Multi-case partial active patterns are not supported. Consider using a single-case partial active pattern or a full active pattern." \ No newline at end of file diff --git a/src/Compiler/FSharp.Compiler.Service.fsproj b/src/Compiler/FSharp.Compiler.Service.fsproj index 45b5bda0d10..8029bb6d45e 100644 --- a/src/Compiler/FSharp.Compiler.Service.fsproj +++ b/src/Compiler/FSharp.Compiler.Service.fsproj @@ -10,6 +10,8 @@ $(NoWarn);75 $(NoWarn);1204 $(NoWarn);NU5125 + $(NoWarn);64;1182;1204 + $(OtherFlags) --warnaserror-:1182 FSharp.Compiler.Service true $(DefineConstants);COMPILER diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index 5f16aead30a..5d71f3ed27b 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -94,7 +94,6 @@ type LanguageFeature = | ParsedHashDirectiveArgumentNonQuotes | EmptyBodiedComputationExpressions | AllowObjectExpressionWithoutOverrides - | ConsistentNowarnLineDirectiveInteraction /// LanguageVersion management type LanguageVersion(versionText) = @@ -213,7 +212,6 @@ type LanguageVersion(versionText) = LanguageFeature.LowerSimpleMappingsInComprehensionsToFastLoops, languageVersion90 LanguageFeature.ParsedHashDirectiveArgumentNonQuotes, languageVersion90 LanguageFeature.EmptyBodiedComputationExpressions, languageVersion90 - LanguageFeature.ConsistentNowarnLineDirectiveInteraction, languageVersion90 // F# preview LanguageFeature.EnforceAttributeTargets, previewVersion // waiting for fix of https://github.com/dotnet/fsharp/issues/17731 @@ -377,7 +375,6 @@ type LanguageVersion(versionText) = | LanguageFeature.ParsedHashDirectiveArgumentNonQuotes -> FSComp.SR.featureParsedHashDirectiveArgumentNonString () | LanguageFeature.EmptyBodiedComputationExpressions -> FSComp.SR.featureEmptyBodiedComputationExpressions () | LanguageFeature.AllowObjectExpressionWithoutOverrides -> FSComp.SR.featureAllowObjectExpressionWithoutOverrides () - | LanguageFeature.ConsistentNowarnLineDirectiveInteraction -> FSComp.SR.featureConsistentNowarnLineDirectiveInteraction () /// 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 4ae722c7f60..7408300b943 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -85,7 +85,6 @@ type LanguageFeature = | ParsedHashDirectiveArgumentNonQuotes | EmptyBodiedComputationExpressions | AllowObjectExpressionWithoutOverrides - | ConsistentNowarnLineDirectiveInteraction /// LanguageVersion management type LanguageVersion = diff --git a/src/Compiler/Service/IncrementalBuild.fs b/src/Compiler/Service/IncrementalBuild.fs index 7951f3c9328..b7560b222c2 100644 --- a/src/Compiler/Service/IncrementalBuild.fs +++ b/src/Compiler/Service/IncrementalBuild.fs @@ -259,7 +259,7 @@ type BoundModel private ( IncrementalBuilderEventTesting.MRU.Add(IncrementalBuilderEventTesting.IBETypechecked fileName) let capturingDiagnosticsLogger = CapturingDiagnosticsLogger("TypeCheck") - let diagnosticsLogger = GetDiagnosticsLoggerFilteringByScopedPragmas(tcConfig.langVersion, input.ScopedPragmas, tcConfig.diagnosticsOptions, capturingDiagnosticsLogger) + let diagnosticsLogger = GetDiagnosticsLoggerFilteringByScopedPragmas(false, input.ScopedPragmas, tcConfig.diagnosticsOptions, capturingDiagnosticsLogger) use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck) beforeFileChecked.Trigger fileName diff --git a/src/Compiler/Service/TransparentCompiler.fs b/src/Compiler/Service/TransparentCompiler.fs index 735a6b241f1..e3acd1d4c6c 100644 --- a/src/Compiler/Service/TransparentCompiler.fs +++ b/src/Compiler/Service/TransparentCompiler.fs @@ -1303,12 +1303,7 @@ type internal TransparentCompiler let diagnosticsLogger = errHandler.DiagnosticsLogger let diagnosticsLogger = - GetDiagnosticsLoggerFilteringByScopedPragmas( - tcConfig.langVersion, - input.ScopedPragmas, - tcConfig.diagnosticsOptions, - diagnosticsLogger - ) + GetDiagnosticsLoggerFilteringByScopedPragmas(false, input.ScopedPragmas, tcConfig.diagnosticsOptions, diagnosticsLogger) use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.TypeCheck) diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 54d47b7c4fb..2794edf560e 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -2,7 +2,6 @@ %{ -#nowarn "64" // turn off warnings that type variables used in production annotations are instantiated to concrete type #nowarn "1182" // generated code has lots of unused "parseState" #nowarn "3261" // the generated code would need to properly annotate nulls, e.g. changing System.Object to `obj|null` diff --git a/src/Compiler/pppars.fsy b/src/Compiler/pppars.fsy index 41cb41ff38a..cd27722a254 100644 --- a/src/Compiler/pppars.fsy +++ b/src/Compiler/pppars.fsy @@ -3,7 +3,6 @@ %{ open FSharp.Compiler.DiagnosticsLogger -#nowarn "64" // turn off warnings that type variables used in production annotations are instantiated to concrete type #nowarn "3261" // the generated code would need to properly annotate nulls, e.g. changing System.Object to `obj|null` let dummy = IfdefId("DUMMY") diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index e384127d444..958a1357ac9 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -307,11 +307,6 @@ Vyvolá upozornění, pokud je atribut TailCall použit u nerekurzivních funkcí. - - The interaction between #nowarn and #line is now consistent. - The interaction between #nowarn and #line is now consistent. - - Constraint intersection on flexible types Průnik omezení u flexibilních typů diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 2cd51bff66a..d7233a5d2fc 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -307,11 +307,6 @@ Löst Warnungen aus, wenn das Attribut "TailCall" für nicht rekursive Funktionen verwendet wird. - - The interaction between #nowarn and #line is now consistent. - The interaction between #nowarn and #line is now consistent. - - Constraint intersection on flexible types Einschränkungsüberschneidung für flexible Typen diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 47c41d9d5a3..1b3205ffa53 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -307,11 +307,6 @@ Genera advertencias si el atributo 'TailCall' se usa en funciones no recursivas. - - The interaction between #nowarn and #line is now consistent. - The interaction between #nowarn and #line is now consistent. - - Constraint intersection on flexible types Intersección de restricciones en tipos flexibles diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 2509d30cd3c..018180a8fb6 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -307,11 +307,6 @@ Émet des avertissements si l’attribut « TailCall » est utilisé sur des fonctions non récursives. - - The interaction between #nowarn and #line is now consistent. - The interaction between #nowarn and #line is now consistent. - - Constraint intersection on flexible types Intersection de contraintes sur les types flexibles diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 932620230c2..7cc3f46259b 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -307,11 +307,6 @@ Genera avvisi se l'attributo 'TailCall' viene utilizzato in funzioni non ricorsive. - - The interaction between #nowarn and #line is now consistent. - The interaction between #nowarn and #line is now consistent. - - Constraint intersection on flexible types Intersezione di vincoli su tipi flessibili diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 0d7aee793bf..10c5f06f4ff 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -307,11 +307,6 @@ 'TailCall' 属性が再帰関数以外で使用されている場合、警告が発せられます。 - - The interaction between #nowarn and #line is now consistent. - The interaction between #nowarn and #line is now consistent. - - Constraint intersection on flexible types フレキシブル型の制約積集合 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index aaf528ddf61..94cd344f052 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -307,11 +307,6 @@ 'TailCall' 특성이 비 재귀 함수에 사용되는 경우 경고를 발생합니다. - - The interaction between #nowarn and #line is now consistent. - The interaction between #nowarn and #line is now consistent. - - Constraint intersection on flexible types 유연한 형식의 제약 조건 교집합 diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 5727c48f9ef..01f2ff1d5e3 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -307,11 +307,6 @@ Zgłasza ostrzeżenia, jeśli atrybut „TailCall” jest używany w funkcjach niekursywnych. - - The interaction between #nowarn and #line is now consistent. - The interaction between #nowarn and #line is now consistent. - - Constraint intersection on flexible types Przecięcie ograniczenia dla typów elastycznych diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 481824624bd..63da6a667b1 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -307,11 +307,6 @@ Gera avisos se o atributo "TailCall" for usado em funções não recursivas. - - The interaction between #nowarn and #line is now consistent. - The interaction between #nowarn and #line is now consistent. - - Constraint intersection on flexible types Interseção de restrição em tipos flexíveis diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 597b46ad265..231bc83103b 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -307,11 +307,6 @@ Выдает предупреждения, если атрибут TailCall используется в нерекурсивных функциях. - - The interaction between #nowarn and #line is now consistent. - The interaction between #nowarn and #line is now consistent. - - Constraint intersection on flexible types Пересечение ограничений на гибких типах diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 9896d5fec9b..a3bab7e5a92 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -307,11 +307,6 @@ 'TailCall' özniteliği özyinelemeli olmayan işlevlerde kullanılıyorsa uyarılar oluşturur. - - The interaction between #nowarn and #line is now consistent. - The interaction between #nowarn and #line is now consistent. - - Constraint intersection on flexible types Esnek türlerde kısıtlama kesişimi diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 41a056b3bd7..579ac9b79c3 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -307,11 +307,6 @@ 如果在非递归函数上使用“TailCall”属性,则引发警告。 - - The interaction between #nowarn and #line is now consistent. - The interaction between #nowarn and #line is now consistent. - - Constraint intersection on flexible types 灵活类型的约束交集 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 74c4b57ae60..09818a7487b 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -307,11 +307,6 @@ 如果 'TailCall' 屬性用於非遞迴函數,則引發警告。 - - The interaction between #nowarn and #line is now consistent. - The interaction between #nowarn and #line is now consistent. - - Constraint intersection on flexible types 彈性類型上的條件約束交集 diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/Nowarn.fs b/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/Nowarn.fs deleted file mode 100644 index 78067aa8c32..00000000000 --- a/tests/FSharp.Compiler.ComponentTests/CompilerDirectives/Nowarn.fs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. -namespace CompilerDirectives - -open Xunit -open FSharp.Test.Compiler - -module Nowarn = - - let warn20Text = "The result of this expression has type 'string' 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'." - - let checkFileBugSource = """ -module A -#nowarn "20" -#line 1 "xyz.fs" -"" - """ - - let checkFileBugSource2 = """ -module A -#line 1 "xyz.fs" -#nowarn "20" -"" - """ - - - [] - let ``checkFile bug simulation for compatibility`` () = - - FSharp checkFileBugSource - |> withLangVersion80 - |> compile - |> shouldSucceed - - [] - let ``checkFile bug fixed leads to new warning`` () = - - FSharp checkFileBugSource - |> withLangVersion90 - |> compile - |> shouldFail - |> withDiagnostics [ - (Warning 20, Line 1, Col 1, Line 1, Col 3, warn20Text) - ] - - [] - let ``checkFile bug fixed, no warning if nowarn is correctly used`` () = - - FSharp checkFileBugSource2 - |> withLangVersion90 - |> compile - |> shouldSucceed diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 96265fdd24b..03ff28e096a 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -33,7 +33,6 @@ - From 349a95d8eb740dd91eff003ae8bb4a04706dd7d7 Mon Sep 17 00:00:00 2001 From: Petr Date: Tue, 15 Oct 2024 11:25:03 +0200 Subject: [PATCH 02/22] Fix a link in release notes (#17883) --- docs/release-notes/.FSharp.Compiler.Service/9.0.100.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md index d350b30edbe..51115b5ead0 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md @@ -32,7 +32,7 @@ * Allow access modifies to auto properties getters and setters ([Language suggestion #430](https://github.com/fsharp/fslang-suggestions/issues/430), [PR 16687](https://github.com/dotnet/fsharp/pull/16687), [PR 16861](https://github.com/dotnet/fsharp/pull/16861), [PR 17522](https://github.com/dotnet/fsharp/pull/17522)) * Render C# nullable-analysis attributes in tooltips ([PR #17485](https://github.com/dotnet/fsharp/pull/17485)) * Allow object expression without overrides. ([Language suggestion #632](https://github.com/fsharp/fslang-suggestions/issues/632), [PR #17387](https://github.com/dotnet/fsharp/pull/17387)) -* Enable FSharp 9.0 Language Version ([Issue #17497](https://github.com/dotnet/fsharp/issues/17438)), [PR](https://github.com/dotnet/fsharp/pull/17500))) +* Enable FSharp 9.0 Language Version ([Issue #17497](https://github.com/dotnet/fsharp/issues/17497)), [PR](https://github.com/dotnet/fsharp/pull/17500))) * Enable LanguageFeature.EnforceAttributeTargets in F# 9.0. ([Issue #17514](https://github.com/dotnet/fsharp/issues/17558), [PR #17516](https://github.com/dotnet/fsharp/pull/17558)) * Parser: better recovery for unfinished patterns ([PR #17231](https://github.com/dotnet/fsharp/pull/17231), [PR #17232](https://github.com/dotnet/fsharp/pull/17232))) * Enable consuming generic arguments defined as `allows ref struct` in C# ([Issue #17597](https://github.com/dotnet/fsharp/issues/17597), display them in tooltips [PR #17706](https://github.com/dotnet/fsharp/pull/17706)) From 3493c767758774e20a813789429b50bf61260b6a Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 15 Oct 2024 12:59:40 +0200 Subject: [PATCH 03/22] Nullness bugfix :: could not assign null to member val property (#17845) --- .../.FSharp.Compiler.Service/9.0.200.md | 1 + src/Compiler/TypedTree/TypedTree.fs | 6 ++++++ src/Compiler/TypedTree/TypedTree.fsi | 1 + src/Compiler/TypedTree/TypedTreeBasics.fs | 2 +- .../Nullness/NullableReferenceTypesTests.fs | 15 +++++++++++++++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md index fe3cde0444a..fd5a94681ec 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md @@ -5,6 +5,7 @@ * Fix extension methods support for non-reference system assemblies ([PR #17799](https://github.com/dotnet/fsharp/pull/17799)) * Ensure `frameworkTcImportsCache` mutations are thread-safe. ([PR #17795](https://github.com/dotnet/fsharp/pull/17795)) * Fix concurrency issue in `ILPreTypeDefImpl` ([PR #17812](https://github.com/dotnet/fsharp/pull/17812)) +* Fix nullness inference for member val and other OO scenarios ([PR #17845](https://github.com/dotnet/fsharp/pull/17845)) ### Added diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index b948e91fb65..b5e620c6bd6 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -4358,6 +4358,12 @@ type NullnessVar() = member nv.IsSolved = solution.IsSome + member nv.IsFullySolved = + match solution with + | None -> false + | Some (Nullness.Known _) -> true + | Some (Nullness.Variable v) -> v.IsFullySolved + member nv.Set(nullness) = assert (not nv.IsSolved) solution <- Some nullness diff --git a/src/Compiler/TypedTree/TypedTree.fsi b/src/Compiler/TypedTree/TypedTree.fsi index d357895728d..5f96fba2266 100644 --- a/src/Compiler/TypedTree/TypedTree.fsi +++ b/src/Compiler/TypedTree/TypedTree.fsi @@ -3100,6 +3100,7 @@ type NullnessVar = member Evaluate: unit -> NullnessInfo member TryEvaluate: unit -> NullnessInfo voption member IsSolved: bool + member IsFullySolved: bool member Set: Nullness -> unit member Unset: unit -> unit member Solution: Nullness diff --git a/src/Compiler/TypedTree/TypedTreeBasics.fs b/src/Compiler/TypedTree/TypedTreeBasics.fs index c8268ffcf8a..0ad62482b6a 100644 --- a/src/Compiler/TypedTree/TypedTreeBasics.fs +++ b/src/Compiler/TypedTree/TypedTreeBasics.fs @@ -284,7 +284,7 @@ let tryAddNullnessToTy nullnessNew (ty:TType) = let addNullnessToTy (nullness: Nullness) (ty:TType) = match nullness with | Nullness.Known NullnessInfo.WithoutNull -> ty - | Nullness.Variable nv when nv.IsSolved && nv.Evaluate() = NullnessInfo.WithoutNull -> ty + | Nullness.Variable nv when nv.IsFullySolved && nv.TryEvaluate() = ValueSome NullnessInfo.WithoutNull -> ty | _ -> match ty with | TType_var (tp, nullnessOrig) -> TType_var (tp, combineNullness nullnessOrig nullness) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs index 1edfbfd7961..0da1169b9a8 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs @@ -144,6 +144,21 @@ let nonStrictFunc(x:string | null) = strictFunc(x) |> shouldFail |> withDiagnostics [ Error 3261, Line 4, Col 49, Line 4, Col 50, "Nullness warning: The types 'string' and 'string | null' do not have equivalent nullability."] + +[] +let ``Can have nullable prop of same type T within a custom type T``() = + FSharp """ +module MyLib +type T () = + let mutable v : T | null = null + member val P : T | null = null with get, set + member this.M() = + v <- null + this.P <- null + """ + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldSucceed [] [] From 14ca0c02232f7272caaf4b36a5e7c79745f5f87e Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Tue, 15 Oct 2024 13:41:36 +0100 Subject: [PATCH 04/22] Better `inherit` error reporting (#17879) * Better `inherit` error reporting * update baselines * format code * Update tests * release notes * update tests --- .../.FSharp.Compiler.Service/9.0.200.md | 1 + src/Compiler/Checking/CheckDeclarations.fs | 10 +++++++--- .../Driver/GraphChecking/FileContentMapping.fs | 2 +- src/Compiler/Service/FSharpParseFileResults.fs | 2 +- src/Compiler/Service/ServiceParseTreeWalk.fs | 2 +- src/Compiler/Service/ServiceParsedInputOps.fs | 4 ++-- src/Compiler/SyntaxTree/SyntaxTree.fs | 2 +- src/Compiler/SyntaxTree/SyntaxTree.fsi | 2 +- src/Compiler/SyntaxTree/SyntaxTrivia.fs | 3 +++ src/Compiler/SyntaxTree/SyntaxTrivia.fsi | 4 ++++ src/Compiler/pars.fsy | 6 ++++-- .../ExceptionDefinitions.fs | 2 +- .../TypeAbbreviations/TypeAbbreviations.fs | 2 +- .../Conformance/Types/UnionTypes/UnionTypes.fs | 4 ++-- .../ErrorMessages/ClassesTests.fs | 17 ++++++++++++++++- ....Service.SurfaceArea.netstandard20.debug.bsl | 8 +++++++- ...ervice.SurfaceArea.netstandard20.release.bsl | 8 +++++++- tests/fsharp/typecheck/sigs/neg06.bsl | 2 +- tests/fsharp/typecheck/sigs/neg10.bsl | 4 ++-- .../StructTypes/E_StructInheritance01b.fs | 2 +- .../TypeKindInference/infer_interface002e.fs | 4 ++-- .../data/SyntaxTree/Member/Inherit 01.fs.bsl | 3 ++- .../data/SyntaxTree/Member/Inherit 03.fs.bsl | 3 ++- .../data/SyntaxTree/Member/Inherit 04.fs.bsl | 3 ++- .../data/SyntaxTree/Member/Inherit 05.fs.bsl | 2 +- .../data/SyntaxTree/Member/Inherit 08.fs.bsl | 2 +- 26 files changed, 74 insertions(+), 30 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md index fd5a94681ec..185fa3a015f 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md @@ -20,5 +20,6 @@ * Better ranges for CE `return, yield, return! and yield!` error reporting. ([PR #17792](https://github.com/dotnet/fsharp/pull/17792)) * Better ranges for CE `match!`. ([PR #17789](https://github.com/dotnet/fsharp/pull/17789)) * Better ranges for CE `use` error reporting. ([PR #17811](https://github.com/dotnet/fsharp/pull/17811)) +* Better ranges for `inherit` error reporting. ([PR #17879](https://github.com/dotnet/fsharp/pull/17879)) ### Breaking Changes diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index e739169ea9c..814374417d3 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -3622,7 +3622,11 @@ module EstablishTypeDefinitionCores = // Note: for a mutually recursive set we can't check this condition // until "isSealedTy" and "isClassTy" give reliable results. superTy |> Option.iter (fun ty -> - let m = match inherits with | [] -> m | (_, m, _) :: _ -> m + let m = + match inherits with + | [] -> m + | (synType, _, _) :: _ -> synType.Range + if isSealedTy g ty then errorR(Error(FSComp.SR.tcCannotInheritFromSealedType(), m)) elif not (isClassTy g ty) then @@ -4292,7 +4296,7 @@ module TcDeclarations = | SynMemberDefn.AutoProperty (range=m) :: _ -> errorR(InternalError("List.takeUntil is wrong, have auto property", m)) | SynMemberDefn.ImplicitInherit (range=m) :: _ -> errorR(Error(FSComp.SR.tcTypeDefinitionsWithImplicitConstructionMustHaveOneInherit(), m)) | SynMemberDefn.LetBindings (range=m) :: _ -> errorR(Error(FSComp.SR.tcTypeDefinitionsWithImplicitConstructionMustHaveLocalBindingsBeforeMembers(), m)) - | SynMemberDefn.Inherit (range=m) :: _ -> errorR(Error(FSComp.SR.tcInheritDeclarationMissingArguments(), m)) + | SynMemberDefn.Inherit (trivia= { InheritKeyword = m }) :: _ -> errorR(Error(FSComp.SR.tcInheritDeclarationMissingArguments(), m)) | SynMemberDefn.NestedType (range=m) :: _ -> errorR(Error(FSComp.SR.tcTypesCannotContainNestedTypes(), m)) | _ -> () | ds -> @@ -4464,7 +4468,7 @@ module TcDeclarations = let implements2 = members |> List.choose (function SynMemberDefn.Interface (interfaceType=ty) -> Some(ty, ty.Range) | _ -> None) let inherits = members |> List.choose (function - | SynMemberDefn.Inherit (ty, idOpt, m) -> Some(ty, m, idOpt) + | SynMemberDefn.Inherit (ty, idOpt, m, _) -> Some(ty, m, idOpt) | SynMemberDefn.ImplicitInherit (ty, _, idOpt, m) -> Some(ty, m, idOpt) | _ -> None) diff --git a/src/Compiler/Driver/GraphChecking/FileContentMapping.fs b/src/Compiler/Driver/GraphChecking/FileContentMapping.fs index 5fd190b1995..938034623ba 100644 --- a/src/Compiler/Driver/GraphChecking/FileContentMapping.fs +++ b/src/Compiler/Driver/GraphChecking/FileContentMapping.fs @@ -220,7 +220,7 @@ let visitSynMemberDefn (md: SynMemberDefn) : FileContentEntry list = | SynMemberDefn.Interface(interfaceType, _, members, _) -> yield! visitSynType interfaceType yield! collectFromOption (List.collect visitSynMemberDefn) members - | SynMemberDefn.Inherit(baseType, _, _) -> yield! visitSynType baseType + | SynMemberDefn.Inherit(baseType = t) -> yield! visitSynType t | SynMemberDefn.ValField(fieldInfo, _) -> yield! visitSynField fieldInfo | SynMemberDefn.NestedType _ -> () | SynMemberDefn.AutoProperty(attributes = attributes; typeOpt = typeOpt; synExpr = synExpr) -> diff --git a/src/Compiler/Service/FSharpParseFileResults.fs b/src/Compiler/Service/FSharpParseFileResults.fs index 2623cbde347..7b273f71430 100644 --- a/src/Compiler/Service/FSharpParseFileResults.fs +++ b/src/Compiler/Service/FSharpParseFileResults.fs @@ -814,7 +814,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput, | SynMemberDefn.Interface(members = Some membs) -> for m in membs do yield! walkMember m - | SynMemberDefn.Inherit(_, _, m) -> + | SynMemberDefn.Inherit(range = m) -> // can break on the "inherit" clause yield! checkRange m | SynMemberDefn.ImplicitInherit(_, arg, _, m) -> diff --git a/src/Compiler/Service/ServiceParseTreeWalk.fs b/src/Compiler/Service/ServiceParseTreeWalk.fs index e0957fe0140..ca1a1c5e657 100644 --- a/src/Compiler/Service/ServiceParseTreeWalk.fs +++ b/src/Compiler/Service/ServiceParseTreeWalk.fs @@ -996,7 +996,7 @@ module SyntaxTraversal = |> pick x | ok -> ok - | SynMemberDefn.Inherit(synType, _identOption, range) -> traverseInherit (synType, range) + | SynMemberDefn.Inherit(synType, _identOption, range, _) -> traverseInherit (synType, range) | SynMemberDefn.ValField _ -> None | SynMemberDefn.NestedType(synTypeDefn, _synAccessOption, _range) -> traverseSynTypeDefn path synTypeDefn diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index 0b3f0134545..cfbefd49ade 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -913,7 +913,7 @@ module ParsedInput = walkType t |> Option.orElseWith (fun () -> members |> Option.bind (List.tryPick walkMember)) - | SynMemberDefn.Inherit(t, _, _) -> walkType t + | SynMemberDefn.Inherit(baseType = t) -> walkType t | SynMemberDefn.ValField(fieldInfo = field) -> walkField field @@ -2240,7 +2240,7 @@ module ParsedInput = | SynMemberDefn.Interface(interfaceType = t; members = members) -> walkType t members |> Option.iter (List.iter walkMember) - | SynMemberDefn.Inherit(t, _, _) -> walkType t + | SynMemberDefn.Inherit(baseType = t) -> walkType t | SynMemberDefn.ValField(fieldInfo = field) -> walkField field | SynMemberDefn.NestedType(tdef, _, _) -> walkTypeDefn tdef | SynMemberDefn.AutoProperty(attributes = Attributes attrs; typeOpt = t; synExpr = e) -> diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs index fc0c811e55d..81e893592b8 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fs +++ b/src/Compiler/SyntaxTree/SyntaxTree.fs @@ -1496,7 +1496,7 @@ type SynMemberDefn = | Interface of interfaceType: SynType * withKeyword: range option * members: SynMemberDefns option * range: range - | Inherit of baseType: SynType * asIdent: Ident option * range: range + | Inherit of baseType: SynType * asIdent: Ident option * range: range * trivia: SynMemberDefnInheritTrivia | ValField of fieldInfo: SynField * range: range diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fsi b/src/Compiler/SyntaxTree/SyntaxTree.fsi index 45b03ad3b75..379362f407c 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTree.fsi @@ -1670,7 +1670,7 @@ type SynMemberDefn = | Interface of interfaceType: SynType * withKeyword: range option * members: SynMemberDefns option * range: range /// An 'inherit' definition within a class - | Inherit of baseType: SynType * asIdent: Ident option * range: range + | Inherit of baseType: SynType * asIdent: Ident option * range: range * trivia: SynMemberDefnInheritTrivia /// A 'val' definition within a class | ValField of fieldInfo: SynField * range: range diff --git a/src/Compiler/SyntaxTree/SyntaxTrivia.fs b/src/Compiler/SyntaxTree/SyntaxTrivia.fs index 6a550c3b1a8..2cd42701e70 100644 --- a/src/Compiler/SyntaxTree/SyntaxTrivia.fs +++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fs @@ -420,6 +420,9 @@ type SynMemberDefnAbstractSlotTrivia = static member Zero = { GetSetKeywords = None } +[] +type SynMemberDefnInheritTrivia = { InheritKeyword: range } + [] type SynFieldTrivia = { diff --git a/src/Compiler/SyntaxTree/SyntaxTrivia.fsi b/src/Compiler/SyntaxTree/SyntaxTrivia.fsi index f16294b0a1d..ab6525bc010 100644 --- a/src/Compiler/SyntaxTree/SyntaxTrivia.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fsi @@ -522,6 +522,10 @@ type SynMemberDefnAbstractSlotTrivia = static member Zero: SynMemberDefnAbstractSlotTrivia +/// Represents additional information for SynMemberDefn.Inherit +[] +type SynMemberDefnInheritTrivia = { InheritKeyword: range } + /// Represents additional information for SynField [] type SynFieldTrivia = diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 185bd1ed842..fac3f30a073 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -2316,7 +2316,8 @@ opt_classDefn: inheritsDefn: | INHERIT atomTypeNonAtomicDeprecated optBaseSpec { let mDecl = unionRanges (rhs parseState 1) $2.Range - SynMemberDefn.Inherit($2, $3, mDecl) } + let trivia = { InheritKeyword = rhs parseState 1 } + SynMemberDefn.Inherit($2, $3, mDecl, trivia) } | INHERIT atomTypeNonAtomicDeprecated opt_HIGH_PRECEDENCE_APP atomicExprAfterType optBaseSpec { let mDecl = unionRanges (rhs parseState 1) $4.Range @@ -2324,8 +2325,9 @@ inheritsDefn: | INHERIT ends_coming_soon_or_recover { let mDecl = (rhs parseState 1) + let trivia = { InheritKeyword = (rhs parseState 1) } if not $2 then errorR (Error(FSComp.SR.parsTypeNameCannotBeEmpty (), mDecl)) - SynMemberDefn.Inherit(SynType.LongIdent(SynLongIdent([], [], [])), None, mDecl) } + SynMemberDefn.Inherit(SynType.LongIdent(SynLongIdent([], [], [])), None, mDecl, trivia) } optAsSpec: | asSpec diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ExceptionDefinitions/ExceptionDefinitions.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ExceptionDefinitions/ExceptionDefinitions.fs index fb7785d3758..1ec630b6e98 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ExceptionDefinitions/ExceptionDefinitions.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ExceptionDefinitions/ExceptionDefinitions.fs @@ -289,7 +289,7 @@ module ExceptionDefinition = |> compile |> shouldFail |> withDiagnostics [ - (Error 945, Line 9, Col 5, Line 9, Col 24, "Cannot inherit a sealed type") + (Error 945, Line 9, Col 13, Line 9, Col 22, "Cannot inherit a sealed type") (Error 1133, Line 9, Col 5, Line 9, Col 24, "No constructors are available for the type 'FSharpExn'") ] diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/TypeAbbreviations/TypeAbbreviations.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/TypeAbbreviations/TypeAbbreviations.fs index 80db08b3025..365f1af46b7 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/TypeAbbreviations/TypeAbbreviations.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/TypeAbbreviations/TypeAbbreviations.fs @@ -157,7 +157,7 @@ module TypeAbbreviations = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 945, Line 9, Col 9, Line 9, Col 22, "Cannot inherit a sealed type") + (Error 945, Line 9, Col 17, Line 9, Col 22, "Cannot inherit a sealed type") ] //SOURCE=E_PrivateTypeAbbreviation02.fs SCFLAGS="--test:ErrorRanges" # E_PrivateTypeAbbreviation02.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs index 26acb4b9d0f..0c61d444a9d 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs @@ -195,8 +195,8 @@ module UnionTypes = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 961, Line 10, Col 5, Line 10, Col 22, "This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e.g. 'inherit BaseType(args)'.") - (Error 945, Line 10, Col 5, Line 10, Col 22, "Cannot inherit a sealed type") + (Error 961, Line 10, Col 5, Line 10, Col 12, "This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e.g. 'inherit BaseType(args)'.") + (Error 945, Line 10, Col 13, Line 10, Col 22, "Cannot inherit a sealed type") ] //SOURCE=E_LowercaseDT.fs # E_LowercaseDT.fs diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs index 55f4d1cbf1b..44e8e202a94 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs @@ -815,4 +815,19 @@ type A() = default this.M() = () """ |> typecheck - |> shouldSucceed \ No newline at end of file + |> shouldSucceed + + [] + let ``This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e. g. 'inherit BaseType(args)'`` () = + Fsx """ +type IA = interface end + +type Class() = + inherit IA + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 961, Line 5, Col 5, Line 5, Col 12, "This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e.g. 'inherit BaseType(args)'.") + (Error 946, Line 5, Col 13, Line 5, Col 15, "Cannot inherit from interface type. Use interface ... with instead.") + ] \ No newline at end of file diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index 15e1dd848e6..f08d67883b7 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -8151,7 +8151,13 @@ FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewAu FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewGetSetMember(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynBinding], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynBinding], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberGetSetTrivia) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitCtor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynAccess], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynAttributeList], FSharp.Compiler.Syntax.SynPat, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Xml.PreXmlDoc, FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnImplicitCtorTrivia) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitInherit(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Syntax.SynExpr, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range) -FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range) +FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia get_trivia() +FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia trivia +FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia) +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: FSharp.Compiler.Text.Range InheritKeyword +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: FSharp.Compiler.Text.Range get_InheritKeyword() +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: System.String ToString() +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: Void .ctor(FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInterface(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynMemberDefn]], FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewLetBindings(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynBinding], Boolean, Boolean, FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewMember(FSharp.Compiler.Syntax.SynBinding, FSharp.Compiler.Text.Range) diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index 15e1dd848e6..f08d67883b7 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -8151,7 +8151,13 @@ FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewAu FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewGetSetMember(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynBinding], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynBinding], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberGetSetTrivia) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitCtor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynAccess], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynAttributeList], FSharp.Compiler.Syntax.SynPat, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Xml.PreXmlDoc, FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnImplicitCtorTrivia) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitInherit(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Syntax.SynExpr, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range) -FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range) +FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia get_trivia() +FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia trivia +FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia) +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: FSharp.Compiler.Text.Range InheritKeyword +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: FSharp.Compiler.Text.Range get_InheritKeyword() +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: System.String ToString() +FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: Void .ctor(FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInterface(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynMemberDefn]], FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewLetBindings(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynBinding], Boolean, Boolean, FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewMember(FSharp.Compiler.Syntax.SynBinding, FSharp.Compiler.Text.Range) diff --git a/tests/fsharp/typecheck/sigs/neg06.bsl b/tests/fsharp/typecheck/sigs/neg06.bsl index d55e3e948d2..4e28da2b6d7 100644 --- a/tests/fsharp/typecheck/sigs/neg06.bsl +++ b/tests/fsharp/typecheck/sigs/neg06.bsl @@ -10,7 +10,7 @@ neg06.fs(24,6,24,30): typecheck error FS0944: Abbreviated types cannot be given neg06.fs(27,6,27,33): typecheck error FS0942: Delegate types are always sealed -neg06.fs(31,9,31,29): typecheck error FS0945: Cannot inherit a sealed type +neg06.fs(31,17,31,27): typecheck error FS0945: Cannot inherit a sealed type neg06.fs(37,6,37,29): typecheck error FS0954: This type definition involves an immediate cyclic reference through a struct field or inheritance relation diff --git a/tests/fsharp/typecheck/sigs/neg10.bsl b/tests/fsharp/typecheck/sigs/neg10.bsl index 60e9056de56..31bcdb1882e 100644 --- a/tests/fsharp/typecheck/sigs/neg10.bsl +++ b/tests/fsharp/typecheck/sigs/neg10.bsl @@ -1,9 +1,9 @@ neg10.fsi(9,6,9,7): typecheck error FS0249: Two type definitions named 'x' occur in namespace 'N' in two parts of this assembly -neg10.fs(11,17,11,27): typecheck error FS0946: Cannot inherit from interface type. Use interface ... with instead. +neg10.fs(11,25,11,27): typecheck error FS0946: Cannot inherit from interface type. Use interface ... with instead. -neg10.fs(13,17,13,26): typecheck error FS0945: Cannot inherit a sealed type +neg10.fs(13,25,13,26): typecheck error FS0945: Cannot inherit a sealed type neg10.fs(15,22,15,32): typecheck error FS0887: The type 'C1' is not an interface type diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_StructInheritance01b.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_StructInheritance01b.fs index c8771146df5..38184a2ac82 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_StructInheritance01b.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_StructInheritance01b.fs @@ -2,7 +2,7 @@ // Verify error when trying to inherit from a struct type // Regression test for FSHARP1.0:2803 //FS0191: Cannot inherit from interface type -//Cannot inherit a sealed type +//Cannot inherit a sealed type type StructType = struct diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs index 4f9a24e00a8..e5998a72c51 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs @@ -2,10 +2,10 @@ // attribute must match inferred type //The kind of the type specified by its attributes does not match the kind implied by its definition //Structs, interfaces, enums and delegates cannot inherit from other types -//Cannot inherit from interface type\. Use interface \.\.\. with instead +//Cannot inherit from interface type\. Use interface \.\.\. with instead //The kind of the type specified by its attributes does not match the kind implied by its definition //Structs, interfaces, enums and delegates cannot inherit from other types -//Cannot inherit from interface type\. Use interface \.\.\. with instead +//Cannot inherit from interface type\. Use interface \.\.\. with instead // An interface type TK_I_003 = interface diff --git a/tests/service/data/SyntaxTree/Member/Inherit 01.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 01.fs.bsl index e138535c113..f10dc2c0997 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 01.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 01.fs.bsl @@ -13,7 +13,8 @@ ImplFile (Unspecified, [Inherit (LongIdent (SynLongIdent ([I], [], [None])), None, - (4,4--4,13))], (4,4--4,13)), [], None, (3,5--4,13), + (4,4--4,13), { InheritKeyword = (4,4--4,11) })], + (4,4--4,13)), [], None, (3,5--4,13), { LeadingKeyword = Type (3,0--3,4) EqualsRange = Some (3,7--3,8) WithKeyword = None })], (3,0--4,13))], diff --git a/tests/service/data/SyntaxTree/Member/Inherit 03.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 03.fs.bsl index eeab1704856..d0101bb0dd4 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 03.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 03.fs.bsl @@ -13,7 +13,8 @@ ImplFile (Unspecified, [Inherit (LongIdent (SynLongIdent ([], [], [])), None, - (4,4--4,11))], (4,4--4,11)), [], None, (3,5--4,11), + (4,4--4,11), { InheritKeyword = (4,4--4,11) })], + (4,4--4,11)), [], None, (3,5--4,11), { LeadingKeyword = Type (3,0--3,4) EqualsRange = Some (3,7--3,8) WithKeyword = None })], (3,0--4,11))], diff --git a/tests/service/data/SyntaxTree/Member/Inherit 04.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 04.fs.bsl index 9c03baf2b56..7d0dcfc450c 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 04.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 04.fs.bsl @@ -13,7 +13,8 @@ ImplFile (Unspecified, [Inherit (LongIdent (SynLongIdent ([], [], [])), None, - (4,4--4,11))], (4,4--4,11)), [], None, (3,5--4,11), + (4,4--4,11), { InheritKeyword = (4,4--4,11) })], + (4,4--4,11)), [], None, (3,5--4,11), { LeadingKeyword = Type (3,0--3,4) EqualsRange = Some (3,7--3,8) WithKeyword = None })], (3,0--4,11)); diff --git a/tests/service/data/SyntaxTree/Member/Inherit 05.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 05.fs.bsl index ddb47eb7ecc..ab71c976fe7 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 05.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 05.fs.bsl @@ -13,7 +13,7 @@ ImplFile (Unspecified, [Inherit (LongIdent (SynLongIdent ([], [], [])), None, - (4,4--4,11)); + (4,4--4,11), { InheritKeyword = (4,4--4,11) }); Member (SynBinding (None, Normal, false, false, [], diff --git a/tests/service/data/SyntaxTree/Member/Inherit 08.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 08.fs.bsl index fa0211259a4..757d0a30638 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 08.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 08.fs.bsl @@ -13,7 +13,7 @@ ImplFile (Unspecified, [Inherit (LongIdent (SynLongIdent ([], [], [])), None, - (4,4--4,11)); + (4,4--4,11), { InheritKeyword = (4,4--4,11) }); Member (SynBinding (None, Normal, false, false, [], From 7ebe5c5cd1303f3c8d1bf487cdcea5157708540c Mon Sep 17 00:00:00 2001 From: Jakub Majocha <1760221+majocha@users.noreply.github.com> Date: Tue, 15 Oct 2024 15:18:20 +0200 Subject: [PATCH 05/22] Asorted tests improvements (#17840) * named test runs in ci * unskip some old tests that actually do work * use some tasks in core\controlMailbox * remove timeouts from AsyncMemoize tests * use temp dir * remove unnecessary timeout * improve timing and don't leave unobserved background tasks running * remove another timeout * disable flaky TryScan test in script * Don't cancel MailboxProcessor body. * fix test * fix test * catch TCE --- azure-pipelines-PR.yml | 6 + .../CompilerService/AsyncMemoize.fs | 370 ++++++++---------- .../FSharpScriptTests.fs | 23 +- .../BuildGraphTests.fs | 19 +- .../ProjectAnalysisTests.fs | 9 +- .../Microsoft.FSharp.Control/AsyncModule.fs | 75 ++-- .../Microsoft.FSharp.Control/AsyncType.fs | 61 +-- .../Microsoft.FSharp.Control/Cancellation.fs | 37 +- .../MailboxProcessorType.fs | 129 ++++-- .../Microsoft.FSharp.Control/Tasks.fs | 45 ++- .../Microsoft.FSharp.Control/TasksDynamic.fs | 45 ++- .../Libraries/Core/Async/AsyncTests.fs | 16 +- tests/fsharp/core/controlMailbox/test.fsx | 188 ++++----- 13 files changed, 535 insertions(+), 488 deletions(-) diff --git a/azure-pipelines-PR.yml b/azure-pipelines-PR.yml index 0c7bc9b5a17..9a5c59441e2 100644 --- a/azure-pipelines-PR.yml +++ b/azure-pipelines-PR.yml @@ -488,6 +488,8 @@ stages: displayName: Publish Test Results inputs: testResultsFormat: 'XUnit' + testRunTitle: WindowsCompressedMetadata $(_testKind) + mergeTestResults: true testResultsFiles: '*.xml' searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_configuration)' continueOnError: true @@ -558,7 +560,9 @@ stages: displayName: Publish Test Results inputs: testResultsFormat: 'XUnit' + testRunTitle: Linux testResultsFiles: '*.xml' + mergeTestResults: true searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' continueOnError: true condition: always() @@ -602,6 +606,8 @@ stages: inputs: testResultsFormat: 'XUnit' testResultsFiles: '*.xml' + testRunTitle: MacOS + mergeTestResults: true searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' continueOnError: true condition: always() diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs index 72dd62e397c..7b65ba798fe 100644 --- a/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs +++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/AsyncMemoize.fs @@ -2,164 +2,149 @@ module CompilerService.AsyncMemoize open System open System.Threading -open Xunit open Internal.Utilities.Collections open System.Threading.Tasks open System.Diagnostics -open System.Collections.Concurrent + open FSharp.Compiler.DiagnosticsLogger open FSharp.Compiler.Diagnostics -open FSharp.Compiler.BuildGraph +open Xunit -let timeout = TimeSpan.FromSeconds 10. +[] +module internal JobEvents = -let waitFor (mre: ManualResetEvent) = - if not <| mre.WaitOne timeout then - failwith "waitFor timed out" + let publishEvent (cache: AsyncMemoize<_, _, _>) = + let wrapper = Event<_>() + cache.OnEvent (fun e -> lock wrapper <| fun () -> wrapper.Trigger e) + wrapper.Publish |> Event.map (fun (jobEvent, (_,k,_)) -> jobEvent, k) -let waitUntil condition value = - task { - let sw = Stopwatch.StartNew() - while not <| condition value do - if sw.Elapsed > timeout then - failwith "waitUntil timed out" - do! Task.Delay 10 - } + let collectEvents cache = + cache |> publishEvent |> Event.scan (fun es e -> e :: es) [] |> Event.map List.rev -let rec internal spinFor (duration: TimeSpan) = - async { - let sw = Stopwatch.StartNew() - do! Async.Sleep 10 - let remaining = duration - sw.Elapsed - if remaining > TimeSpan.Zero then - return! spinFor remaining - } - -#if BUILDING_WITH_LKG -type internal EventRecorder<'a, 'b, 'c when 'a : equality and 'b : equality>(memoize: AsyncMemoize<'a,'b,'c>) as self = -#else -type internal EventRecorder<'a, 'b, 'c when 'a : equality and 'b : equality and 'a:not null and 'b:not null>(memoize: AsyncMemoize<'a,'b,'c>) as self = -#endif + /// Exposes a live view of the list of JobEvents generated by AsyncMemoize. + let observe cache = + let updateAvailable = new AutoResetEvent(false) + let mutable recorded = [] - let events = ConcurrentQueue() + let update next = + Debug.WriteLine $"%A{next}" + recorded <- next + updateAvailable.Set() |> ignore - do memoize.OnEvent self.Add + collectEvents cache |> Event.add update - member _.Add (e, (_label, k, _version)) = events.Enqueue (e, k) + let waitForUpdate = updateAvailable |> Async.AwaitWaitHandle |> Async.Ignore - member _.Received value = events |> Seq.exists (fst >> (=) value) - - member _.CountOf value count = events |> Seq.filter (fst >> (=) value) |> Seq.length |> (=) count + async { + Debug.WriteLine $"current: %A{recorded}" + return recorded, waitForUpdate + } - member _.ShouldBe (expected) = - let expected = expected |> Seq.toArray - let actual = events |> Seq.toArray - Assert.Equal<_ array>(expected, actual) + let countOf value count events = events |> Seq.filter (fst >> (=) value) |> Seq.length |> (=) count - member _.Sequence = events |> Seq.map id + let received value events = events |> Seq.exists (fst >> (=) value) + let waitUntil observedCache condition = + let rec loop() = async { + let! current, waitForUpdate = observedCache + if current |> condition |> not then + do! waitForUpdate + return! loop() + } + loop() [] let ``Basics``() = - - let computation key = async { - do! Async.Sleep 1 - return key * 2 - } - - let memoize = AsyncMemoize() - let events = EventRecorder(memoize) - - let result = - seq { - memoize.Get'(5, computation 5) - memoize.Get'(5, computation 5) - memoize.Get'(2, computation 2) - memoize.Get'(5, computation 5) - memoize.Get'(3, computation 3) - memoize.Get'(2, computation 2) + task { + let computation key = async { + do! Async.Sleep 1 + return key * 2 } - |> Async.Parallel - |> Async.RunSynchronously - let expected = [| 10; 10; 4; 10; 6; 4|] + let memoize = AsyncMemoize() + let events = observe memoize + + let result = + seq { + memoize.Get'(5, computation 5) + memoize.Get'(5, computation 5) + memoize.Get'(2, computation 2) + memoize.Get'(5, computation 5) + memoize.Get'(3, computation 3) + memoize.Get'(2, computation 2) + } + |> Async.Parallel + |> Async.RunSynchronously - Assert.Equal(expected, result) + let expected = [| 10; 10; 4; 10; 6; 4|] - (waitUntil (events.CountOf Finished) 3).Wait() + Assert.Equal(expected, result) - let groups = events.Sequence |> Seq.groupBy snd |> Seq.toList - Assert.Equal(3, groups.Length) - for key, events in groups do - Assert.Equal>(Set [ Requested, key; Started, key; Finished, key ], Set events) + do! waitUntil events (countOf Finished 3) + let! current, _ = events + let groups = current |> Seq.groupBy snd |> Seq.toList + Assert.Equal(3, groups.Length) + for key, events in groups do + Assert.Equal>(Set [ Requested, key; Started, key; Finished, key ], Set events) + } [] let ``We can cancel a job`` () = task { - let jobStarted = new ManualResetEvent(false) + let jobStarted = new ManualResetEventSlim(false) + let cts = new CancellationTokenSource() + let ctsCancelled = new ManualResetEventSlim(false) - let computation action = async { - action() |> ignore - do! spinFor timeout + let computation = async { + use! _catch = Async.OnCancel ignore + jobStarted.Set() + ctsCancelled.Wait() + do! async { } failwith "Should be canceled before it gets here" } let memoize = AsyncMemoize<_, int, _>() - let events = EventRecorder(memoize) - - use cts1 = new CancellationTokenSource() - use cts2 = new CancellationTokenSource() - use cts3 = new CancellationTokenSource() + let events = observe memoize let key = 1 - let _task1 = Async.StartAsTask( memoize.Get'(key, computation jobStarted.Set), cancellationToken = cts1.Token) - - waitFor jobStarted - jobStarted.Reset() |> ignore + let _task1 = Async.StartAsTask( memoize.Get'(1, computation), cancellationToken = cts.Token) - let _task2 = Async.StartAsTask( memoize.Get'(key, computation ignore), cancellationToken = cts2.Token) - let _task3 = Async.StartAsTask( memoize.Get'(key, computation ignore), cancellationToken = cts3.Token) + jobStarted.Wait() + cts.Cancel() + ctsCancelled.Set() - do! waitUntil (events.CountOf Requested) 3 + do! waitUntil events (received Canceled) + let! current, _ = events - cts1.Cancel() - cts2.Cancel() - - waitFor jobStarted - - cts3.Cancel() - - do! waitUntil events.Received Canceled - - events.ShouldBe [ - Requested, key - Started, key - Requested, key - Requested, key - Restarted, key - Canceled, key - ] + Assert.Equal<_ list>( + [ + Requested, key + Started, key + Canceled, key + ], + current + ) } [] let ``Job is restarted if first requestor cancels`` () = task { - let jobStarted = new ManualResetEvent(false) + let jobStarted = new SemaphoreSlim(0) - let jobCanComplete = new ManualResetEvent(false) + let jobCanComplete = new ManualResetEventSlim(false) let computation key = async { - jobStarted.Set() |> ignore - waitFor jobCanComplete + jobStarted.Release() |> ignore + + jobCanComplete.Wait() return key * 2 } let memoize = AsyncMemoize<_, int, _>() - let events = EventRecorder(memoize) - + let events = observe memoize use cts1 = new CancellationTokenSource() use cts2 = new CancellationTokenSource() @@ -169,48 +154,49 @@ let ``Job is restarted if first requestor cancels`` () = let _task1 = Async.StartAsTask( memoize.Get'(key, computation key), cancellationToken = cts1.Token) - waitFor jobStarted - jobStarted.Reset() |> ignore - + do! jobStarted.WaitAsync() let _task2 = Async.StartAsTask( memoize.Get'(key, computation key), cancellationToken = cts2.Token) let _task3 = Async.StartAsTask( memoize.Get'(key, computation key), cancellationToken = cts3.Token) - do! waitUntil (events.CountOf Requested) 3 + do! waitUntil events (countOf Requested 3) cts1.Cancel() - waitFor jobStarted - jobCanComplete.Set() |> ignore + do! jobStarted.WaitAsync() + let! result = _task2 Assert.Equal(2, result) - events.ShouldBe [ - Requested, key + let! current, _ = events + + Assert.Equal<_ list>( + [ Requested, key Started, key Requested, key Requested, key Restarted, key - Finished, key ] + Finished, key ], + current + ) } [] let ``Job is restarted if first requestor cancels but keeps running if second requestor cancels`` () = task { - let jobStarted = new ManualResetEvent(false) + let jobStarted = new ManualResetEventSlim(false) - let jobCanComplete = new ManualResetEvent(false) + let jobCanComplete = new ManualResetEventSlim(false) let computation key = async { jobStarted.Set() |> ignore - waitFor jobCanComplete + jobCanComplete.Wait() return key * 2 } let memoize = AsyncMemoize<_, int, _>() - let events = EventRecorder(memoize) - + let events = observe memoize use cts1 = new CancellationTokenSource() use cts2 = new CancellationTokenSource() @@ -220,17 +206,17 @@ let ``Job is restarted if first requestor cancels but keeps running if second re let _task1 = Async.StartAsTask( memoize.Get'(key, computation key), cancellationToken = cts1.Token) - waitFor jobStarted + jobStarted.Wait() jobStarted.Reset() |> ignore let _task2 = Async.StartAsTask( memoize.Get'(key, computation key), cancellationToken = cts2.Token) let _task3 = Async.StartAsTask( memoize.Get'(key, computation key), cancellationToken = cts3.Token) - do! waitUntil (events.CountOf Requested) 3 + do! waitUntil events (countOf Requested 3) cts1.Cancel() - waitFor jobStarted + jobStarted.Wait() cts2.Cancel() @@ -239,13 +225,17 @@ let ``Job is restarted if first requestor cancels but keeps running if second re let! result = _task3 Assert.Equal(2, result) - events.ShouldBe [ - Requested, key + let! current, _ = events + + Assert.Equal<_ list>( + [ Requested, key Started, key Requested, key Requested, key Restarted, key - Finished, key ] + Finished, key ], + current + ) } @@ -376,59 +366,56 @@ let ``Stress test`` () = [] [] let ``Cancel running jobs with the same key`` cancelDuplicate expectFinished = - task { - let cache = AsyncMemoize(cancelDuplicateRunningJobs=cancelDuplicate) - - let mutable started = 0 - let mutable finished = 0 + let cache = AsyncMemoize(cancelDuplicateRunningJobs=cancelDuplicate) - let job1started = new ManualResetEvent(false) - let job1finished = new ManualResetEvent(false) + let mutable started = 0 + let mutable finished = 0 - let jobCanContinue = new ManualResetEvent(false) + let job1started = new ManualResetEventSlim(false) + let job1finished = new ManualResetEventSlim(false) - let job2started = new ManualResetEvent(false) - let job2finished = new ManualResetEvent(false) + let jobCanContinue = new ManualResetEventSlim(false) - let work onStart onFinish = async { - Interlocked.Increment &started |> ignore - onStart() |> ignore - waitFor jobCanContinue - do! spinFor (TimeSpan.FromMilliseconds 100) - Interlocked.Increment &finished |> ignore - onFinish() |> ignore - } + let job2started = new ManualResetEventSlim(false) + let job2finished = new ManualResetEventSlim(false) - let key1 = - { new ICacheKey<_, _> with - member _.GetKey() = 1 - member _.GetVersion() = 1 - member _.GetLabel() = "key1" } + let work onStart onFinish = async { + Interlocked.Increment &started |> ignore + onStart() |> ignore + jobCanContinue.Wait() + do! Async.Sleep 100 + Interlocked.Increment &finished |> ignore + onFinish() |> ignore + } - cache.Get(key1, work job1started.Set job1finished.Set) |> Async.Start + let key1 = + { new ICacheKey<_, _> with + member _.GetKey() = 1 + member _.GetVersion() = 1 + member _.GetLabel() = "key1" } - waitFor job1started + cache.Get(key1, work job1started.Set job1finished.Set) |> Async.Catch |> Async.Ignore |> Async.Start - let key2 = - { new ICacheKey<_, _> with - member _.GetKey() = key1.GetKey() - member _.GetVersion() = key1.GetVersion() + 1 - member _.GetLabel() = "key2" } + job1started.Wait() - cache.Get(key2, work job2started.Set job2finished.Set ) |> Async.Start + let key2 = + { new ICacheKey<_, _> with + member _.GetKey() = key1.GetKey() + member _.GetVersion() = key1.GetVersion() + 1 + member _.GetLabel() = "key2" } - waitFor job2started + cache.Get(key2, work job2started.Set job2finished.Set ) |> Async.Catch |> Async.Ignore |> Async.Start - jobCanContinue.Set() |> ignore + job2started.Wait() - waitFor job2finished + jobCanContinue.Set() |> ignore - if not cancelDuplicate then - waitFor job1finished - - Assert.Equal((2, expectFinished), (started, finished)) - } + job2finished.Wait() + + if not cancelDuplicate then + job1finished.Wait() + Assert.Equal((2, expectFinished), (started, finished)) type DummyException(msg) = inherit Exception(msg) @@ -490,7 +477,7 @@ let ``Preserve thread static diagnostics`` () = let diagnostics = diagnosticsLogger.GetDiagnostics() - //Assert.Equal(3, diagnostics.Length) + Assert.Equal(4, diagnostics.Length) return result, diagnostics } @@ -498,9 +485,9 @@ let ``Preserve thread static diagnostics`` () = let results = (Task.WhenAll tasks).Result - let _diagnosticCounts = results |> Seq.map snd |> Seq.map Array.length |> Seq.groupBy id |> Seq.map (fun (k, v) -> k, v |> Seq.length) |> Seq.sortBy fst |> Seq.toList + let diagnosticCounts = results |> Seq.map snd |> Seq.map Array.length |> Seq.groupBy id |> Seq.map (fun (k, v) -> k, v |> Seq.length) |> Seq.sortBy fst |> Seq.toList - //Assert.Equal<(int * int) list>([4, 100], diagnosticCounts) + Assert.Equal<(int * int) list>([4, 100], diagnosticCounts) let diagnosticMessages = results |> Seq.map snd |> Seq.map (Array.map (fun (d, _) -> d.Exception.Message) >> Array.toList) |> Set @@ -523,7 +510,7 @@ let ``Preserve thread static diagnostics already completed job`` () = return Ok input } - async { + task { let diagnosticsLogger = CompilationDiagnosticLogger($"Testing", FSharpDiagnosticOptions.Default) @@ -534,10 +521,9 @@ let ``Preserve thread static diagnostics already completed job`` () = let diagnosticMessages = diagnosticsLogger.GetDiagnostics() |> Array.map (fun (d, _) -> d.Exception.Message) |> Array.toList - Assert.Equal>(["job 1 error"; "job 1 error"], diagnosticMessages) + Assert.Equal<_ list>(["job 1 error"; "job 1 error"], diagnosticMessages) } - |> Async.StartAsTask [] @@ -550,34 +536,22 @@ let ``We get diagnostics from the job that failed`` () = member _.GetVersion() = 1 member _.GetLabel() = "job1" } - let job (input: int) = async { - let ex = DummyException($"job {input} error") - do! Async.Sleep 100 - DiagnosticsThreadStatics.DiagnosticsLogger.Error(ex) + let job = async { + let ex = DummyException($"job error") + + // no recovery + DiagnosticsThreadStatics.DiagnosticsLogger.Error ex return 5 } - let result = - [1; 2] - |> Seq.map (fun i -> - async { - let diagnosticsLogger = CompilationDiagnosticLogger($"Testing", FSharpDiagnosticOptions.Default) - - use _ = new CompilationGlobalsScope(diagnosticsLogger, BuildPhase.Optimize) - try - let! _ = cache.Get(key, job i ) - () - with _ -> - () - let diagnosticMessages = diagnosticsLogger.GetDiagnostics() |> Array.map (fun (d, _) -> d.Exception.Message) |> Array.toList - - return diagnosticMessages - }) - |> Async.Parallel - |> Async.StartAsTask - |> (fun t -> t.Result) - |> Array.toList - - Assert.True( - result = [["job 1 error"]; ["job 1 error"]] || - result = [["job 2 error"]; ["job 2 error"]] ) + task { + let logger = CapturingDiagnosticsLogger("AsyncMemoize diagnostics test") + + SetThreadDiagnosticsLoggerNoUnwind logger + + do! cache.Get(key, job ) |> Async.Catch |> Async.Ignore + + let messages = logger.Diagnostics |> List.map fst |> List.map _.Exception.Message + + Assert.Equal<_ list>(["job error"], messages) + } diff --git a/tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs b/tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs index aff47308ad2..bf3a9cbaac6 100644 --- a/tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs +++ b/tests/FSharp.Compiler.Private.Scripting.UnitTests/FSharpScriptTests.fs @@ -12,12 +12,16 @@ open System.Threading.Tasks open FSharp.Compiler.Interactive open FSharp.Compiler.Interactive.Shell open FSharp.Test.ScriptHelpers -open FSharp.Test.Utilities open Xunit type InteractiveTests() = + let copyHousingToTemp() = + let tempName = TestFramework.getTemporaryFileName() + File.Copy(__SOURCE_DIRECTORY__ ++ "housing.csv", tempName + ".csv") + tempName + [] member _.``ValueRestriction error message should not have type variables fully solved``() = use script = new FSharpScript() @@ -248,10 +252,10 @@ System.Configuration.ConfigurationManager.AppSettings.Item "Environment" <- "LOC if RuntimeInformation.ProcessArchitecture = Architecture.Arm64 then () else - let code = @" -#r ""nuget:Microsoft.ML,version=1.4.0-preview"" -#r ""nuget:Microsoft.ML.AutoML,version=0.16.0-preview"" -#r ""nuget:Microsoft.Data.Analysis,version=0.4.0"" + let code = $""" +#r "nuget:Microsoft.ML,version=1.4.0-preview" +#r "nuget:Microsoft.ML.AutoML,version=0.16.0-preview" +#r "nuget:Microsoft.Data.Analysis,version=0.4.0" open System open System.IO @@ -267,7 +271,7 @@ let Shuffle (arr:int[]) = arr.[i] <- temp arr -let housingPath = ""housing.csv"" +let housingPath = @"{copyHousingToTemp()}.csv" let housingData = DataFrame.LoadCsv(housingPath) let randomIndices = (Shuffle(Enumerable.Range(0, (int (housingData.Rows.Count) - 1)).ToArray())) let testSize = int (float (housingData.Rows.Count) * 0.1) @@ -281,11 +285,11 @@ open Microsoft.ML.AutoML let mlContext = MLContext() let experiment = mlContext.Auto().CreateRegressionExperiment(maxExperimentTimeInSeconds = 15u) -let result = experiment.Execute(housing_train, labelColumnName = ""median_house_value"") +let result = experiment.Execute(housing_train, labelColumnName = "median_house_value") let details = result.RunDetails -printfn ""%A"" result +printfn "{@"%A"}" result 123 -" +""" use script = new FSharpScript(additionalArgs=[| |]) let opt = script.Eval(code) |> getValue let value = opt.Value @@ -511,3 +515,4 @@ let add (col:IServiceCollection) = use script = new FSharpScript(additionalArgs=[| |]) let _value,diag = script.Eval(code) Assert.Empty(diag) + diff --git a/tests/FSharp.Compiler.Service.Tests/BuildGraphTests.fs b/tests/FSharp.Compiler.Service.Tests/BuildGraphTests.fs index 16b0ff7b878..4769b4c322d 100644 --- a/tests/FSharp.Compiler.Service.Tests/BuildGraphTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/BuildGraphTests.fs @@ -385,22 +385,17 @@ module BuildGraphTests = for i in 1 .. 300 do async { - Interlocked.Increment(&count) |> ignore - errorR (ExampleException $"{i}") + errorR (ExampleException $"{Interlocked.Increment(&count)}") + error (ExampleException $"{Interlocked.Increment(&count)}") } ] - let run = - tasks |> MultipleDiagnosticsLoggers.Parallel |> Async.Catch |> Async.StartAsTask - - Assert.True( - run.Wait(1000), - "MultipleDiagnosticsLoggers.Parallel did not finish." - ) - - // Diagnostics from all started tasks should be collected despite the exception. - errorCountShouldBe count + task { + do! tasks |> MultipleDiagnosticsLoggers.Parallel |> Async.Catch |> Async.Ignore + // Diagnostics from all started tasks should be collected despite the exception. + errorCountShouldBe count + } [] let ``AsyncLocal diagnostics context flows correctly`` () = diff --git a/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs b/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs index 78d03ac8a9b..5752f9de41c 100644 --- a/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs @@ -123,7 +123,14 @@ let ``Test project1 and make sure TcImports gets cleaned up`` () = let weakTcImports = test () checker.InvalidateConfiguration Project1.options checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() - GC.Collect(2, GCCollectionMode.Forced, blocking = true) + + //collect 2 more times for good measure, + // See for example: https://github.com/dotnet/runtime/discussions/108081 + GC.Collect() + GC.WaitForPendingFinalizers() + GC.Collect() + GC.WaitForPendingFinalizers() + Assert.False weakTcImports.IsAlive [] diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs index 145d9a70c3e..213ff435adf 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncModule.fs @@ -7,6 +7,7 @@ namespace FSharp.Core.UnitTests.Control open System open System.Threading +open System.Threading.Tasks open FSharp.Core.UnitTests.LibraryTestFx open Xunit open FsCheck @@ -273,8 +274,7 @@ type AsyncModule() = } Async.RunSynchronously test - // test is flaky: https://github.com/dotnet/fsharp/issues/11586 - //[] + [] member _.``OnCancel.RaceBetweenCancellationHandlerAndDisposingHandlerRegistration``() = let test() = use flag = new ManualResetEvent(false) @@ -297,8 +297,7 @@ type AsyncModule() = for _i = 1 to 300 do test() - // test is flaky: https://github.com/dotnet/fsharp/issues/11586 - //[] + [] member _.``OnCancel.RaceBetweenCancellationAndDispose``() = let mutable flag = 0 let cts = new System.Threading.CancellationTokenSource() @@ -316,8 +315,7 @@ type AsyncModule() = :? System.OperationCanceledException -> () Assert.AreEqual(1, flag) - // test is flaky: https://github.com/dotnet/fsharp/issues/11586 - //[] + [] member _.``OnCancel.CancelThatWasSignalledBeforeRunningTheComputation``() = let test() = let cts = new System.Threading.CancellationTokenSource() @@ -379,23 +377,25 @@ type AsyncModule() = [] member _.``AwaitWaitHandle.DisposedWaitHandle2``() = - let wh = new System.Threading.ManualResetEvent(false) - let barrier = new System.Threading.ManualResetEvent(false) + let wh = new ManualResetEvent(false) + let started = new ManualResetEventSlim(false) - let test = async { - let! timeout = Async.AwaitWaitHandle(wh, 10000) - Assert.False(timeout, "Timeout expected") - barrier.Set() |> ignore + let test = + async { + started.Set() + let! timeout = Async.AwaitWaitHandle(wh, 5000) + Assert.False(timeout, "Timeout expected") } - Async.Start test - - // await 3 secs then dispose waithandle - nothing should happen - let timeout = wait barrier 3000 - Assert.False(timeout, "Barrier was reached too early") - dispose wh - - let ok = wait barrier 10000 - if not ok then Assert.Fail("Async computation was not completed in given time") + |> Async.StartAsTask + + task { + started.Wait() + // Wait a moment then dispose waithandle - nothing should happen + do! Task.Delay 500 + Assert.False(test.IsCompleted, "Test completed too early") + dispose wh + do! test + } [] member _.``RunSynchronously.NoThreadJumpsAndTimeout``() = @@ -467,22 +467,24 @@ type AsyncModule() = [] member _.``error on one workflow should cancel all others``() = - let counter = - async { - let mutable counter = 0 - let job i = async { - if i = 55 then failwith "boom" - else - do! Async.Sleep 1000 - counter <- counter + 1 - } - - let! _ = Async.Parallel [ for i in 1 .. 100 -> job i ] |> Async.Catch - do! Async.Sleep 5000 - return counter - } |> Async.RunSynchronously + task { + use failOnlyOne = new Semaphore(0, 1) + let mutable cancelled = 0 + let mutable started = 0 + + let job i = async { + Interlocked.Increment &started |> ignore + use! holder = Async.OnCancel (fun () -> Interlocked.Increment &cancelled |> ignore) + do! failOnlyOne |> Async.AwaitWaitHandle |> Async.Ignore + failwith "boom" + } - Assert.AreEqual(0, counter) + let test = Async.Parallel [ for i in 1 .. 100 -> job i ] |> Async.Catch |> Async.Ignore |> Async.StartAsTask + do! Task.Delay 100 + failOnlyOne.Release() |> ignore + do! test + Assert.Equal(started - 1, cancelled) + } [] member _.``AwaitWaitHandle.ExceptionsAfterTimeout``() = @@ -641,7 +643,6 @@ type AsyncModule() = member _.``Parallel with maxDegreeOfParallelism`` () = let mutable i = 1 let action j = async { - do! Async.Sleep 1 Assert.Equal(j, i) i <- i + 1 } diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs index 950432ccc8e..1b15be8fa98 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/AsyncType.fs @@ -54,16 +54,20 @@ type AsyncType() = [] member _.AsyncRunSynchronouslyReusesThreadPoolThread() = - let action = async { async { () } |> Async.RunSynchronously } - let computation = - [| for i in 1 .. 1000 -> action |] - |> Async.Parallel + let action _ = + async { + return + async { return Thread.CurrentThread.ManagedThreadId } + |> Async.RunSynchronously + } // This test needs approximately 1000 ThreadPool threads // if Async.RunSynchronously doesn't reuse them. - // In such case TimeoutException is raised - // since ThreadPool cannot provide 1000 threads in 1 second - // (the number of threads in ThreadPool is adjusted slowly). - Async.RunSynchronously(computation, timeout = 1000) |> ignore + let usedThreads = + Seq.init 1000 action + |> Async.Parallel + |> Async.RunSynchronously + |> Set.ofArray + Assert.True(usedThreads.Count < 256, $"RunSynchronously used {usedThreads.Count} threads.") [] [] @@ -231,7 +235,8 @@ type AsyncType() = use t = Async.StartAsTask a let mutable exceptionThrown = false try - waitASec t + // waitASec t + t.Wait() with e -> exceptionThrown <- true Assert.True (t.IsFaulted) @@ -269,7 +274,7 @@ type AsyncType() = // printfn "%A" t.Status let mutable exceptionThrown = false try - waitASec t + t.Wait() with e -> exceptionThrown <- true Assert.True (exceptionThrown) Assert.True(t.IsCanceled) @@ -302,56 +307,50 @@ type AsyncType() = use t = Async.StartImmediateAsTask a let mutable exceptionThrown = false try - waitASec t + t.Wait() with e -> exceptionThrown <- true Assert.True (t.IsFaulted) Assert.True(exceptionThrown) -#if IGNORED [] - [] member _.CancellationPropagatesToImmediateTask () = let a = async { - while true do () + while true do + do! Async.Sleep 100 } use t = Async.StartImmediateAsTask a Async.CancelDefaultToken () let mutable exceptionThrown = false try - waitASec t + t.Wait() with e -> exceptionThrown <- true Assert.True (exceptionThrown) Assert.True(t.IsCanceled) -#endif -#if IGNORED [] - [] member _.CancellationPropagatesToGroupImmediate () = let ewh = new ManualResetEvent(false) - let cancelled = ref false + let mutable cancelled = false let a = async { - use! holder = Async.OnCancel (fun _ -> cancelled := true) + use! holder = Async.OnCancel (fun _ -> cancelled <- true) ewh.Set() |> Assert.True - while true do () + while true do + do! Async.Sleep 100 } let cts = new CancellationTokenSource() let token = cts.Token use t = Async.StartImmediateAsTask(a, cancellationToken=token) -// printfn "%A" t.Status ewh.WaitOne() |> Assert.True cts.Cancel() -// printfn "%A" t.Status let mutable exceptionThrown = false try - waitASec t + t.Wait() with e -> exceptionThrown <- true Assert.True (exceptionThrown) Assert.True(t.IsCanceled) - Assert.True(!cancelled) -#endif + Assert.True(cancelled) [] member _.TaskAsyncValue () = @@ -411,8 +410,7 @@ type AsyncType() = } Async.RunSynchronously(a) |> Assert.True - // test is flaky: https://github.com/dotnet/fsharp/issues/11586 - //[] + [] member _.TaskAsyncValueCancellation () = use ewh = new ManualResetEvent(false) let cts = new CancellationTokenSource() @@ -430,9 +428,11 @@ type AsyncType() = :? TaskCanceledException -> ewh.Set() |> ignore // this is ok } - Async.Start a + let t1 = Async.StartAsTask a cts.Cancel() ewh.WaitOne(10000) |> ignore + // Don't leave unobserved background tasks, because they can crash the test run. + t1.Wait() [] member _.NonGenericTaskAsyncValue () = @@ -473,9 +473,10 @@ type AsyncType() = :? TaskCanceledException -> ewh.Set() |> ignore // this is ok } - Async.Start a + let t1 = Async.StartAsTask a cts.Cancel() ewh.WaitOne(10000) |> ignore + t1.Wait() [] member _.CancellationExceptionThrown () = diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Cancellation.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Cancellation.fs index 4e04f64bc1f..cecfaec7590 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Cancellation.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Cancellation.fs @@ -5,7 +5,9 @@ namespace FSharp.Core.UnitTests.Control open System open FSharp.Core.UnitTests.LibraryTestFx open Xunit +open FSharp.Test open System.Threading +open System.Threading.Tasks type CancellationType() = @@ -229,6 +231,7 @@ type CancellationType() = } asyncs |> Async.Parallel |> Async.RunSynchronously |> ignore + // See https://github.com/dotnet/fsharp/issues/3254 [] member this.AwaitTaskCancellationAfterAsyncTokenCancellation() = let StartCatchCancellation cancellationToken (work) = @@ -262,11 +265,11 @@ type CancellationType() = let cts = new CancellationTokenSource() let tcs = System.Threading.Tasks.TaskCompletionSource<_>() - let t = + let test() = async { do! tcs.Task |> Async.AwaitTask } - |> StartAsTaskProperCancel None (Some cts.Token) + |> StartAsTaskProperCancel None (Some cts.Token) :> Task // First cancel the token, then set the task as cancelled. async { @@ -274,15 +277,31 @@ type CancellationType() = cts.Cancel() do! Async.Sleep 100 tcs.TrySetException (TimeoutException "Task timed out after token.") - |> ignore + |> ignore } |> Async.Start - try - let res = t.Wait(2000) - let msg = sprintf "Excepted TimeoutException wrapped in an AggregateException, but got %A" res - printfn "failure msg: %s" msg - Assert.Fail (msg) - with :? AggregateException as agg -> () + task { + let! agg = Assert.ThrowsAsync(test) + let inner = agg.InnerException + Assert.True(inner :? TimeoutException, $"Excepted TimeoutException wrapped in an AggregateException, but got %A{inner}") + } + + // Simpler regression test for https://github.com/dotnet/fsharp/issues/3254 + [] + member this.AwaitTaskCancellationAfterAsyncTokenCancellation2() = + let tcs = new TaskCompletionSource() + let cts = new CancellationTokenSource() + let _ = cts.Token.Register(fun () -> tcs.SetResult 42) + Assert.ThrowsAsync( fun () -> + Async.StartAsTask( + async { + cts.CancelAfter 100 + let! result = tcs.Task |> Async.AwaitTask + return result + }, + cancellationToken = cts.Token + ) + ) [] member this.Equality() = diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/MailboxProcessorType.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/MailboxProcessorType.fs index 904bc7dc622..f3964aaa78c 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/MailboxProcessorType.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/MailboxProcessorType.fs @@ -125,7 +125,7 @@ type MailboxProcessorType() = use mre2 = new ManualResetEventSlim(false) // https://github.com/dotnet/fsharp/issues/3337 - let cts = new CancellationTokenSource () + use cts = new CancellationTokenSource () let addMsg msg = match result with @@ -204,25 +204,24 @@ type MailboxProcessorType() = [] member this.``Receive Races with Post``() = - let receiveEv = new ManualResetEvent(false) - let postEv = new ManualResetEvent(false) - let finishedEv = new ManualResetEvent(false) + let receiveEv = new AutoResetEvent(false) + let postEv = new AutoResetEvent(false) + let finishedEv = new AutoResetEvent(false) + use cts = new CancellationTokenSource() let mb = MailboxProcessor.Start ( fun inbox -> async { while true do - let w = receiveEv.WaitOne() - receiveEv.Reset() |> ignore + receiveEv.WaitOne() |> ignore let! (msg) = inbox.Receive () finishedEv.Set() |> ignore }) let post = async { - while true do - let r = postEv.WaitOne() - postEv.Reset() |> ignore + while not cts.IsCancellationRequested do + postEv.WaitOne() |> ignore mb.Post(fun () -> ()) - } |> Async.Start + } |> Async.StartAsTask for i in 0 .. 100000 do if i % 2 = 0 then receiveEv.Set() |> ignore @@ -232,19 +231,23 @@ type MailboxProcessorType() = receiveEv.Set() |> ignore finishedEv.WaitOne() |> ignore - finishedEv.Reset() |> ignore + + cts.Cancel() + // Let the post task finish. + postEv.Set() |> ignore + post.Wait() [] member this.``Receive Races with Post on timeout``() = - let receiveEv = new ManualResetEvent(false) - let postEv = new ManualResetEvent(false) - let finishedEv = new ManualResetEvent(false) + let receiveEv = new AutoResetEvent(false) + let postEv = new AutoResetEvent(false) + let finishedEv = new AutoResetEvent(false) + use cts = new CancellationTokenSource() let mb = MailboxProcessor.Start ( fun inbox -> async { while true do - let w = receiveEv.WaitOne() - receiveEv.Reset() |> ignore + receiveEv.WaitOne() |> ignore let! (msg) = inbox.Receive (5000) finishedEv.Set() |> ignore }) @@ -252,12 +255,11 @@ type MailboxProcessorType() = let isErrored = mb.Error |> Async.AwaitEvent |> Async.StartAsTask let post = - async { - while true do - let r = postEv.WaitOne() - postEv.Reset() |> ignore + backgroundTask { + while not cts.IsCancellationRequested do + postEv.WaitOne() |> ignore mb.Post(fun () -> ()) - } |> Async.Start + } for i in 0 .. 10000 do if i % 2 = 0 then @@ -271,32 +273,35 @@ type MailboxProcessorType() = if isErrored.IsCompleted then raise <| Exception("Mailbox should not fail!", isErrored.Result) - finishedEv.Reset() |> ignore + cts.Cancel() + // Let the post task finish. + postEv.Set() |> ignore + post.Wait() [] member this.``TryReceive Races with Post on timeout``() = - let receiveEv = new ManualResetEvent(false) - let postEv = new ManualResetEvent(false) - let finishedEv = new ManualResetEvent(false) + let receiveEv = new AutoResetEvent(false) + let postEv = new AutoResetEvent(false) + let finishedEv = new AutoResetEvent(false) + use cts = new CancellationTokenSource() let mb = MailboxProcessor.Start ( fun inbox -> async { while true do - let w = receiveEv.WaitOne() - receiveEv.Reset() |> ignore + receiveEv.WaitOne() |> ignore let! (msg) = inbox.TryReceive (5000) finishedEv.Set() |> ignore - }) + } + ) let isErrored = mb.Error |> Async.AwaitEvent |> Async.StartAsTask let post = - async { - while true do - let r = postEv.WaitOne() - postEv.Reset() |> ignore + backgroundTask { + while not cts.IsCancellationRequested do + postEv.WaitOne() |> ignore mb.Post(fun () -> ()) - } |> Async.Start + } for i in 0 .. 10000 do if i % 2 = 0 then @@ -310,7 +315,9 @@ type MailboxProcessorType() = if isErrored.IsCompleted then raise <| Exception("Mailbox should not fail!", isErrored.Result) - finishedEv.Reset() |> ignore + cts.Cancel() + postEv.Set() |> ignore + post.Wait() [] member this.``After dispose is called, mailbox should stop receiving and processing messages``() = task { @@ -397,6 +404,7 @@ type MailboxProcessorType() = Assert.Equal(expectedMessagesCount, actualMessagesCount) Assert.Equal(0, actualSkipMessagesCount) Assert.Equal(0, mb.CurrentQueueLength) + } [] @@ -496,3 +504,56 @@ type MailboxProcessorType() = // If StartImmediate worked correctly, the information should be identical since // the threads should be the same. Assert.Equal(callingThreadInfo, mailboxThreadInfo) + +module MailboxProcessorType = + + [] + let TryScan () = + let tcs = TaskCompletionSource<_>() + use mailbox = + new MailboxProcessor(fun inbox -> async { + do! + inbox.TryScan( function + | Reset -> async { tcs.SetResult "Reset processed" } |> Some + | _ -> None) + |> Async.Ignore + }) + mailbox.Start() + + for i in 1 .. 100 do + mailbox.Post(Increment i) + mailbox.Post Reset + + Assert.Equal("Reset processed", tcs.Task.Result) + Assert.Equal(100, mailbox.CurrentQueueLength) + + [] + let ``TryScan with timeout`` () = + let tcs = TaskCompletionSource<_>() + use mailbox = + new MailboxProcessor(fun inbox -> + let rec loop i = async { + match! + inbox.TryScan( function + | Reset -> async { tcs.SetResult i } |> Some + | _ -> None) + with + | None -> do! loop (i + 1) + | _ -> () + } + loop 1 + ) + mailbox.DefaultTimeout <- 10 + mailbox.Start() + + let iteration = + task { + for i in 1 .. 100 do + mailbox.Post(Increment 1) + do! Task.Delay 10 + mailbox.Post Reset + + return! tcs.Task + } + + Assert.True(iteration.Result > 1, "TryScan did not timeout") diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Tasks.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Tasks.fs index 5d533b880c3..8097c2d10f5 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Tasks.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Tasks.fs @@ -236,15 +236,16 @@ type Basics() = [] member _.testNonBlocking() = printfn "Running testNonBlocking..." - let sw = Stopwatch() - sw.Start() + let allowContinue = new SemaphoreSlim(0) + let finished = new ManualResetEventSlim() let t = task { - do! Task.Yield() + do! allowContinue.WaitAsync() Thread.Sleep(100) + finished.Set() } - sw.Stop() - require (sw.ElapsedMilliseconds < 50L) "sleep blocked caller" + allowContinue.Release() |> ignore + require (not finished.IsSet) "sleep blocked caller" t.Wait() [] @@ -908,58 +909,60 @@ type Basics() = [] member _.testExceptionThrownInFinally() = printfn "running testExceptionThrownInFinally" - for i in 1 .. 5 do - let mutable ranInitial = false - let mutable ranNext = false + for i in 1 .. 5 do + use stepOutside = new SemaphoreSlim(0) + use ranInitial = new ManualResetEventSlim() + use ranNext = new ManualResetEventSlim() let mutable ranFinally = 0 let t = task { try - ranInitial <- true + ranInitial.Set() do! Task.Yield() Thread.Sleep(100) // shouldn't be blocking so we should get through to requires before this finishes - ranNext <- true + ranNext.Set() finally ranFinally <- ranFinally + 1 failtest "finally exn!" } - require ranInitial "didn't run initial" - require (not ranNext) "ran next too early" + require ranInitial.IsSet "didn't run initial" + require (not ranNext.IsSet) "ran next too early" try t.Wait() require false "shouldn't get here" with | _ -> () - require ranNext "didn't run next" + require ranNext.IsSet "didn't run next" require (ranFinally = 1) "didn't run finally exactly once" [] member _.test2ndExceptionThrownInFinally() = printfn "running test2ndExceptionThrownInFinally" for i in 1 .. 5 do - let mutable ranInitial = false - let mutable ranNext = false + use ranInitial = new ManualResetEventSlim() + use continueTask = new SemaphoreSlim(0) + use ranNext = new ManualResetEventSlim() let mutable ranFinally = 0 let t = task { try - ranInitial <- true + ranInitial.Set() + do! continueTask.WaitAsync() + ranNext.Set() do! Task.Yield() - Thread.Sleep(100) // shouldn't be blocking so we should get through to requires before this finishes - ranNext <- true failtest "uhoh" finally ranFinally <- ranFinally + 1 failtest "2nd exn!" } - require ranInitial "didn't run initial" - require (not ranNext) "ran next too early" + ranInitial.Wait() + continueTask.Release() |> ignore try t.Wait() require false "shouldn't get here" with | _ -> () - require ranNext "didn't run next" + require ranNext.IsSet "didn't run next" require (ranFinally = 1) "didn't run finally exactly once" [] diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TasksDynamic.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TasksDynamic.fs index c811aecaa5c..7f844e99d96 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TasksDynamic.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/TasksDynamic.fs @@ -357,15 +357,16 @@ type Basics() = [] member _.testNonBlocking() = printfn "Running testNonBlocking..." - let sw = Stopwatch() - sw.Start() + let allowContinue = new SemaphoreSlim(0) + let finished = new ManualResetEventSlim() let t = taskDynamic { - do! Task.Yield() + do! allowContinue.WaitAsync() Thread.Sleep(100) + finished.Set() } - sw.Stop() - require (sw.ElapsedMilliseconds < 50L) "sleep blocked caller" + allowContinue.Release() |> ignore + require (not finished.IsSet) "sleep blocked caller" t.Wait() [] @@ -982,58 +983,60 @@ type Basics() = [] member _.testExceptionThrownInFinally() = printfn "running testExceptionThrownInFinally" - for i in 1 .. 5 do - let mutable ranInitial = false - let mutable ranNext = false + for i in 1 .. 5 do + use stepOutside = new SemaphoreSlim(0) + use ranInitial = new ManualResetEventSlim() + use ranNext = new ManualResetEventSlim() let mutable ranFinally = 0 let t = taskDynamic { try - ranInitial <- true + ranInitial.Set() do! Task.Yield() Thread.Sleep(100) // shouldn't be blocking so we should get through to requires before this finishes - ranNext <- true + ranNext.Set() finally ranFinally <- ranFinally + 1 failtest "finally exn!" } - require ranInitial "didn't run initial" - require (not ranNext) "ran next too early" + require ranInitial.IsSet "didn't run initial" + require (not ranNext.IsSet) "ran next too early" try t.Wait() require false "shouldn't get here" with | _ -> () - require ranNext "didn't run next" + require ranNext.IsSet "didn't run next" require (ranFinally = 1) "didn't run finally exactly once" [] member _.test2ndExceptionThrownInFinally() = printfn "running test2ndExceptionThrownInFinally" for i in 1 .. 5 do - let mutable ranInitial = false - let mutable ranNext = false + use ranInitial = new ManualResetEventSlim() + use continueTask = new SemaphoreSlim(0) + use ranNext = new ManualResetEventSlim() let mutable ranFinally = 0 let t = taskDynamic { try - ranInitial <- true + ranInitial.Set() + do! continueTask.WaitAsync() + ranNext.Set() do! Task.Yield() - Thread.Sleep(100) // shouldn't be blocking so we should get through to requires before this finishes - ranNext <- true failtest "uhoh" finally ranFinally <- ranFinally + 1 failtest "2nd exn!" } - require ranInitial "didn't run initial" - require (not ranNext) "ran next too early" + ranInitial.Wait() + continueTask.Release() |> ignore try t.Wait() require false "shouldn't get here" with | _ -> () - require ranNext "didn't run next" + require ranNext.IsSet "didn't run next" require (ranFinally = 1) "didn't run finally exactly once" [] diff --git a/tests/fsharp/Compiler/Libraries/Core/Async/AsyncTests.fs b/tests/fsharp/Compiler/Libraries/Core/Async/AsyncTests.fs index 708e7e58e2e..3b83b97db7a 100644 --- a/tests/fsharp/Compiler/Libraries/Core/Async/AsyncTests.fs +++ b/tests/fsharp/Compiler/Libraries/Core/Async/AsyncTests.fs @@ -8,7 +8,7 @@ open FSharp.Test module AsyncTests = // Regression for FSHARP1.0:5969 // Async.StartChild: error when wait async is executed more than once - [] + [] let ``Execute Async multiple times``() = CompilerAssert.CompileExeAndRun """ @@ -24,13 +24,12 @@ let a = async { return result } |> Async.RunSynchronously -exit 0 """ // Regression for FSHARP1.0:5970 // Async.StartChild: race in implementation of ResultCell in FSharp.Core - [] + [] let ``Joining StartChild``() = CompilerAssert.CompileExeAndRun """ @@ -54,12 +53,10 @@ let r = with _ -> (0,0) -exit 0 - """ // Regression test for FSHARP1.0:6086 - [] + [] let ``Mailbox Async dot not StackOverflow``() = CompilerAssert.CompileExeAndRun """ @@ -128,12 +125,11 @@ for meet in meets do printfn "%d" meet printfn "Total: %d in %O" (Seq.sum meets) (watch.Elapsed) -exit 0 """ // Regression for FSHARP1.0:5971 - [] + [] let ``StartChild do not throw ObjectDisposedException``() = CompilerAssert.CompileExeAndRun """ @@ -142,10 +138,9 @@ module M let b = async {return 5} |> Async.StartChild printfn "%A" (b |> Async.RunSynchronously |> Async.RunSynchronously) -exit 0 """ - [] + [] let ``StartChild test Trampoline HijackLimit``() = CompilerAssert.CompileExeAndRun """ @@ -164,5 +159,4 @@ let r = () } |> Async.RunSynchronously -exit 0 """ diff --git a/tests/fsharp/core/controlMailbox/test.fsx b/tests/fsharp/core/controlMailbox/test.fsx index 98d6a7d2f31..5aa65035ecd 100644 --- a/tests/fsharp/core/controlMailbox/test.fsx +++ b/tests/fsharp/core/controlMailbox/test.fsx @@ -6,9 +6,7 @@ module Core_controlMailBox #nowarn "40" // recursive references -#if NETCOREAPP open System.Threading.Tasks -#endif let biggerThanTrampoliningLimit = 10000 @@ -49,22 +47,27 @@ let checkQuiet s x1 x2 = (test s false; log (sprintf "expected: %A, got %A" x2 x1)) -let check s x1 x2 = +let check s x1 x2 = if x1 = x2 then test s true else (test s false; log (sprintf "expected: %A, got %A" x2 x1)) +let checkAsync s (x1: Task<_>) x2 = check s x1.Result x2 + open Microsoft.FSharp.Control -open Microsoft.FSharp.Control.WebExtensions module MailboxProcessorBasicTests = + let test() = check "c32398u6: MailboxProcessor null" - (let mb1 = new MailboxProcessor(fun inbox -> async { return () }) - mb1.Start(); - 100) - 100 + ( + let mb1 = new MailboxProcessor(fun inbox -> async { return () }) + mb1.Start() + 100 + ) + + 100 check "c32398u7: MailboxProcessor Receive/PostAndReply" @@ -197,9 +200,10 @@ module MailboxProcessorBasicTests = 200 for n in [0; 1; 100; 1000; 100000 ] do - check + checkAsync (sprintf "c32398u: MailboxProcessor Post/Receive, n=%d" n) - (let received = ref 0 + (task { + let received = ref 0 let mb1 = new MailboxProcessor(fun inbox -> async { for i in 0 .. n-1 do let! _ = inbox.Receive() @@ -208,48 +212,37 @@ module MailboxProcessorBasicTests = for i in 0 .. n-1 do mb1.Post(i) while !received < n do - if !received % 100 = 0 then - printfn "received = %d" !received -#if NETCOREAPP - Task.Delay(1).Wait() -#else - System.Threading.Thread.Sleep(1) -#endif - !received) + do! Task.Yield() + return !received}) n for timeout in [0; 10] do for n in [0; 1; 100] do - check + checkAsync (sprintf "c32398u: MailboxProcessor Post/TryReceive, n=%d, timeout=%d" n timeout) - (let received = ref 0 + (task { + let received = ref 0 let mb1 = new MailboxProcessor(fun inbox -> async { while !received < n do - let! msgOpt = inbox.TryReceive(timeout=timeout) - match msgOpt with - | None -> - do if !received % 100 = 0 then - printfn "timeout!, received = %d" !received - | Some _ -> do incr received }) + match! inbox.TryReceive(timeout=timeout) with + | Some _ -> incr received + | _ -> () + }) + + mb1.Post(0) + mb1.Start(); for i in 0 .. n-1 do -#if NETCOREAPP - Task.Delay(1).Wait(); -#else - System.Threading.Thread.Sleep(1) -#endif mb1.Post(i) + do! Task.Yield() while !received < n do - if !received % 100 = 0 then - printfn "main thread: received = %d" !received -#if NETCOREAPP - Task.Delay(1).Wait(); -#else - System.Threading.Thread.Sleep(1) -#endif - !received) + do! Task.Yield() + return !received}) n + +(* Disabled for timing issues. Some replacement TryScan tests were added to FSharp.Core.UnitTests. + for i in 1..10 do for sleep in [0;1;10] do for timeout in [10;1;0] do @@ -284,8 +277,11 @@ module MailboxProcessorBasicTests = !timedOut) (Some true) - check "cf72361: MailboxProcessor TryScan wo/timeout" - (let timedOut = ref None +*) + + checkAsync "cf72361: MailboxProcessor TryScan wo/timeout" + (task { + let timedOut = ref None let mb = new MailboxProcessor(fun inbox -> async { let! result = inbox.TryScan((fun i -> if i then async { return () } |> Some else None)) @@ -298,65 +294,58 @@ module MailboxProcessorBasicTests = w.Start() while w.ElapsedMilliseconds < 100L do mb.Post(false) -#if NETCOREAPP - Task.Delay(0).Wait(); -#else - System.Threading.Thread.Sleep(0) -#endif + do! Task.Yield() let r = !timedOut mb.Post(true) - r) + return r}) None module MailboxProcessorErrorEventTests = exception Err of int let test() = // Make sure the event doesn't get raised if no error - check + checkAsync "c32398u9330: MailboxProcessor Error (0)" - (let mb1 = new MailboxProcessor(fun inbox -> async { return () }) - let res = ref 100 - mb1.Error.Add(fun _ -> res := 0) + (task { + let mb1 = new MailboxProcessor(fun inbox -> async { return () }) + mb1.Error.Add(fun _ -> failwith "unexpected error event") mb1.Start(); -#if NETCOREAPP - Task.Delay(200).Wait(); -#else - System.Threading.Thread.Sleep(200) -#endif - !res) + do! Task.Delay(200) + return 100}) 100 // Make sure the event does get raised if error - check + check "c32398u9331: MailboxProcessor Error (1)" (let mb1 = new MailboxProcessor(fun inbox -> async { failwith "fail" }) - let res = ref 0 - mb1.Error.Add(fun _ -> res := 100) + use res = new System.Threading.ManualResetEventSlim(false) + mb1.Error.Add(fun _ -> res.Set()) mb1.Start(); -#if NETCOREAPP - Task.Delay(200).Wait(); -#else - System.Threading.Thread.Sleep(200) -#endif - !res) - 100 + res.Wait() + true) + true // Make sure the event does get raised after message receive - check + checkAsync "c32398u9332: MailboxProcessor Error (2)" - (let mb1 = new MailboxProcessor(fun inbox -> - async { let! msg = inbox.Receive() - raise (Err msg) }) - let res = ref 0 - mb1.Error.Add(function Err n -> res := n | _ -> check "rwe90r - unexpected error" 0 1) - mb1.Start(); - mb1.Post 100 -#if NETCOREAPP - Task.Delay(200).Wait(); -#else - System.Threading.Thread.Sleep(200) -#endif - !res) + ( + let errorNumber = TaskCompletionSource<_>() + + let mb1 = new MailboxProcessor( fun inbox -> async { + let! msg = inbox.Receive() + raise (Err msg) + }) + + mb1.Error.Add(function + | Err n -> errorNumber.SetResult n + | _ -> + check "rwe90r - unexpected error" 0 1 ) + + mb1.Start(); + mb1.Post 100 + + errorNumber.Task + ) 100 type msg = Increment of int | Fetch of AsyncReplyChannel | Reset @@ -472,13 +461,10 @@ let test7() = let timeoutboxes str = new MailboxProcessor<'b>(fun inbox -> - async { for i in 1 .. 10 do -#if NETCOREAPP - Task.Delay(200).Wait() -#else - do System.Threading.Thread.Sleep 200 -#endif - }) + async { + for i in 1 .. 10 do + do! Async.Sleep 200 + }) // Timeout let timeout_tpar() = @@ -553,17 +539,9 @@ let timeout_para_def() = test "default timeout & PostAndAsyncReply" false with _ -> test "default timeout & PostAndAsyncReply" true -// Useful class: put "checkpoints" in the code. -// Check they are called in the right order. -type Path(str) = - let mutable current = 0 - member p.Check n = check (str + " #" + string (current+1)) n (current+1) - current <- n - - - module LotsOfMessages = let test () = + task { let N = 200000 let count = ref N @@ -586,12 +564,9 @@ module LotsOfMessages = check "celrv09ervkn" (queueLength >= logger.CurrentQueueLength) true queueLength <- logger.CurrentQueueLength -#if NETCOREAPP - Task.Delay(10).Wait() -#else - System.Threading.Thread.Sleep(10) -#endif + do! Task.Delay(10) check "celrv09ervknf3ew" logger.CurrentQueueLength 0 + } let RunAll() = MailboxProcessorBasicTests.test() @@ -608,11 +583,11 @@ let RunAll() = timeout_tpar_def() // ToDo: 7/31/2008: Disabled because of probable timing issue. QA needs to re-enable post-CTP. // Tracked by bug FSharp 1.0:2891 - //test15() + // test15() // ToDo: 7/31/2008: Disabled because of probable timing issue. QA needs to re-enable post-CTP. // Tracked by bug FSharp 1.0:2891 - //test15b() - LotsOfMessages.test() + // test15b() + LotsOfMessages.test().Wait() #if TESTS_AS_APP let RUN() = RunAll(); failures @@ -621,6 +596,9 @@ RunAll() let aa = if not failures.IsEmpty then stdout.WriteLine "Test Failed" + stdout.WriteLine() + stdout.WriteLine "failures:" + failures |> List.iter stdout.WriteLine exit 1 else stdout.WriteLine "Test Passed" From a89514e4484369d1dba2753583a171dc16c1aa68 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 11:41:14 +0200 Subject: [PATCH 06/22] [main] Update dependencies from dotnet/source-build-reference-packages (#17875) * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20241010.2 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 10.0.0-alpha.1.24507.1 -> To Version 10.0.0-alpha.1.24510.2 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20241011.4 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 10.0.0-alpha.1.24510.2 -> To Version 10.0.0-alpha.1.24511.4 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20241014.1 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 10.0.0-alpha.1.24511.4 -> To Version 10.0.0-alpha.1.24514.1 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e9557ab4f4e..92075c52737 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,9 +1,9 @@ - + https://github.com/dotnet/source-build-reference-packages - fd609e3b427601180d23633e2f1a4cdac6c42c20 + f3889ab90d78377122a3e427fe9a74c03611a4bd From 346a59f93edb3aee3133e2a34ec10925e654c40b Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Wed, 16 Oct 2024 13:39:58 +0100 Subject: [PATCH 07/22] Better error range for `struct` and restricted super types `inherit` (#17886) * Better error range for struct inherit * CheckSuperType * release notes * E_RestrictedSuperTypes * neg6.bsl * neg4.bsl --- .../.FSharp.Compiler.Service/9.0.200.md | 1 + src/Compiler/Checking/CheckDeclarations.fs | 19 +++++++++++------- .../Checking/Expressions/CheckExpressions.fs | 2 +- .../Types/StructTypes/E_Inheritance.fs | 7 +++++++ .../Types/StructTypes/StructTypes.fs | 12 +++++++++++ .../ErrorMessages/ClassesTests.fs | 19 ++++++++++++++++++ tests/fsharp/typeProviders/negTests/neg4.bsl | 8 ++++---- tests/fsharp/typeProviders/negTests/neg6.bsl | 12 +++++------ .../ClassTypes/Misc/E_RestrictedSuperTypes.fs | 20 +++++++++---------- .../TypeKindInference/infer_interface002e.fs | 4 ++-- 10 files changed, 74 insertions(+), 30 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/E_Inheritance.fs diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md index 185fa3a015f..a7d549b23bd 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md @@ -21,5 +21,6 @@ * Better ranges for CE `match!`. ([PR #17789](https://github.com/dotnet/fsharp/pull/17789)) * Better ranges for CE `use` error reporting. ([PR #17811](https://github.com/dotnet/fsharp/pull/17811)) * Better ranges for `inherit` error reporting. ([PR #17879](https://github.com/dotnet/fsharp/pull/17879)) +* Better ranges for `inherit` `struct` error reporting. ([PR #17886](https://github.com/dotnet/fsharp/pull/17886)) ### Breaking Changes diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 814374417d3..31ce9be573c 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -3322,7 +3322,7 @@ module EstablishTypeDefinitionCores = | SynTypeDefnSimpleRepr.Record _ -> if tycon.IsStructRecordOrUnionTycon then Some(g.system_Value_ty) else None - | SynTypeDefnSimpleRepr.General (kind, _, slotsigs, fields, isConcrete, _, _, _) -> + | SynTypeDefnSimpleRepr.General (kind, inherits, slotsigs, fields, isConcrete, _, _, _) -> let kind = InferTyconKind g (kind, attrs, slotsigs, fields, inSig, isConcrete, m) match inheritedTys with @@ -3333,15 +3333,20 @@ module EstablishTypeDefinitionCores = | SynTypeDefnKind.Opaque | SynTypeDefnKind.Class | SynTypeDefnKind.Interface -> None | _ -> error(InternalError("should have inferred tycon kind", m)) - | [(ty, m)] -> - if not firstPass && not (match kind with SynTypeDefnKind.Class -> true | _ -> false) then - errorR (Error(FSComp.SR.tcStructsInterfacesEnumsDelegatesMayNotInheritFromOtherTypes(), m)) - CheckSuperType cenv ty m + | [(ty, m)] -> + let inheritRange = + match inherits with + | [] -> m + | (synType, _, _) :: _ -> synType.Range + if not firstPass && not (match kind with SynTypeDefnKind.Class -> true | _ -> false) then + errorR (Error(FSComp.SR.tcStructsInterfacesEnumsDelegatesMayNotInheritFromOtherTypes(), inheritRange)) + CheckSuperType cenv ty inheritRange if isTyparTy g ty then if firstPass then - errorR(Error(FSComp.SR.tcCannotInheritFromVariableType(), m)) + errorR(Error(FSComp.SR.tcCannotInheritFromVariableType(), inheritRange)) Some g.obj_ty_noNulls // a "super" that is a variable type causes grief later - else + else + Some ty | _ -> error(Error(FSComp.SR.tcTypesCannotInheritFromMultipleConcreteTypes(), m)) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 4325d503206..30375d047f4 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -7140,7 +7140,7 @@ and CheckSuperType (cenv: cenv) ty m = typeEquiv g ty g.system_Array_ty || typeEquiv g ty g.system_MulticastDelegate_ty || typeEquiv g ty g.system_Delegate_ty then - error(Error(FSComp.SR.tcPredefinedTypeCannotBeUsedAsSuperType(), m)) + errorR(Error(FSComp.SR.tcPredefinedTypeCannotBeUsedAsSuperType(), m)) if isErasedType g ty then errorR(Error(FSComp.SR.tcCannotInheritFromErasedType(), m)) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/E_Inheritance.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/E_Inheritance.fs new file mode 100644 index 00000000000..4407d0dafed --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/E_Inheritance.fs @@ -0,0 +1,7 @@ +type TK_I_005 = + abstract M : unit -> unit + +[] +type TK_I_006b = + inherit TK_I_005 + diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/StructTypes.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/StructTypes.fs index 95f228de96a..95e1cb2e4a6 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/StructTypes.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/StructTypes/StructTypes.fs @@ -38,3 +38,15 @@ module StructTypes = |> shouldSucceed |> ignore + [] + let ``StructTypes - E_Inheritance.fs`` compilation = + compilation + |> asFsx + |> withOptions ["--warnaserror+"; "--nowarn:988"] + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 931, Line 6, Col 12, Line 6, Col 20, "Structs, interfaces, enums and delegates cannot inherit from other types"); + (Error 946, Line 6, Col 12, Line 6, Col 20, "Cannot inherit from interface type. Use interface ... with instead.") + ] + diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs index 44e8e202a94..f902fa14369 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs @@ -830,4 +830,23 @@ type Class() = |> withDiagnostics [ (Error 961, Line 5, Col 5, Line 5, Col 12, "This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e.g. 'inherit BaseType(args)'.") (Error 946, Line 5, Col 13, Line 5, Col 15, "Cannot inherit from interface type. Use interface ... with instead.") + ] + + [] + let ``The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class.`` () = + Fsx """ +type C1 = class inherit System.ValueType override x.ToString() = "" end +type C2 = class inherit System.Array override x.ToString() = "" end +type C3 = class inherit System.Enum override x.ToString() = "" end +type C4 = class inherit System.Delegate override x.ToString() = "" end +type C5 = class inherit System.MulticastDelegate override x.ToString() = "" end + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 771, Line 2, Col 25, Line 2, Col 41, "The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class"); + (Error 771, Line 3, Col 25, Line 3, Col 37, "The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class"); + (Error 771, Line 4, Col 25, Line 4, Col 36, "The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class") + (Error 771, Line 5, Col 25, Line 5, Col 40, "The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class"); + (Error 771, Line 6, Col 25, Line 6, Col 49, "The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class") ] \ No newline at end of file diff --git a/tests/fsharp/typeProviders/negTests/neg4.bsl b/tests/fsharp/typeProviders/negTests/neg4.bsl index 7f2259377c8..a1ed652c2cc 100644 --- a/tests/fsharp/typeProviders/negTests/neg4.bsl +++ b/tests/fsharp/typeProviders/negTests/neg4.bsl @@ -17,12 +17,12 @@ neg4.fsx(30,5,30,22): typecheck error FS3062: This type test with a provided typ neg4.fsx(36,5,36,28): typecheck error FS3060: This type test or downcast will erase the provided type 'HelloWorldType' to the type 'System.Object' -neg4.fsx(42,8,42,33): typecheck error FS3063: Cannot inherit from erased provided type +neg4.fsx(42,16,42,33): typecheck error FS3063: Cannot inherit from erased provided type -neg4.fsx(42,8,42,33): typecheck error FS3063: Cannot inherit from erased provided type +neg4.fsx(42,16,42,33): typecheck error FS3063: Cannot inherit from erased provided type -neg4.fsx(47,8,47,35): typecheck error FS3063: Cannot inherit from erased provided type +neg4.fsx(47,16,47,33): typecheck error FS3063: Cannot inherit from erased provided type -neg4.fsx(47,8,47,35): typecheck error FS3063: Cannot inherit from erased provided type +neg4.fsx(47,16,47,33): typecheck error FS3063: Cannot inherit from erased provided type neg4.fsx(52,25,52,42): typecheck error FS3063: Cannot inherit from erased provided type diff --git a/tests/fsharp/typeProviders/negTests/neg6.bsl b/tests/fsharp/typeProviders/negTests/neg6.bsl index 985dd483213..08c6c3166fa 100644 --- a/tests/fsharp/typeProviders/negTests/neg6.bsl +++ b/tests/fsharp/typeProviders/negTests/neg6.bsl @@ -1,12 +1,12 @@ -neg6.fsx(8,3,8,27): typecheck error FS3063: Cannot inherit from erased provided type +neg6.fsx(8,11,8,25): typecheck error FS3063: Cannot inherit from erased provided type -neg6.fsx(8,3,8,27): typecheck error FS3063: Cannot inherit from erased provided type +neg6.fsx(8,11,8,25): typecheck error FS3063: Cannot inherit from erased provided type -neg6.fsx(11,3,11,30): typecheck error FS3063: Cannot inherit from erased provided type +neg6.fsx(11,11,11,28): typecheck error FS3063: Cannot inherit from erased provided type -neg6.fsx(11,3,11,30): typecheck error FS3063: Cannot inherit from erased provided type +neg6.fsx(11,11,11,28): typecheck error FS3063: Cannot inherit from erased provided type -neg6.fsx(14,3,14,35): typecheck error FS3063: Cannot inherit from erased provided type +neg6.fsx(14,11,14,33): typecheck error FS3063: Cannot inherit from erased provided type -neg6.fsx(14,3,14,35): typecheck error FS3063: Cannot inherit from erased provided type +neg6.fsx(14,11,14,33): typecheck error FS3063: Cannot inherit from erased provided type diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_RestrictedSuperTypes.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_RestrictedSuperTypes.fs index 4019069641d..c973c282410 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_RestrictedSuperTypes.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_RestrictedSuperTypes.fs @@ -5,16 +5,16 @@ //The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class //The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class //The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class -//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class +//The types System\.ValueType, System\.Enum, System\.Delegate, System\.MulticastDelegate and System\.Array cannot be used as super types in an object expression or class #light let o1 = { new System.ValueType with member x.ToString() = "" } diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs index e5998a72c51..05074e12def 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface002e.fs @@ -1,10 +1,10 @@ // #Regression #Conformance #ObjectOrientedTypes #TypeInference // attribute must match inferred type //The kind of the type specified by its attributes does not match the kind implied by its definition -//Structs, interfaces, enums and delegates cannot inherit from other types +//Structs, interfaces, enums and delegates cannot inherit from other types //Cannot inherit from interface type\. Use interface \.\.\. with instead //The kind of the type specified by its attributes does not match the kind implied by its definition -//Structs, interfaces, enums and delegates cannot inherit from other types +//Structs, interfaces, enums and delegates cannot inherit from other types //Cannot inherit from interface type\. Use interface \.\.\. with instead // An interface From 69dd6d761f2a1fb831857625f94cddf52122d73a Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Wed, 16 Oct 2024 15:05:22 +0200 Subject: [PATCH 08/22] Update tools (#17889) --- .config/dotnet-tools.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 4dbfc605554..b6cba414baa 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -5,37 +5,37 @@ "commands": [ "dotnet-counters" ], - "version": "8.0.460601" + "version": "8.0.547301" }, "dotnet-dump": { "commands": [ "dotnet-dump" ], - "version": "8.0.460601" + "version": "8.0.547301" }, "dotnet-gcdump": { "commands": [ "dotnet-gcdump" ], - "version": "8.0.460601" + "version": "8.0.547301" }, "dotnet-sos": { "commands": [ "dotnet-sos" ], - "version": "8.0.460601" + "version": "8.0.547301" }, "dotnet-symbol": { "commands": [ "dotnet-symbol" ], - "version": "1.0.460401" + "version": "8.0.547301" }, "dotnet-trace": { "commands": [ "dotnet-trace" ], - "version": "8.0.460601" + "version": "8.0.547301" }, "fantomas": { "commands": [ From 62328fcf5c1cdfc85e0fc58597263e79f2d74528 Mon Sep 17 00:00:00 2001 From: Michael Simons Date: Thu, 17 Oct 2024 04:19:00 -0500 Subject: [PATCH 09/22] Update source-build team references (#17894) --- .github/CODEOWNERS | 3 ++- eng/DotNetBuild.props | 2 +- eng/SourceBuildPrebuiltBaseline.xml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 16d61e579a1..b40e4b69c5b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,3 @@ * @dotnet/fsharp-team-msft -/eng/SourceBuild* @dotnet/source-build-internal +/eng/DotNetBuild.props @dotnet/product-construction +/eng/SourceBuild* @dotnet/source-build diff --git a/eng/DotNetBuild.props b/eng/DotNetBuild.props index c7bc688ba3e..6891541838a 100644 --- a/eng/DotNetBuild.props +++ b/eng/DotNetBuild.props @@ -1,4 +1,4 @@ - + diff --git a/eng/SourceBuildPrebuiltBaseline.xml b/eng/SourceBuildPrebuiltBaseline.xml index 4416e9693af..18f3b782d76 100644 --- a/eng/SourceBuildPrebuiltBaseline.xml +++ b/eng/SourceBuildPrebuiltBaseline.xml @@ -1,4 +1,4 @@ - + From 315966454bcd4e0ec273fa2ab70bcbc48cdbcb86 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Mon, 21 Oct 2024 11:31:27 +0100 Subject: [PATCH 10/22] RFC FS-1033: Deprecate places where `seq` can be omitted (#17772) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Treat `{ 1..10 }` as sequence expression * deprecate { start..finish } and { start..step..finish } * fix build part1 * 3873., chkDeprecatePlacesWhereSeqCanBeOmitted * more tests * release notes * reorg seq tests * Better check * fix merge conflicts * Add code fix for adding missing `seq` before `{…}` * More tests * Fmt * update release notes * more editor tests --------- Co-authored-by: Brian Rourke Boll --- .../.FSharp.Compiler.Service/9.0.200.md | 2 +- docs/release-notes/.Language/preview.md | 1 + docs/release-notes/.VisualStudio/17.13.md | 8 + .../Checking/Expressions/CheckExpressions.fs | 11 + src/Compiler/FSComp.txt | 4 +- src/Compiler/Facilities/LanguageFeatures.fs | 3 + src/Compiler/Facilities/LanguageFeatures.fsi | 1 + src/Compiler/xlf/FSComp.txt.cs.xlf | 12 +- src/Compiler/xlf/FSComp.txt.de.xlf | 12 +- src/Compiler/xlf/FSComp.txt.es.xlf | 12 +- src/Compiler/xlf/FSComp.txt.fr.xlf | 12 +- src/Compiler/xlf/FSComp.txt.it.xlf | 12 +- src/Compiler/xlf/FSComp.txt.ja.xlf | 12 +- src/Compiler/xlf/FSComp.txt.ko.xlf | 12 +- src/Compiler/xlf/FSComp.txt.pl.xlf | 12 +- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 12 +- src/Compiler/xlf/FSComp.txt.ru.xlf | 12 +- src/Compiler/xlf/FSComp.txt.tr.xlf | 12 +- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 12 +- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 12 +- .../FSharp.Compiler.ComponentTests.fsproj | 2 +- .../E_SequenceExpressions01.fs | 76 ++++++ .../SequenceExpressionTests.fs | 126 ++++++++- .../SequenceExpressions01.fs | 76 ++++++ .../PatternMatchCompilationTests.fs | 6 +- .../ArrayModule.fs | 4 +- .../ArrayModule2.fs | 2 +- .../ListModule.fs | 4 +- .../ListModule2.fs | 2 +- .../ObsoleteSeqFunctions.fs | 6 +- .../Microsoft.FSharp.Collections/SeqModule.fs | 34 +-- .../SeqModule2.fs | 54 ++-- .../FSharp.Core/PrimTypes.fs | 92 +++---- .../TestFrameworkHelpers.fs | 2 +- .../FSharp.Editor/CodeFixes/AddMissingSeq.fs | 77 ++++++ .../src/FSharp.Editor/Common/Constants.fs | 3 + .../src/FSharp.Editor/FSharp.Editor.fsproj | 1 + .../src/FSharp.Editor/FSharp.Editor.resx | 3 + .../FSharp.Editor/xlf/FSharp.Editor.cs.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.de.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.es.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.fr.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.it.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.ja.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.ko.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.pl.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.ru.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.tr.xlf | 5 + .../xlf/FSharp.Editor.zh-Hans.xlf | 5 + .../xlf/FSharp.Editor.zh-Hant.xlf | 5 + .../CodeFixes/AddMissingSeqTests.fs | 239 ++++++++++++++++++ .../FSharp.Editor.Tests.fsproj | 1 + 53 files changed, 940 insertions(+), 121 deletions(-) create mode 100644 docs/release-notes/.VisualStudio/17.13.md create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/E_SequenceExpressions01.fs rename tests/FSharp.Compiler.ComponentTests/Language/{ => SequenceExpressions}/SequenceExpressionTests.fs (59%) create mode 100644 tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions01.fs create mode 100644 vsintegration/src/FSharp.Editor/CodeFixes/AddMissingSeq.fs create mode 100644 vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddMissingSeqTests.fs diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md index a7d549b23bd..15b5f1248e6 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md @@ -8,7 +8,7 @@ * Fix nullness inference for member val and other OO scenarios ([PR #17845](https://github.com/dotnet/fsharp/pull/17845)) ### Added - +* Deprecate places where `seq` can be omitted. ([Language suggestion #1033](https://github.com/fsharp/fslang-suggestions/issues/1033), [PR #17772](https://github.com/dotnet/fsharp/pull/17772)) * Support literal attribute on decimals ([PR #17769](https://github.com/dotnet/fsharp/pull/17769)) ### Changed diff --git a/docs/release-notes/.Language/preview.md b/docs/release-notes/.Language/preview.md index b18d08e30c3..a38e14215dc 100644 --- a/docs/release-notes/.Language/preview.md +++ b/docs/release-notes/.Language/preview.md @@ -1,6 +1,7 @@ ### Added * Better generic unmanaged structs handling. ([Language suggestion #692](https://github.com/fsharp/fslang-suggestions/issues/692), [PR #12154](https://github.com/dotnet/fsharp/pull/12154)) +* Deprecate places where `seq` can be omitted. ([Language suggestion #1033](https://github.com/fsharp/fslang-suggestions/issues/1033), [PR #17772](https://github.com/dotnet/fsharp/pull/17772)) ### Fixed diff --git a/docs/release-notes/.VisualStudio/17.13.md b/docs/release-notes/.VisualStudio/17.13.md new file mode 100644 index 00000000000..dae07600e1b --- /dev/null +++ b/docs/release-notes/.VisualStudio/17.13.md @@ -0,0 +1,8 @@ +### Fixed + +### Added +* Code fix for adding missing `seq`. ([PR #17772](https://github.com/dotnet/fsharp/pull/17772)) + +### Changed + +### Breaking Changes diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 30375d047f4..9c14787d113 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -5891,6 +5891,17 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, pat, synEnumExpr, synBodyExpr, m, spFor, spIn, m) | SynExpr.ComputationExpr (hasSeqBuilder, comp, m) -> + let isIndexRange = match comp with | SynExpr.IndexRange _ -> true | _ -> false + let deprecatedPlacesWhereSeqCanBeOmitted = + cenv.g.langVersion.SupportsFeature LanguageFeature.DeprecatePlacesWhereSeqCanBeOmitted + if + deprecatedPlacesWhereSeqCanBeOmitted + && isIndexRange + && not hasSeqBuilder + && not cenv.g.compilingFSharpCore + then + warning (Error(FSComp.SR.chkDeprecatePlacesWhereSeqCanBeOmitted (), m)) + let env = ExitFamilyRegion env cenv.TcSequenceExpressionEntry cenv env overallTy tpenv (hasSeqBuilder, comp) m diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index b5a50afc7c0..9a6b69fa2ff 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1783,4 +1783,6 @@ featureEmptyBodiedComputationExpressions,"Support for computation expressions wi featureAllowAccessModifiersToAutoPropertiesGettersAndSetters,"Allow access modifiers to auto properties getters and setters" 3871,tcAccessModifiersNotAllowedInSRTPConstraint,"Access modifiers cannot be applied to an SRTP constraint." featureAllowObjectExpressionWithoutOverrides,"Allow object expressions without overrides" -3872,tcPartialActivePattern,"Multi-case partial active patterns are not supported. Consider using a single-case partial active pattern or a full active pattern." \ No newline at end of file +3872,tcPartialActivePattern,"Multi-case partial active patterns are not supported. Consider using a single-case partial active pattern or a full active pattern." +3873,chkDeprecatePlacesWhereSeqCanBeOmitted,"This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}'" +featureDeprecatePlacesWhereSeqCanBeOmitted,"Deprecate places where 'seq' can be omitted" \ No newline at end of file diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index 5c311237594..3488a3399e1 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -94,6 +94,7 @@ type LanguageFeature = | ParsedHashDirectiveArgumentNonQuotes | EmptyBodiedComputationExpressions | AllowObjectExpressionWithoutOverrides + | DeprecatePlacesWhereSeqCanBeOmitted /// LanguageVersion management type LanguageVersion(versionText) = @@ -219,6 +220,7 @@ type LanguageVersion(versionText) = LanguageFeature.FromEndSlicing, previewVersion // Unfinished features --- needs work LanguageFeature.AllowAccessModifiersToAutoPropertiesGettersAndSetters, previewVersion LanguageFeature.AllowObjectExpressionWithoutOverrides, previewVersion + LanguageFeature.DeprecatePlacesWhereSeqCanBeOmitted, previewVersion ] static let defaultLanguageVersion = LanguageVersion("default") @@ -375,6 +377,7 @@ type LanguageVersion(versionText) = | LanguageFeature.ParsedHashDirectiveArgumentNonQuotes -> FSComp.SR.featureParsedHashDirectiveArgumentNonString () | LanguageFeature.EmptyBodiedComputationExpressions -> FSComp.SR.featureEmptyBodiedComputationExpressions () | LanguageFeature.AllowObjectExpressionWithoutOverrides -> FSComp.SR.featureAllowObjectExpressionWithoutOverrides () + | LanguageFeature.DeprecatePlacesWhereSeqCanBeOmitted -> FSComp.SR.featureDeprecatePlacesWhereSeqCanBeOmitted () /// 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 7408300b943..6396f7b72c0 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -85,6 +85,7 @@ type LanguageFeature = | ParsedHashDirectiveArgumentNonQuotes | EmptyBodiedComputationExpressions | AllowObjectExpressionWithoutOverrides + | DeprecatePlacesWhereSeqCanBeOmitted /// LanguageVersion management type LanguageVersion = diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 958a1357ac9..4a6bbf58d2f 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -52,6 +52,11 @@ Tento výraz je anonymní záznam, použijte {{|...|}} místo {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Duplicitní parametr Parametr {0} byl v této metodě použit vícekrát. @@ -322,6 +327,11 @@ opravit překlad názvů typů delegátů, viz https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding vzor discard ve vazbě použití @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Neplatný výraz záznamu, pořadí nebo výpočtu. Výrazy pořadí by měly mít notaci seq {{ ... }}. + Neplatný výraz záznamu, pořadí nebo výpočtu. Výrazy pořadí by měly mít notaci seq {{ ... }}. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index d7233a5d2fc..1546541aee7 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -52,6 +52,11 @@ Dieser Ausdruck ist ein anonymer Datensatz. Verwenden Sie {{|...|}} anstelle von {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Doppelter Parameter. Der Parameter „{0}“ wurde in dieser Methode mehrmals verwendet. @@ -322,6 +327,11 @@ Informationen zur Problembehebung bezüglich der Auflösung von Delegattypnamen finden Sie unter https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding Das Verwerfen des verwendeten Musters ist verbindlich. @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Ungültiger Datensatz-, Sequenz- oder Berechnungsausdruck. Sequenzausdrücke müssen das Format "seq {{ ... }}" besitzen. + Ungültiger Datensatz-, Sequenz- oder Berechnungsausdruck. Sequenzausdrücke müssen das Format "seq {{ ... }}" besitzen. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 1b3205ffa53..db357235565 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -52,6 +52,11 @@ Esta expresión es un registro anónimo; use {{|...|}} en lugar de {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Parámetro duplicado. El parámetro '{0}' se ha usado más una vez en este método. @@ -322,6 +327,11 @@ corrección para la resolución de nombres de tipo de delegado, consulte https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding descartar enlace de patrón en uso @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Expresión de registro, secuencia o cómputo no válida. Las expresiones de secuencia deben tener el formato 'seq {{ ... }}'. + Expresión de registro, secuencia o cómputo no válida. Las expresiones de secuencia deben tener el formato 'seq {{ ... }}'. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 018180a8fb6..dca6fe2b78d 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -52,6 +52,11 @@ Cette expression est un enregistrement anonyme, utilisez {{|...|}} au lieu de {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Paramètre dupliqué. Le paramètre « {0} » a été utilisé une fois de plus dans cette méthode. @@ -322,6 +327,11 @@ corriger pour résoudre les noms de types délégués, voir https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding annuler le modèle dans la liaison d’utilisation @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Expression d'enregistrement, de séquence ou de calcul non valide. Les expressions de séquence doivent avoir le format 'seq {{ ... }}' + Expression d'enregistrement, de séquence ou de calcul non valide. Les expressions de séquence doivent avoir le format 'seq {{ ... }}' diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 7cc3f46259b..0d2815aa9b2 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -52,6 +52,11 @@ Questa espressione è un record anonimo. Usa {{|...|}} invece di {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Parametro duplicato. Il parametro '{0}' è stato utilizzato più volte in questo metodo. @@ -322,6 +327,11 @@ correggere la risoluzione dei nomi dei tipi delegati, vedere https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding rimuovi criterio nell'utilizzo dell'associazione @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Espressione di calcolo, sequenza o record non valida. Il formato delle espressioni sequenza deve essere 'seq {{ ... }}' + Espressione di calcolo, sequenza o record non valida. Il formato delle espressioni sequenza deve essere 'seq {{ ... }}' diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 10c5f06f4ff..d660cf6768b 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -52,6 +52,11 @@ この式は匿名レコードであり、{{...}} の代わりに {{|...|}} を使用してください。 + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. パラメーターが重複しています。パラメーター '{0}' は、このメソッドで 1 回以上使用されています。 @@ -322,6 +327,11 @@ デリゲート型名の解決を修正するには、https://github.com/dotnet/fsharp/issues/10228 を参照してください + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding 使用バインドでパターンを破棄する @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - 無効なレコード、シーケンス式、またはコンピュテーション式です。シーケンス式は 'seq {{ ... }}' という形式にしてください。 + 無効なレコード、シーケンス式、またはコンピュテーション式です。シーケンス式は 'seq {{ ... }}' という形式にしてください。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 94cd344f052..a0f3d1411b4 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -52,6 +52,11 @@ 이 식은 익명 레코드입니다. {{...}} 대신 {{|...|}}을 사용하세요. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. 매개 변수가 중복되었습니다. 이 메소드에서 매개 변수 '{0}'이(가) 두 번 이상 사용되었습니다. @@ -322,6 +327,11 @@ 대리자 형식 이름의 해결 방법을 수정합니다. https://github.com/dotnet/fsharp/issues/10228 참조하세요. + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding 사용 중인 패턴 바인딩 무시 @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - 레코드, 시퀀스 또는 계산 식이 잘못되었습니다. 시퀀스 식의 형식은 'seq {{ ... }}'여야 합니다. + 레코드, 시퀀스 또는 계산 식이 잘못되었습니다. 시퀀스 식의 형식은 'seq {{ ... }}'여야 합니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 01f2ff1d5e3..fcb2638d5a2 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -52,6 +52,11 @@ To wyrażenie jest rekordem anonimowym. Użyj {{|...|}} zamiast {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Zduplikowany parametr. Parametr „{0}” został użyty więcej niż raz w tej metodzie. @@ -322,6 +327,11 @@ naprawa rozpoznawania nazw typów delegatów, sprawdź stronę https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding odrzuć wzorzec w powiązaniu użycia @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Nieprawidłowe wyrażenie rekordu, sekwencji lub obliczenia. Wyrażenia sekwencji powinny mieć postać „seq {{ ... }}” + Nieprawidłowe wyrażenie rekordu, sekwencji lub obliczenia. Wyrażenia sekwencji powinny mieć postać „seq {{ ... }}” diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 63da6a667b1..a27487e1c20 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -52,6 +52,11 @@ Esta expressão é um registro anônimo, use {{|...|}} em vez de {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Parâmetro duplicado. O parâmetro '{0}' foi usado mais de uma vez neste método. @@ -322,6 +327,11 @@ corrigir para resolução de nomes de tipos delegados, consulte https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding descartar o padrão em uso de associação @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Expressão de registro, sequência ou computação inválida. Expressões de sequência devem estar na forma 'seq {{ ... }}' + Expressão de registro, sequência ou computação inválida. Expressões de sequência devem estar na forma 'seq {{ ... }}' diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 231bc83103b..18c6c501759 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -52,6 +52,11 @@ Это выражение является анонимной записью. Используйте {{|...|}} вместо {{...}}. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Повторяющийся параметр. Параметр "{0}" использовался в этом методе несколько раз. @@ -322,6 +327,11 @@ исправить разрешение имен типов делегатов, см. https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding шаблон отмены в привязке использования @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Недопустимая запись, выражение последовательности или вычислительное выражение. Выражения последовательностей должны иметь форму "seq {{ ... }}' + Недопустимая запись, выражение последовательности или вычислительное выражение. Выражения последовательностей должны иметь форму "seq {{ ... }}' diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index a3bab7e5a92..94a7a284470 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -52,6 +52,11 @@ Bu ifade, anonim bir kayıt, {{...}} yerine {{|...|}} kullanın. + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. Yinelenen parametre. '{0}' parametresi bu metotta bir kereden fazla kullanıldı. @@ -322,6 +327,11 @@ temsilci türü adlarının çözümlenmesiyle ilgili sorunun çözümü için bkz. https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding kullanım bağlamasında deseni at @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - Geçersiz kayıt, dizi veya hesaplama ifadesi. Dizi ifadeleri 'seq {{ ... }}' biçiminde olmalıdır + Geçersiz kayıt, dizi veya hesaplama ifadesi. Dizi ifadeleri 'seq {{ ... }}' biçiminde olmalıdır diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 579ac9b79c3..ba5826eb686 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -52,6 +52,11 @@ 此表达式是匿名记录,请使用 {{|...|}} 而不是 {{...}}。 + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. 参数重复。此方法中多次使用了参数“{0}”。 @@ -322,6 +327,11 @@ 修复了委托类型名称的解析,请参阅 https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding 放弃使用绑定模式 @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - 记录、序列或计算表达式无效。序列表达式的格式应为“seq {{ ... }}” + 记录、序列或计算表达式无效。序列表达式的格式应为“seq {{ ... }}” diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 09818a7487b..b039caf9e93 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -52,6 +52,11 @@ 此運算式是匿名記錄,請使用 {{|...|}} 而不是 {{...}}。 + + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + This construct is deprecated. Sequence expressions should be of the form 'seq {{ ... }}' + + Duplicate parameter. The parameter '{0}' has been used more that once in this method. 重複的參數。參數 '{0}' 在此方法中使用多次。 @@ -322,6 +327,11 @@ 修正委派類型名稱的解析,請參閱 https://github.com/dotnet/fsharp/issues/10228 + + Deprecate places where 'seq' can be omitted + Deprecate places where 'seq' can be omitted + + discard pattern in use binding 捨棄使用繫結中的模式 @@ -4524,7 +4534,7 @@ Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq {{ ... }}' - 無效的記錄、循序項或計算運算式。循序項運算式應該是 'seq {{ ... }}' 形式。 + 無效的記錄、循序項或計算運算式。循序項運算式應該是 'seq {{ ... }}' 形式。 diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 029ec14b0b4..af431847400 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -223,6 +223,7 @@ + @@ -237,7 +238,6 @@ - diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/E_SequenceExpressions01.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/E_SequenceExpressions01.fs new file mode 100644 index 00000000000..37ca58c3db6 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/E_SequenceExpressions01.fs @@ -0,0 +1,76 @@ +{ 1..10 } + +{ 1..5..10 } + +[| { 1..10 } |] + +[| { 1..5..10 } |] + +let a = { 1..10 } + +let a3 = { 1..10..20 } + +let b = [| { 1..10 } |] + +let b3 = [| { 1..10..20 } |] + +let c = [ { 1..10 } ] + +[| { 1..10 } |] + +[| yield { 1..10 } |] + +[ { 1..10 } ] + +[ { 1..10..10 } ] + +[ yield { 1..10 } ] + +[ yield { 1..10..20 } ] + +ResizeArray({ 1..10 }) + +ResizeArray({ 1..10..20 }) + +let fw start finish = [ for x in { start..finish } -> x ] + +let fe start finish = [| for x in { start..finish } -> x |] + +for x in { 1..10 } do () + +for x in { 1..5..10 } do () + +let f = Seq.head + +let a2 = f { 1..6 } + +let a23 = f { 1..6..10 } + +let b2 = set { 1..6 } + +let f10 start finish = for x in { start..finish } do ignore (float x ** float x) + +let (..) _ _ = "lol" + +let lol1 = { 1..10 } + +{ 1..5..10 } + +let resultInt = Seq.length {1..8} + +let resultInt2 funcInt = Seq.map3 funcInt { 1..8 } { 2..9 } { 3..10 } + +let verify c = failwith "not implemented" + +Seq.splitInto 4 {1..5} |> verify { 1.. 10 } + +seq [ {1..4}; {5..7}; {8..10} ] + +Seq.allPairs { 1..7 } Seq.empty + +Seq.allPairs Seq.empty { 1..7 } + +let intArr1 = [| yield! {1..100} + yield! {1..100} |] + +Array.ofSeq {1..10} \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressionTests.fs similarity index 59% rename from tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressionTests.fs rename to tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressionTests.fs index 8247eaf60e3..263f305f7a5 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressionTests.fs @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. -module Language.SequenceExpressionTests +module Language.SequenceExpression.SequenceExpressionTests +open FSharp.Test open Xunit open FSharp.Test.Compiler open FSharp.Test.ScriptHelpers @@ -467,4 +468,125 @@ let f2 = return! [ 3; 4 ] |> withDiagnostics [ (Error 748, Line 2, Col 10, Line 2, Col 16, "This construct may only be used within computation expressions. To return a value from an ordinary function simply write the expression without 'return'."); (Error 748, Line 3, Col 10, Line 3, Col 17, "This construct may only be used within computation expressions. To return a value from an ordinary function simply write the expression without 'return'.") - ] \ No newline at end of file + ] + +[] +let ``Sequence(SynExpr.Sequential) expressions should be of the form 'seq { ... } lang version 9``() = + Fsx """ +{ 1;10 } +[| { 1;10 } |] +let a = { 1;10 } +let b = [| { 1;10 } |] +let c = [ { 1;10 } ] + """ + |> withOptions [ "--nowarn:0020" ] + |> withLangVersion90 + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 740, Line 2, Col 1, Line 2, Col 9, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 3, Col 4, Line 3, Col 12, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 4, Col 9, Line 4, Col 17, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 5, Col 12, Line 5, Col 20, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 6, Col 11, Line 6, Col 19, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + ] + +[] +let ``Sequence(SynExpr.Sequential) expressions should be of the form 'seq { ... } lang version preview``() = + Fsx """ +{ 1;10 } +[| { 1;10 } |] +let a = { 1;10 } +let b = [| { 1;10 } |] +let c = [ { 1;10 } ] + """ + |> withOptions [ "--nowarn:0020" ] + |> withLangVersionPreview + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 740, Line 2, Col 1, Line 2, Col 9, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 3, Col 4, Line 3, Col 12, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 4, Col 9, Line 4, Col 17, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 5, Col 12, Line 5, Col 20, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + (Error 740, Line 6, Col 11, Line 6, Col 19, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'") + ] + +// SOURCE=E_SequenceExpressions01.fs # E_SequenceExpressions01.fs +[] +let ``E_SequenceExpressions01 lang version 9`` compilation = + compilation + |> withOptions [ "--nowarn:0020" ] + |> withLangVersion90 + |> typecheck + |> shouldSucceed + +// SOURCE=E_SequenceExpressions01.fs # E_SequenceExpressions01.fs +[] +let ``E_SequenceExpressions01 lang version preview`` compilation = + compilation + |> withOptions [ "--nowarn:0020" ] + |> withLangVersionPreview + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Warning 3873, Line 1, Col 1, Line 1, Col 10, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 3, Col 1, Line 3, Col 13, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 5, Col 4, Line 5, Col 13, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 7, Col 4, Line 7, Col 16, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 9, Col 9, Line 9, Col 18, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 11, Col 10, Line 11, Col 23, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 13, Col 12, Line 13, Col 21, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 15, Col 13, Line 15, Col 26, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 17, Col 11, Line 17, Col 20, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 19, Col 4, Line 19, Col 13, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 21, Col 10, Line 21, Col 19, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 23, Col 3, Line 23, Col 12, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 25, Col 3, Line 25, Col 16, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 27, Col 9, Line 27, Col 18, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 29, Col 9, Line 29, Col 22, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 31, Col 13, Line 31, Col 22, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 33, Col 13, Line 33, Col 26, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 35, Col 34, Line 35, Col 51, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 37, Col 35, Line 37, Col 52, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 39, Col 10, Line 39, Col 19, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 41, Col 10, Line 41, Col 22, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 45, Col 12, Line 45, Col 20, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 47, Col 13, Line 47, Col 25, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 49, Col 14, Line 49, Col 22, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 51, Col 33, Line 51, Col 50, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 55, Col 12, Line 55, Col 21, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 57, Col 1, Line 57, Col 13, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 59, Col 28, Line 59, Col 34, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 61, Col 44, Line 61, Col 52, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 61, Col 53, Line 61, Col 61, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 61, Col 62, Line 61, Col 71, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 65, Col 17, Line 65, Col 23, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 65, Col 34, Line 65, Col 44, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 67, Col 7, Line 67, Col 13, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 67, Col 15, Line 67, Col 21, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 67, Col 23, Line 67, Col 30, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 69, Col 14, Line 69, Col 22, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 71, Col 24, Line 71, Col 32, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 73, Col 25, Line 73, Col 33, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 74, Col 25, Line 74, Col 33, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + (Warning 3873, Line 76, Col 13, Line 76, Col 20, "This construct is deprecated. Sequence expressions should be of the form 'seq { ... }'") + ] + +// SOURCE=SequenceExpressions01.fs # SequenceExpressions01.fs +[] +let ``SequenceExpressions01 lang version 9`` compilation = + compilation + |> withOptions [ "--nowarn:0020" ] + |> withLangVersion90 + |> typecheck + |> shouldSucceed + +// SOURCE=SequenceExpressions01.fs # SequenceExpressions01.fs +[] +let ``SequenceExpressions01 lang version preview`` compilation = + compilation + |> withOptions [ "--nowarn:0020" ] + |> withLangVersionPreview + |> typecheck + |> shouldSucceed \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions01.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions01.fs new file mode 100644 index 00000000000..ea1ab603eef --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressions/SequenceExpressions01.fs @@ -0,0 +1,76 @@ +seq { 1..10 } + +seq { 1..5..10 } + +[| seq { 1..10 } |] + +[| seq { 1..5..10 } |] + +let a = seq { 1..10 } + +let a3 = seq { 1..10..20 } + +let b = [| seq { 1..10 } |] + +let b3 = [| seq { 1..10..20 } |] + +let c = [ seq { 1..10 } ] + +[| seq { 1..10 } |] + +[| yield seq { 1..10 } |] + +[ seq { 1..10 } ] + +[ seq { 1..10..10 } ] + +[ yield seq { 1..10 } ] + +[ yield seq { 1..10..20 } ] + +ResizeArray(seq { 1..10 }) + +ResizeArray(seq { 1..10..20 }) + +let fw start finish = [ for x in seq { start..finish } -> x ] + +let fe start finish = [| for x in seq { start..finish } -> x |] + +for x in seq { 1..10 } do () + +for x in seq { 1..5..10 } do () + +let f = Seq.head + +let a2 = f (seq { 1..6 }) + +let a23 = f (seq { 1..6..10 }) + +let b2 = set (seq { 1..6 }) + +let f10 start finish = for x in seq { start..finish } do ignore (float x ** float x) + +let (..) _ _ = "lol" + +let lol1 = seq { 1..10 } + +seq { 1..5..10 } + +let resultInt = Seq.length (seq {1..8}) + +let resultInt2 funcInt = Seq.map3 funcInt (seq { 1..8 }) (seq { 2..9 }) (seq { 3..10 }) + +let verify c = failwith "not implemented" + +Seq.splitInto 4 (seq {1..5}) |> verify (seq { 1.. 10 }) + +seq [ seq {1..4}; seq {5..7}; seq {8..10} ] + +Seq.allPairs (seq { 1..7 }) Seq.empty + +Seq.allPairs Seq.empty (seq { 1..7 }) + +let intArr1 = [| yield! seq {1..100} + yield! seq {1..100} |] + +Array.ofSeq (seq {1..10}) \ No newline at end of file diff --git a/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs b/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs index 4ae43434099..e22c58e8a3a 100644 --- a/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs @@ -455,7 +455,7 @@ let r as _ = 10 let s as Id0 = 11 let t as (u) = 12 let v as struct(w, x) = 13, 14 -let y as z : int = 15{set { 'a'..'x' } - set [ 'p'; 'v' ] |> Set.map (sprintf " + %c") |> System.String.Concat} +let y as z : int = 15{set (seq { 'a'..'x' }) - set [ 'p'; 'v' ] |> Set.map (sprintf " + %c") |> System.String.Concat} Some p |> eq Some v |> eq () @@ -590,7 +590,7 @@ let _ as r = 10 let Id0 as s = 11 let (t) as u = 12 let struct(w, v) as x = 13, 14 -let (y : int) as z = 15{set { 'a'..'v' } - set [ 'h'; 'q' ] |> Set.map (sprintf " + %c") |> System.String.Concat} +let (y : int) as z = 15{set (seq { 'a'..'v' }) - set [ 'h'; 'q' ] |> Set.map (sprintf " + %c") |> System.String.Concat} Some h |> eq Some q |> eq Some x |> eq @@ -917,7 +917,7 @@ let :? z as [] let ``As 16 - syntactical precedence matrix testing left with type tests - total patterns`` () = - let validSet = set { 'a'..'x' } - set [ 'p'; 'q' ] |> Set.map string + let validSet = set (seq { 'a'..'x' }) - set [ 'p'; 'q' ] |> Set.map string let _, checkResults = getParseAndCheckResults70 $""" let eq<'T> (x:'T option) = () // FS-1093-safe type assert function let (|Id0|) = ignore diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs index c2b0d240372..662a729e28f 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs @@ -259,8 +259,8 @@ type ArrayModule() = [] member _.Except() = // integer array - let intArr1 = [| yield! {1..100} - yield! {1..100} |] + let intArr1 = [| yield! seq {1..100} + yield! seq {1..100} |] let intArr2 = [| 1 .. 10 |] let expectedIntArr = [| 11 .. 100 |] diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs index ec30e724bbb..5c5afc3c234 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs @@ -372,7 +372,7 @@ type ArrayModule2() = [] member this.Of_Seq() = // integer array - let resultInt = Array.ofSeq {1..10} + let resultInt = Array.ofSeq (seq {1..10}) if resultInt <> [|1..10|] then Assert.Fail() // string array diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule.fs index 9f3ae062d02..8b0fcf507e5 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule.fs @@ -346,8 +346,8 @@ type ListModule() = [] member _.Except() = // integer list - let intList1 = [ yield! {1..100} - yield! {1..100} ] + let intList1 = [ yield! seq {1..100} + yield! seq {1..100} ] let intList2 = [1..10] let expectedIntList = [11..100] diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule2.fs index 328574bdac0..3a27d4e7d2a 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule2.fs @@ -367,7 +367,7 @@ type ListModule02() = [] member this.Of_Seq() = // integer List - let resultInt = List.ofSeq {1..10} + let resultInt = List.ofSeq (seq {1..10}) Assert.AreEqual([1..10], resultInt) // string List diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ObsoleteSeqFunctions.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ObsoleteSeqFunctions.fs index 3b8727fc538..67c5aeba747 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ObsoleteSeqFunctions.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ObsoleteSeqFunctions.fs @@ -15,14 +15,14 @@ type ObsoleteSeqFunctions() = // Negative index for i = -1 downto -10 do - CheckThrowsArgumentException (fun () -> Seq.nth i { 10 .. 20 } |> ignore) + CheckThrowsArgumentException (fun () -> Seq.nth i (seq { 10 .. 20 }) |> ignore) // Out of range for i = 11 to 20 do - CheckThrowsArgumentException (fun () -> Seq.nth i { 10 .. 20 } |> ignore) + CheckThrowsArgumentException (fun () -> Seq.nth i (seq { 10 .. 20 }) |> ignore) // integer Seq - let resultInt = Seq.nth 3 { 10..20 } + let resultInt = Seq.nth 3 (seq { 10..20 }) Assert.AreEqual(13, resultInt) // string Seq diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs index de6f66dd7ec..f2f88933506 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs @@ -39,8 +39,8 @@ type SeqModule() = // empty Seq VerifySeqsEqual Seq.empty <| Seq.allPairs Seq.empty Seq.empty - VerifySeqsEqual Seq.empty <| Seq.allPairs { 1..7 } Seq.empty - VerifySeqsEqual Seq.empty <| Seq.allPairs Seq.empty { 1..7 } + VerifySeqsEqual Seq.empty <| Seq.allPairs (seq { 1..7 }) Seq.empty + VerifySeqsEqual Seq.empty <| Seq.allPairs Seq.empty (seq { 1..7 }) // null Seq CheckThrowsArgumentNullException(fun() -> Seq.allPairs null null |> ignore) @@ -349,9 +349,9 @@ type SeqModule() = |> Seq.iter ((<||) VerifySeqsEqual) // int Seq - verify [[1..4];[5..8]] <| Seq.chunkBySize 4 {1..8} - verify [[1..4];[5..8];[9..10]] <| Seq.chunkBySize 4 {1..10} - verify [[1]; [2]; [3]; [4]] <| Seq.chunkBySize 1 {1..4} + verify [[1..4];[5..8]] <| Seq.chunkBySize 4 (seq {1..8}) + verify [[1..4];[5..8];[9..10]] <| Seq.chunkBySize 4 (seq {1..10}) + verify [[1]; [2]; [3]; [4]] <| Seq.chunkBySize 1 (seq {1..4}) Seq.chunkBySize 2 (Seq.initInfinite id) |> Seq.take 3 @@ -372,8 +372,8 @@ type SeqModule() = CheckThrowsArgumentNullException (fun () -> Seq.chunkBySize 3 nullSeq |> ignore) // invalidArg - CheckThrowsArgumentException (fun () -> Seq.chunkBySize 0 {1..10} |> ignore) - CheckThrowsArgumentException (fun () -> Seq.chunkBySize -1 {1..10} |> ignore) + CheckThrowsArgumentException (fun () -> Seq.chunkBySize 0 (seq {1..10}) |> ignore) + CheckThrowsArgumentException (fun () -> Seq.chunkBySize -1 (seq {1..10}) |> ignore) () @@ -385,12 +385,12 @@ type SeqModule() = |> Seq.iter ((<||) VerifySeqsEqual) // int Seq - Seq.splitInto 3 {1..10} |> verify (seq [ {1..4}; {5..7}; {8..10} ]) - Seq.splitInto 3 {1..11} |> verify (seq [ {1..4}; {5..8}; {9..11} ]) - Seq.splitInto 3 {1..12} |> verify (seq [ {1..4}; {5..8}; {9..12} ]) + Seq.splitInto 3 (seq {1..10}) |> verify (seq [ seq {1..4}; seq {5..7}; seq {8..10} ]) + Seq.splitInto 3 (seq {1..11}) |> verify (seq [ seq {1..4}; seq {5..8}; seq {9..11} ]) + Seq.splitInto 3 (seq {1..12}) |> verify (seq [ seq {1..4}; seq {5..8}; seq {9..12} ]) - Seq.splitInto 4 {1..5} |> verify (seq [ [1..2]; [3]; [4]; [5] ]) - Seq.splitInto 20 {1..4} |> verify (seq [ [1]; [2]; [3]; [4] ]) + Seq.splitInto 4 (seq {1..5}) |> verify (seq [ [1..2]; [3]; [4]; [5] ]) + Seq.splitInto 20 (seq {1..4}) |> verify (seq [ [1]; [2]; [3]; [4] ]) // string Seq Seq.splitInto 3 ["a";"b";"c";"d";"e"] |> verify ([ ["a"; "b"]; ["c";"d"]; ["e"] ]) @@ -586,10 +586,10 @@ type SeqModule() = [] member _.Except() = // integer Seq - let intSeq1 = seq { yield! {1..100} - yield! {1..100} } - let intSeq2 = {1..10} - let expectedIntSeq = {11..100} + let intSeq1 = seq { yield! seq {1..100} + yield! seq {1..100} } + let intSeq2 = seq {1..10} + let expectedIntSeq = seq {11..100} VerifySeqsEqual expectedIntSeq <| Seq.except intSeq2 intSeq1 @@ -609,7 +609,7 @@ type SeqModule() = // empty Seq let emptyIntSeq = Seq.empty - VerifySeqsEqual {1..100} <| Seq.except emptyIntSeq intSeq1 + VerifySeqsEqual (seq {1..100}) <| Seq.except emptyIntSeq intSeq1 VerifySeqsEqual emptyIntSeq <| Seq.except intSeq1 emptyIntSeq VerifySeqsEqual emptyIntSeq <| Seq.except emptyIntSeq emptyIntSeq VerifySeqsEqual emptyIntSeq <| Seq.except intSeq1 intSeq1 diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs index 8412b999b5d..db3b8a3adcc 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs @@ -479,7 +479,7 @@ type SeqModule2() = member _.Length() = // integer seq - let resultInt = Seq.length {1..8} + let resultInt = Seq.length (seq {1..8}) if resultInt <> 8 then Assert.Fail() // string Seq @@ -505,7 +505,7 @@ type SeqModule2() = | _ when x % 2 = 0 -> 10*x | _ -> x - let resultInt = Seq.map funcInt { 1..10 } + let resultInt = Seq.map funcInt (seq { 1..10 }) let expectedint = seq [1;20;3;40;5;60;7;80;9;100] VerifySeqsEqual expectedint resultInt @@ -531,7 +531,7 @@ type SeqModule2() = member _.Map2() = // integer Seq let funcInt x y = x+y - let resultInt = Seq.map2 funcInt { 1..10 } {2..2..20} + let resultInt = Seq.map2 funcInt (seq { 1..10 }) (seq {2..2..20}) let expectedint = seq [3;6;9;12;15;18;21;24;27;30] VerifySeqsEqual expectedint resultInt @@ -558,16 +558,16 @@ type SeqModule2() = member _.Map3() = // Integer seq let funcInt a b c = (a + b) * c - let resultInt = Seq.map3 funcInt { 1..8 } { 2..9 } { 3..10 } + let resultInt = Seq.map3 funcInt (seq { 1..8 }) (seq { 2..9 }) (seq { 3..10 }) let expectedInt = seq [9; 20; 35; 54; 77; 104; 135; 170] VerifySeqsEqual expectedInt resultInt // First seq is shorter - VerifySeqsEqual (seq [9; 20]) (Seq.map3 funcInt { 1..2 } { 2..9 } { 3..10 }) + VerifySeqsEqual (seq [9; 20]) (Seq.map3 funcInt (seq { 1..2 }) (seq { 2..9 }) (seq { 3..10 })) // Second seq is shorter - VerifySeqsEqual (seq [9; 20; 35]) (Seq.map3 funcInt { 1..8 } { 2..4 } { 3..10 }) + VerifySeqsEqual (seq [9; 20; 35]) (Seq.map3 funcInt (seq { 1..8 }) (seq { 2..4 }) (seq { 3..10 })) // Third seq is shorter - VerifySeqsEqual (seq [9; 20; 35; 54]) (Seq.map3 funcInt { 1..8 } { 2..6 } { 3..6 }) + VerifySeqsEqual (seq [9; 20; 35; 54]) (Seq.map3 funcInt (seq { 1..8 }) (seq { 2..6 }) (seq { 3..6 })) // String seq let funcStr a b c = a + b + c @@ -812,7 +812,7 @@ type SeqModule2() = member _.Collect() = // integer Seq let funcInt x = seq [x+1] - let resultInt = Seq.collect funcInt { 1..10 } + let resultInt = Seq.collect funcInt (seq { 1..10 }) let expectedint = seq {2..11} @@ -843,7 +843,7 @@ type SeqModule2() = // integer Seq let funcInt x y = x+y - let resultInt = Seq.mapi funcInt { 10..2..20 } + let resultInt = Seq.mapi funcInt (seq { 10..2..20 }) let expectedint = seq [10;13;16;19;22;25] VerifySeqsEqual expectedint resultInt @@ -871,7 +871,7 @@ type SeqModule2() = member _.Mapi2() = // integer Seq let funcInt x y z = x+y+z - let resultInt = Seq.mapi2 funcInt { 1..10 } {2..2..20} + let resultInt = Seq.mapi2 funcInt (seq { 1..10 }) (seq {2..2..20}) let expectedint = seq [3;7;11;15;19;23;27;31;35;39] VerifySeqsEqual expectedint resultInt @@ -907,7 +907,7 @@ type SeqModule2() = member _.Indexed() = // integer Seq - let resultInt = Seq.indexed { 10..2..20 } + let resultInt = Seq.indexed (seq { 10..2..20 }) let expectedint = seq [(0,10);(1,12);(2,14);(3,16);(4,18);(5,20)] VerifySeqsEqual expectedint resultInt @@ -931,7 +931,7 @@ type SeqModule2() = [] member _.Max() = // integer Seq - let resultInt = Seq.max { 10..20 } + let resultInt = Seq.max (seq { 10..20 }) Assert.AreEqual(20,resultInt) @@ -954,7 +954,7 @@ type SeqModule2() = // integer Seq let funcInt x = x % 8 - let resultInt = Seq.maxBy funcInt { 2..2..20 } + let resultInt = Seq.maxBy funcInt (seq { 2..2..20 }) Assert.AreEqual(6,resultInt) // string Seq @@ -976,7 +976,7 @@ type SeqModule2() = // integer Seq let funcInt x = x % 8 - let resultInt = Seq.minBy funcInt { 2..2..20 } + let resultInt = Seq.minBy funcInt (seq { 2..2..20 }) Assert.AreEqual(8,resultInt) // string Seq @@ -998,7 +998,7 @@ type SeqModule2() = member _.Min() = // integer Seq - let resultInt = Seq.min { 10..20 } + let resultInt = Seq.min (seq { 10..20 }) Assert.AreEqual(10,resultInt) // string Seq @@ -1017,7 +1017,7 @@ type SeqModule2() = [] member _.Item() = // integer Seq - let resultInt = Seq.item 3 { 10..20 } + let resultInt = Seq.item 3 (seq { 10..20 }) Assert.AreEqual(13, resultInt) // string Seq @@ -1033,11 +1033,11 @@ type SeqModule2() = // Negative index for i = -1 downto -10 do - CheckThrowsArgumentException (fun () -> Seq.item i { 10 .. 20 } |> ignore) + CheckThrowsArgumentException (fun () -> Seq.item i (seq { 10 .. 20 }) |> ignore) // Out of range for i = 11 to 20 do - CheckThrowsArgumentException (fun () -> Seq.item i { 10 .. 20 } |> ignore) + CheckThrowsArgumentException (fun () -> Seq.item i (seq { 10 .. 20 }) |> ignore) [] member _.``item should fail with correct number of missing elements``() = @@ -1057,7 +1057,7 @@ type SeqModule2() = member _.Of_Array() = // integer Seq let resultInt = Seq.ofArray [|1..10|] - let expectedInt = {1..10} + let expectedInt = seq {1..10} VerifySeqsEqual expectedInt resultInt @@ -1076,7 +1076,7 @@ type SeqModule2() = member _.Of_List() = // integer Seq let resultInt = Seq.ofList [1..10] - let expectedInt = {1..10} + let expectedInt = seq {1..10} VerifySeqsEqual expectedInt resultInt @@ -1095,7 +1095,7 @@ type SeqModule2() = [] member _.Pairwise() = // integer Seq - let resultInt = Seq.pairwise {1..3} + let resultInt = Seq.pairwise (seq {1..3}) let expectedInt = seq [1,2;2,3] @@ -1182,7 +1182,7 @@ type SeqModule2() = member _.Scan() = // integer Seq let funcInt x y = x+y - let resultInt = Seq.scan funcInt 9 {1..10} + let resultInt = Seq.scan funcInt 9 (seq {1..10}) let expectedInt = seq [9;10;12;15;19;24;30;37;45;54;64] VerifySeqsEqual expectedInt resultInt @@ -1207,7 +1207,7 @@ type SeqModule2() = member _.ScanBack() = // integer Seq let funcInt x y = x+y - let resultInt = Seq.scanBack funcInt { 1..10 } 9 + let resultInt = Seq.scanBack funcInt (seq { 1..10 }) 9 let expectedInt = seq [64;63;61;58;54;49;43;36;28;19;9] VerifySeqsEqual expectedInt resultInt @@ -1313,7 +1313,7 @@ type SeqModule2() = // integer Seq let resultInt = Seq.sort (seq [1;3;2;4;6;5;7]) - let expectedInt = {1..7} + let expectedInt = seq {1..7} VerifySeqsEqual expectedInt resultInt // string Seq @@ -1960,7 +1960,7 @@ type SeqModule2() = [] member _.tryItem() = // integer Seq - let resultInt = Seq.tryItem 3 { 10..20 } + let resultInt = Seq.tryItem 3 (seq { 10..20 }) Assert.AreEqual(Some(13), resultInt) // string Seq @@ -1976,11 +1976,11 @@ type SeqModule2() = CheckThrowsArgumentNullException (fun () -> Seq.tryItem 3 nullSeq |> ignore) // Negative index - let resultNegativeIndex = Seq.tryItem -1 { 10..20 } + let resultNegativeIndex = Seq.tryItem -1 (seq { 10..20 }) Assert.AreEqual(None, resultNegativeIndex) // Index greater than length - let resultIndexGreater = Seq.tryItem 31 { 10..20 } + let resultIndexGreater = Seq.tryItem 31 (seq { 10..20 }) Assert.AreEqual(None, resultIndexGreater) [] diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs index 8e24be62850..68692f65c67 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/PrimTypes.fs @@ -821,7 +821,7 @@ module internal RangeTestsHelpers = enumerator.Current |> ignore let inline exceptions zero one two = - Assert.Throws (typeof, (fun () -> {one .. zero .. two} |> Seq.length |> ignore)) |> ignore + Assert.Throws (typeof, (fun () -> seq {one .. zero .. two} |> Seq.length |> ignore)) |> ignore Assert.Throws (typeof, (fun () -> [one .. zero .. two] |> List.length |> ignore)) |> ignore Assert.Throws (typeof, (fun () -> [|one .. zero .. two|] |> Array.length |> ignore)) |> ignore @@ -831,10 +831,10 @@ module internal RangeTestsHelpers = Assert.Throws (typeof, (fun () -> regressionExceptionAfterEndVariableStepIntegralRange zero two)) |> ignore let inline common (min0, min1, min2, min3) (max0, max1, max2, max3) (zero, one, two, three) = - Assert.AreEqual (seq {yield min0; yield min1; yield min2; yield min3}, {min0 .. min3}) - Assert.AreEqual (seq {min0; min1; min2; min3}, {min0 .. one .. min3}) - Assert.AreEqual (seq {min0; min2}, {min0 .. two .. min3}) - Assert.AreEqual (seq {min0; min3}, {min0 .. three .. min3}) + Assert.AreEqual (seq {yield min0; yield min1; yield min2; yield min3}, seq {min0 .. min3}) + Assert.AreEqual (seq {min0; min1; min2; min3}, seq {min0 .. one .. min3}) + Assert.AreEqual (seq {min0; min2}, seq {min0 .. two .. min3}) + Assert.AreEqual (seq {min0; min3}, seq {min0 .. three .. min3}) Assert.AreEqual ([min0; min1; min2; min3], [min0 .. min3]) Assert.AreEqual ([min0; min1; min2; min3], [min0 .. one .. min3]) @@ -846,10 +846,10 @@ module internal RangeTestsHelpers = Assert.AreEqual ([|min0; min2|], [|min0 .. two .. min3|]) Assert.AreEqual ([|min0; min3|], [|min0 .. three .. min3|]) - Assert.AreEqual (seq {yield max3; yield max2; yield max1; yield max0}, {max3 .. max0}) - Assert.AreEqual (seq {max3; max2; max1; max0}, {max3 .. one .. max0}) - Assert.AreEqual (seq {max3; max1}, {max3 .. two .. max0}) - Assert.AreEqual (seq {max3; max0}, {max3 .. three .. max0}) + Assert.AreEqual (seq {yield max3; yield max2; yield max1; yield max0}, seq {max3 .. max0}) + Assert.AreEqual (seq {max3; max2; max1; max0}, seq {max3 .. one .. max0}) + Assert.AreEqual (seq {max3; max1}, seq {max3 .. two .. max0}) + Assert.AreEqual (seq {max3; max0}, seq {max3 .. three .. max0}) Assert.AreEqual ([max3; max2; max1; max0], [max3 .. max0]) Assert.AreEqual ([max3; max2; max1; max0], [max3 .. one .. max0]) @@ -861,10 +861,10 @@ module internal RangeTestsHelpers = Assert.AreEqual ([|max3; max1|], [|max3 .. two .. max0|]) Assert.AreEqual ([|max3; max0|], [|max3 .. three .. max0|]) - Assert.AreEqual (Seq.empty, {max0 .. min0}) - Assert.AreEqual (Seq.empty, {max0 .. one .. min0}) - Assert.AreEqual (Seq.empty, {max0 .. two .. min0}) - Assert.AreEqual (Seq.empty, {max0 .. three .. min0}) + Assert.AreEqual (Seq.empty, seq {max0 .. min0}) + Assert.AreEqual (Seq.empty, seq {max0 .. one .. min0}) + Assert.AreEqual (Seq.empty, seq {max0 .. two .. min0}) + Assert.AreEqual (Seq.empty, seq {max0 .. three .. min0}) Assert.AreEqual ([], [max0 .. min0]) Assert.AreEqual ([], [max0 .. one .. min0]) @@ -880,8 +880,8 @@ module internal RangeTestsHelpers = // tests for singleStepRangeEnumerator, as it only is used if start and/or end are not the // minimum or maximum of the number range and it is counting by 1s - Assert.AreEqual (seq {min1; min2; min3}, {min1 .. min3}) - Assert.AreEqual (seq {max3; max2; max1}, {max3 .. max1}) + Assert.AreEqual (seq {min1; min2; min3}, seq {min1 .. min3}) + Assert.AreEqual (seq {max3; max2; max1}, seq {max3 .. max1}) Assert.AreEqual ([min1; min2; min3], [min1 .. min3]) Assert.AreEqual ([max3; max2; max1], [max3 .. max1]) @@ -903,10 +903,10 @@ module internal RangeTestsHelpers = common (min0, min1, min2, min3) (max0, max1, max2, max3) (zero, one, two, three) - Assert.AreEqual (seq { min0; min0 + max0; min0 + max0 + max0 }, {min0 .. max0 .. max0}) - Assert.AreEqual (seq { min0; min0 + max1; min0 + max1 + max1 }, {min0 .. max1 .. max0}) - Assert.AreEqual (seq { min0; min0 + max2; min0 + max2 + max2 }, {min0 .. max2 .. max0}) - Assert.AreEqual (seq { min0; min0 + max3; min0 + max3 + max3 }, {min0 .. max3 .. max0}) + Assert.AreEqual (seq { min0; min0 + max0; min0 + max0 + max0 }, seq {min0 .. max0 .. max0}) + Assert.AreEqual (seq { min0; min0 + max1; min0 + max1 + max1 }, seq {min0 .. max1 .. max0}) + Assert.AreEqual (seq { min0; min0 + max2; min0 + max2 + max2 }, seq {min0 .. max2 .. max0}) + Assert.AreEqual (seq { min0; min0 + max3; min0 + max3 + max3 }, seq {min0 .. max3 .. max0}) Assert.AreEqual ([ min0; min0 + max0; min0 + max0 + max0 ], [min0 .. max0 .. max0]) Assert.AreEqual ([ min0; min0 + max1; min0 + max1 + max1 ], [min0 .. max1 .. max0]) @@ -918,9 +918,9 @@ module internal RangeTestsHelpers = Assert.AreEqual ([| min0; min0 + max2; min0 + max2 + max2 |], [|min0 .. max2 .. max0|]) Assert.AreEqual ([| min0; min0 + max3; min0 + max3 + max3 |], [|min0 .. max3 .. max0|]) - Assert.AreEqual (seq {min3; min2; min1; min0}, {min3 .. -one .. min0}) - Assert.AreEqual (seq {min3; min1}, {min3 .. -two .. min0}) - Assert.AreEqual (seq {min3; min0}, {min3 .. -three .. min0}) + Assert.AreEqual (seq {min3; min2; min1; min0}, seq {min3 .. -one .. min0}) + Assert.AreEqual (seq {min3; min1}, seq {min3 .. -two .. min0}) + Assert.AreEqual (seq {min3; min0}, seq {min3 .. -three .. min0}) Assert.AreEqual ([min3; min2; min1; min0], [min3 .. -one .. min0]) Assert.AreEqual ([min3; min1], [min3 .. -two .. min0]) @@ -930,9 +930,9 @@ module internal RangeTestsHelpers = Assert.AreEqual ([|min3; min1|], [|min3 .. -two .. min0|]) Assert.AreEqual ([|min3; min0|], [|min3 .. -three .. min0|]) - Assert.AreEqual (seq {max0; max1; max2; max3}, {max0 .. -one .. max3}) - Assert.AreEqual (seq {max0; max2}, {max0 .. -two .. max3}) - Assert.AreEqual (seq {max0; max3}, {max0 .. -three .. max3}) + Assert.AreEqual (seq {max0; max1; max2; max3}, seq {max0 .. -one .. max3}) + Assert.AreEqual (seq {max0; max2}, seq {max0 .. -two .. max3}) + Assert.AreEqual (seq {max0; max3}, seq {max0 .. -three .. max3}) Assert.AreEqual ([max0; max1; max2; max3], [max0 .. -one .. max3]) Assert.AreEqual ([max0; max2], [max0 .. -two .. max3]) @@ -942,9 +942,9 @@ module internal RangeTestsHelpers = Assert.AreEqual ([|max0; max2|], [|max0 .. -two .. max3|]) Assert.AreEqual ([|max0; max3|], [|max0 .. -three .. max3|]) - Assert.AreEqual (Seq.empty, {min0 .. -one .. max0}) - Assert.AreEqual (Seq.empty, {min0 .. -two .. max0}) - Assert.AreEqual (Seq.empty, {min0 .. -three .. max0}) + Assert.AreEqual (Seq.empty, seq {min0 .. -one .. max0}) + Assert.AreEqual (Seq.empty, seq {min0 .. -two .. max0}) + Assert.AreEqual (Seq.empty, seq {min0 .. -three .. max0}) Assert.AreEqual ([], [min0 .. -one .. max0]) Assert.AreEqual ([], [min0 .. -two .. max0]) @@ -954,10 +954,10 @@ module internal RangeTestsHelpers = Assert.AreEqual ([||], [|min0 .. -two .. max0|]) Assert.AreEqual ([||], [|min0 .. -three .. max0|]) - Assert.AreEqual (seq {max0; max0 + min0}, {max0 .. min0 .. min0}) - Assert.AreEqual (seq {max0; max0 + min1; max0 + min1 + min1 }, {max0 .. min1 .. min0}) - Assert.AreEqual (seq {max0; max0 + min2; max0 + min2 + min2 }, {max0 .. min2 .. min0}) - Assert.AreEqual (seq {max0; max0 + min3; max0 + min3 + min3 }, {max0 .. min3 .. min0}) + Assert.AreEqual (seq {max0; max0 + min0}, seq {max0 .. min0 .. min0}) + Assert.AreEqual (seq {max0; max0 + min1; max0 + min1 + min1 }, seq {max0 .. min1 .. min0}) + Assert.AreEqual (seq {max0; max0 + min2; max0 + min2 + min2 }, seq {max0 .. min2 .. min0}) + Assert.AreEqual (seq {max0; max0 + min3; max0 + min3 + min3 }, seq {max0 .. min3 .. min0}) Assert.AreEqual ([max0; max0 + min0], [max0 .. min0 .. min0]) Assert.AreEqual ([max0; max0 + min1; max0 + min1 + min1 ], [max0 .. min1 .. min0]) @@ -983,10 +983,10 @@ module internal RangeTestsHelpers = common (min0, min1, min2, min3) (max0, max1, max2, max3) (zero, one, two, three) - Assert.AreEqual (seq {yield min0; yield min0 + max0}, {min0 .. max0 .. max0}) - Assert.AreEqual (seq {min0; min0 + max1}, {min0 .. max1 .. max0}) - Assert.AreEqual (seq {min0; min0 + max2}, {min0 .. max2 .. max0}) - Assert.AreEqual (seq {min0; min0 + max3}, {min0 .. max3 .. max0}) + Assert.AreEqual (seq {yield min0; yield min0 + max0}, seq {min0 .. max0 .. max0}) + Assert.AreEqual (seq {min0; min0 + max1}, seq {min0 .. max1 .. max0}) + Assert.AreEqual (seq {min0; min0 + max2}, seq {min0 .. max2 .. max0}) + Assert.AreEqual (seq {min0; min0 + max3}, seq {min0 .. max3 .. max0}) Assert.AreEqual ([min0; min0 + max0], [min0 .. max0 .. max0]) Assert.AreEqual ([min0; min0 + max1], [min0 .. max1 .. max0]) @@ -1064,15 +1064,15 @@ module RangeTests = Assert.AreEqual(256, let mutable c = 0 in for _ in System.SByte.MinValue..1y..System.SByte.MaxValue do c <- c + 1 done; c) Assert.AreEqual(256, let mutable c = 0 in for _ in System.SByte.MaxValue .. -1y .. System.SByte.MinValue do c <- c + 1 done; c) - Assert.AreEqual(allSBytesSeq, {System.SByte.MinValue..System.SByte.MaxValue}) + Assert.AreEqual(allSBytesSeq, seq {System.SByte.MinValue..System.SByte.MaxValue}) Assert.AreEqual(allSBytesList, [System.SByte.MinValue..System.SByte.MaxValue]) Assert.AreEqual(allSBytesArray, [|System.SByte.MinValue..System.SByte.MaxValue|]) - Assert.AreEqual(allSBytesSeq, {System.SByte.MinValue..1y..System.SByte.MaxValue}) + Assert.AreEqual(allSBytesSeq, seq {System.SByte.MinValue..1y..System.SByte.MaxValue}) Assert.AreEqual(allSBytesList, [System.SByte.MinValue..1y..System.SByte.MaxValue]) Assert.AreEqual(allSBytesArray, [|System.SByte.MinValue..1y..System.SByte.MaxValue|]) - Assert.AreEqual(Seq.rev allSBytesSeq, {System.SByte.MaxValue .. -1y .. System.SByte.MinValue}) + Assert.AreEqual(Seq.rev allSBytesSeq, seq {System.SByte.MaxValue .. -1y .. System.SByte.MinValue}) Assert.AreEqual(List.rev allSBytesList, [System.SByte.MaxValue .. -1y .. System.SByte.MinValue]) Assert.AreEqual(Array.rev allSBytesArray, [|System.SByte.MaxValue .. -1y .. System.SByte.MinValue|]) @@ -1083,11 +1083,11 @@ module RangeTests = Assert.AreEqual(256, let mutable c = 0 in for _ in System.Byte.MinValue..System.Byte.MaxValue do c <- c + 1 done; c) Assert.AreEqual(256, let mutable c = 0 in for _ in System.Byte.MinValue..1uy..System.Byte.MaxValue do c <- c + 1 done; c) - Assert.AreEqual(allBytesSeq, {System.Byte.MinValue..System.Byte.MaxValue}) + Assert.AreEqual(allBytesSeq, seq {System.Byte.MinValue..System.Byte.MaxValue}) Assert.AreEqual(allBytesList, [System.Byte.MinValue..System.Byte.MaxValue]) Assert.AreEqual(allBytesArray, [|System.Byte.MinValue..System.Byte.MaxValue|]) - Assert.AreEqual(allBytesSeq, {System.Byte.MinValue..1uy..System.Byte.MaxValue}) + Assert.AreEqual(allBytesSeq, seq {System.Byte.MinValue..1uy..System.Byte.MaxValue}) Assert.AreEqual(allBytesList, [System.Byte.MinValue..1uy..System.Byte.MaxValue]) Assert.AreEqual(allBytesArray, [|System.Byte.MinValue..1uy..System.Byte.MaxValue|]) @@ -1141,15 +1141,15 @@ module RangeTests = Assert.AreEqual(256, let mutable c = 0 in for _ in min0..one..max0 do c <- c + 1 done; c) Assert.AreEqual(256, let mutable c = 0 in for _ in max0 .. -one .. min0 do c <- c + 1 done; c) - Assert.AreEqual(allSBytesSeq, {min0..max0}) + Assert.AreEqual(allSBytesSeq, seq {min0..max0}) Assert.AreEqual(allSBytesList, [min0..max0]) Assert.AreEqual(allSBytesArray, [|min0..max0|]) - Assert.AreEqual(allSBytesSeq, {min0..one..max0}) + Assert.AreEqual(allSBytesSeq, seq {min0..one..max0}) Assert.AreEqual(allSBytesList, [min0..one..max0]) Assert.AreEqual(allSBytesArray, [|min0..one..max0|]) - Assert.AreEqual(Seq.rev allSBytesSeq, {max0 .. -one .. min0}) + Assert.AreEqual(Seq.rev allSBytesSeq, seq {max0 .. -one .. min0}) Assert.AreEqual(List.rev allSBytesList, [max0 .. -one .. min0]) Assert.AreEqual(Array.rev allSBytesArray, [|max0 .. -one .. min0|]) @@ -1160,11 +1160,11 @@ module RangeTests = Assert.AreEqual(256, let mutable c = 0 in for _ in min0..max0 do c <- c + 1 done; c) Assert.AreEqual(256, let mutable c = 0 in for _ in min0..one..max0 do c <- c + 1 done; c) - Assert.AreEqual(allBytesSeq, {min0..max0}) + Assert.AreEqual(allBytesSeq, seq {min0..max0}) Assert.AreEqual(allBytesList, [min0..max0]) Assert.AreEqual(allBytesArray, [|min0..max0|]) - Assert.AreEqual(allBytesSeq, {min0..one..max0}) + Assert.AreEqual(allBytesSeq, seq {min0..one..max0}) Assert.AreEqual(allBytesList, [min0..one..max0]) Assert.AreEqual(allBytesArray, [|min0..one..max0|]) diff --git a/tests/FSharp.Core.UnitTests/TestFrameworkHelpers.fs b/tests/FSharp.Core.UnitTests/TestFrameworkHelpers.fs index d5fe22cc3b3..31a699ae586 100644 --- a/tests/FSharp.Core.UnitTests/TestFrameworkHelpers.fs +++ b/tests/FSharp.Core.UnitTests/TestFrameworkHelpers.fs @@ -72,7 +72,7 @@ module private Impl = let ub = a1.GetUpperBound(0) if lb <> a2.GetLowerBound(0) || ub <> a2.GetUpperBound(0) then false else - {lb..ub} |> Seq.forall(fun i -> equals (a1.GetValue(i)) (a2.GetValue(i))) + seq {lb..ub} |> Seq.forall(fun i -> equals (a1.GetValue(i)) (a2.GetValue(i))) | _ -> Object.Equals(expected, actual) diff --git a/vsintegration/src/FSharp.Editor/CodeFixes/AddMissingSeq.fs b/vsintegration/src/FSharp.Editor/CodeFixes/AddMissingSeq.fs new file mode 100644 index 00000000000..e9a5783bbb2 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/CodeFixes/AddMissingSeq.fs @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.VisualStudio.FSharp.Editor + +open System.Collections.Immutable +open System.Composition +open FSharp.Compiler.Syntax +open FSharp.Compiler.Text +open Microsoft.CodeAnalysis.CodeFixes +open Microsoft.CodeAnalysis.Text +open CancellableTasks + +[] +[] +type internal AddMissingSeqCodeFixProvider() = + inherit CodeFixProvider() + + static let title = SR.AddMissingSeq() + static let fixableDiagnosticIds = ImmutableArray.Create("FS3873", "FS0740") + + override _.FixableDiagnosticIds = fixableDiagnosticIds + override this.RegisterCodeFixesAsync context = context.RegisterFsharpFix this + override this.GetFixAllProvider() = this.RegisterFsharpFixAll() + + interface IFSharpCodeFixProvider with + member _.GetCodeFixIfAppliesAsync context = + cancellableTask { + let! sourceText = context.GetSourceTextAsync() + let! parseFileResults = context.Document.GetFSharpParseResultsAsync(nameof AddMissingSeqCodeFixProvider) + + let getSourceLineStr line = + sourceText.Lines[Line.toZ line].ToString() + + let range = + RoslynHelpers.TextSpanToFSharpRange(context.Document.FilePath, context.Span, sourceText) + + let needsParens = + (range.Start, parseFileResults.ParseTree) + ||> ParsedInput.exists (fun path node -> + match path, node with + | SyntaxNode.SynExpr outer :: _, SyntaxNode.SynExpr(expr & SynExpr.ComputationExpr _) when + expr.Range |> Range.equals range + -> + let seqRange = + range + |> Range.withEnd (Position.mkPos range.Start.Line (range.Start.Column + 3)) + + let inner = + SynExpr.App( + ExprAtomicFlag.NonAtomic, + false, + SynExpr.Ident(Ident(nameof seq, seqRange)), + expr, + Range.unionRanges seqRange expr.Range + ) + + let outer = + match outer with + | SynExpr.App(flag, isInfix, funcExpr, _, outerAppRange) -> + SynExpr.App(flag, isInfix, funcExpr, inner, outerAppRange) + | outer -> outer + + inner + |> SynExpr.shouldBeParenthesizedInContext getSourceLineStr (SyntaxNode.SynExpr outer :: path) + | _ -> false) + + let text = sourceText.ToString(TextSpan(context.Span.Start, context.Span.Length)) + let newText = if needsParens then $"(seq {text})" else $"seq {text}" + + return + ValueSome + { + Name = CodeFix.AddMissingSeq + Message = title + Changes = [ TextChange(context.Span, newText) ] + } + } diff --git a/vsintegration/src/FSharp.Editor/Common/Constants.fs b/vsintegration/src/FSharp.Editor/Common/Constants.fs index 822af01d16a..24ee22eb433 100644 --- a/vsintegration/src/FSharp.Editor/Common/Constants.fs +++ b/vsintegration/src/FSharp.Editor/Common/Constants.fs @@ -208,3 +208,6 @@ module internal CodeFix = [] let RemoveUnnecessaryParentheses = "RemoveUnnecessaryParentheses" + + [] + let AddMissingSeq = "AddMissingSeq" diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 37bb02d43d2..2ec608dda20 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -141,6 +141,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx index 26b96dcc405..fac57e8b469 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx @@ -359,6 +359,9 @@ Use live (unsaved) buffers for analysis Remove unnecessary parentheses + + Add missing 'seq' + Remarks: diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index 421cc037111..7f7c1064aad 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -17,6 +17,11 @@ Přidat chybějící parametr člena instance + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Přidejte klíčové slovo new. diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index ff2a415b3a0..4117ecceddc 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -17,6 +17,11 @@ Fehlenden Instanzmemberparameter hinzufügen + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Schlüsselwort "new" hinzufügen diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index 5df84b54acc..729a252061a 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -17,6 +17,11 @@ Agregar parámetro de miembro de instancia que falta + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Agregar "nueva" palabra clave diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index efe15d65037..a49ba5d1a13 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -17,6 +17,11 @@ Ajouter un paramètre de membre d’instance manquant + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Ajouter le mot clé 'new' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index ca32c029946..0f82d483df8 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -17,6 +17,11 @@ Aggiungi parametro membro di istanza mancante + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Aggiungi la parola chiave 'new' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index 44ca609e1cd..71c981ec17c 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -17,6 +17,11 @@ 見つからないインスタンス メンバー パラメーターを追加する + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword 'new' キーワードを追加する diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index 66cfbeed575..776efa37ca0 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -17,6 +17,11 @@ 누락된 인스턴스 멤버 매개 변수 추가 + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword 'new' 키워드 추가 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index 1675887bd6d..d4b1c40cd09 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -17,6 +17,11 @@ Dodaj brakujący parametr składowej wystąpienia + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Dodaj słowo kluczowe „new” diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf index f6770d970de..d743e4f549d 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -17,6 +17,11 @@ Adicionar parâmetro de membro de instância ausente + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Adicionar a palavra-chave 'new' diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index bc8554237a8..623dbc446f3 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -17,6 +17,11 @@ Добавить отсутствующий параметр экземплярного элемента + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword Добавить ключевое слово "new" diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index cf2198ba7d3..d652ca45127 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -17,6 +17,11 @@ Eksik örnek üye parametresini ekleyin + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword 'new' anahtar sözcüğünü ekleme diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf index 16a89acc021..e0d31417ab4 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -17,6 +17,11 @@ 添加缺少的实例成员参数 + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword 添加“新”关键字 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf index 932d4de3e61..89f6de50bcd 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -17,6 +17,11 @@ 新增缺少的執行個體成員參數 + + Add missing 'seq' + Add missing 'seq' + + Add 'new' keyword 新增 'new' 關鍵字 diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddMissingSeqTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddMissingSeqTests.fs new file mode 100644 index 00000000000..8a51be6a8fc --- /dev/null +++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/AddMissingSeqTests.fs @@ -0,0 +1,239 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +module FSharp.Editor.Tests.CodeFixes.AddMissingSeqTests + +open Microsoft.VisualStudio.FSharp.Editor +open Xunit +open CodeFixTestFramework + +let private codeFix = AddMissingSeqCodeFixProvider() + +// This can be changed to Auto when featureDeprecatePlacesWhereSeqCanBeOmitted is out of preview. +let mode = WithOption "--langversion:preview" + +[] +let ``FS3873 — Adds missing seq before { start..finish }`` () = + let code = "let xs = { 1..10 }" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = seq { 1..10 }" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds missing seq before { start..step..finish }`` () = + let code = "let xs = { 1..5..10 }" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = seq { 1..5..10 }" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS0740 — Adds missing seq before { x; y }`` () = + let code = "let xs = { 1; 10 }" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = seq { 1; 10 }" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds missing seq before yield { start..finish }`` () = + let code = "let xs = [| yield { 1..100 } |]" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = [| yield seq { 1..100 } |]" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds missing seq before yield { start..finish } multiline`` () = + let code = + """ +let xs = [| yield seq { 1..100 } + yield { 1..100 } |] +""" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = + """ +let xs = [| yield seq { 1..100 } + yield seq { 1..100 } |] +""" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds parens when needed — app`` () = + let code = "let xs = id { 1..10 }" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = id (seq { 1..10 })" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds parens when needed — app parens`` () = + let code = "let xs = ResizeArray({ 1..10 })" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = ResizeArray(seq { 1..10 })" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds parens when needed — foreach`` () = + let code = "[ for x in { 1..10 } -> x ]" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "[ for x in seq { 1..10 } -> x ]" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds parens when needed — dot`` () = + let code = "let s = { 1..10 }.ToString ()" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let s = (seq { 1..10 }).ToString ()" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS0740 — Adds parens when needed — app`` () = + let code = "let xs = id { 1; 10 }" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let xs = id (seq { 1; 10 })" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS0740 — Adds parens when needed — dot`` () = + let code = "let s = { 1; 10 }.ToString ()" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = "let s = (seq { 1; 10 }).ToString ()" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS3873 — Adds parens when needed — multiline`` () = + let code = + """ +let xs = + id { + 1..10 + } +""" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = + """ +let xs = + id (seq { + 1..10 + }) +""" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) + +[] +let ``FS0740 — Adds parens when needed — multiline`` () = + let code = + """ +let xs = + id { + 1; 10 + } +""" + + let expected = + Some + { + Message = "Add missing 'seq'" + FixedCode = + """ +let xs = + id (seq { + 1; 10 + }) +""" + } + + let actual = codeFix |> tryFix code mode + + Assert.Equal(expected, actual) diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj index a180accc43f..738a3e1323c 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj +++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj @@ -72,6 +72,7 @@ + From f07a91420bec3f657153e16c9f047cf151c1179f Mon Sep 17 00:00:00 2001 From: "Kevin Ransom (msft)" Date: Tue, 22 Oct 2024 17:17:36 -0700 Subject: [PATCH 11/22] cherry pick (#17907) --- src/FSharp.Build/Microsoft.FSharp.NetSdk.props | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/FSharp.Build/Microsoft.FSharp.NetSdk.props b/src/FSharp.Build/Microsoft.FSharp.NetSdk.props index 792df8e2356..71dfca26382 100644 --- a/src/FSharp.Build/Microsoft.FSharp.NetSdk.props +++ b/src/FSharp.Build/Microsoft.FSharp.NetSdk.props @@ -130,6 +130,22 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and true + + + CompileFirst + + + + CompileBefore + + + + CompileAfter + + + + CompileLast + From e49b91fa7e711d8f744a9e490e10dccef9c7f146 Mon Sep 17 00:00:00 2001 From: Jo Shields Date: Wed, 23 Oct 2024 01:58:07 -0400 Subject: [PATCH 12/22] Rename SourceBuildUseMonoRuntime property, which is not SB specific (#17778) This is a coordinated cross-repo change, and might break the build until all four PRs are merged. The other three are: Ref: https://github.com/dotnet/source-build/issues/4165 --- Directory.Build.props | 2 +- eng/DotNetBuild.props | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 8802ca237b5..c4f2bff9287 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -44,7 +44,7 @@ true - false + false diff --git a/eng/DotNetBuild.props b/eng/DotNetBuild.props index 6891541838a..d1681803391 100644 --- a/eng/DotNetBuild.props +++ b/eng/DotNetBuild.props @@ -30,7 +30,7 @@ --tfm $(SourceBuildBootstrapTfm) - false + false From 1f9bbca7c3cb517149776f273aad89bf13790e23 Mon Sep 17 00:00:00 2001 From: Petr Pokorny Date: Wed, 23 Oct 2024 13:42:25 +0200 Subject: [PATCH 13/22] Convert OCE to empty value on certain VS operations (#17906) --- .../Classification/ClassificationService.fs | 1 + .../FSharp.Editor/Common/CancellableTasks.fs | 23 ++++++++++++++----- .../Structure/BlockStructureService.fs | 3 +++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs index 889ebec9718..afdb990489b 100644 --- a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs +++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs @@ -295,6 +295,7 @@ type internal FSharpClassificationService [] () = addSemanticClassification sourceText textSpan classificationData result } + |> CancellableTask.ifCanceledReturn () |> CancellableTask.startAsTask cancellationToken // Do not perform classification if we don't have project options (#defines matter) diff --git a/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs b/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs index 99eb3946bba..78a28eb0de2 100644 --- a/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs +++ b/vsintegration/src/FSharp.Editor/Common/CancellableTasks.fs @@ -19,7 +19,7 @@ // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + namespace Microsoft.VisualStudio.FSharp.Editor // Don't warn about the resumable code invocation @@ -467,8 +467,8 @@ module CancellableTasks = // Low priority extensions type CancellableTaskBuilderBase with - [] - member inline _.Source(awaiter: CancellableTask) = + [] + member inline _.Source(awaiter: CancellableTask) = (fun (token) -> (awaiter token :> Task).GetAwaiter()) /// @@ -611,10 +611,10 @@ module CancellableTasks = fun sm -> if __useResumableCode then sm.Data.ThrowIfCancellationRequested() - + let mutable awaiter = getAwaiter let mutable __stack_fin = true - + if not (Awaiter.isCompleted awaiter) then let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) __stack_fin <- __stack_yield_fin @@ -706,7 +706,7 @@ module CancellableTasks = (task: 'Awaitable) : 'Awaiter = Awaitable.getAwaiter task - + /// Allows the computation expression to turn other types into CancellationToken -> 'Awaiter /// @@ -1119,6 +1119,17 @@ module CancellableTasks = let inline ignore ([] ctask: CancellableTask<_>) = toUnit ctask + /// If this CancellableTask gets canceled for another reason than the token being canceled, return the specified value. + let inline ifCanceledReturn value (ctask : CancellableTask<_>) = + cancellableTask { + let! ct = getCancellationToken () + + try + return! ctask + with :? OperationCanceledException when ct.IsCancellationRequested = false -> + return value + } + /// [] module MergeSourcesExtensions = diff --git a/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs b/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs index f96ea848c1f..d0326d84311 100644 --- a/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs +++ b/vsintegration/src/FSharp.Editor/Structure/BlockStructureService.fs @@ -156,6 +156,8 @@ open CancellableTasks [)>] type internal FSharpBlockStructureService [] () = + let emptyValue = FSharpBlockStructure ImmutableArray.empty + interface IFSharpBlockStructureService with member _.GetBlockStructureAsync(document, cancellationToken) : Task = @@ -171,4 +173,5 @@ type internal FSharpBlockStructureService [] () = |> Seq.toImmutableArray |> FSharpBlockStructure } + |> CancellableTask.ifCanceledReturn emptyValue |> CancellableTask.start cancellationToken From 85f090f46eb7c805d1fa677a7e134081f3a19429 Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Wed, 23 Oct 2024 04:47:06 -0700 Subject: [PATCH 14/22] Merge release/dev17.12 to main (#17863) * Revert PR - Make the interaction between #line and #nowarn directives consistent (#17859) * merge * revert Reverting PR - Make the interaction between #line and #nowarn directives consistent * Update LanguageFeatures.fs --------- Co-authored-by: Kevin Ransom (msft) Co-authored-by: Tomas Grosup Co-authored-by: Vlad Zarytovskii --- buildtools/fslex/fslex.fsproj | 1 + buildtools/fsyacc/fsyacc.fsproj | 1 + src/Compiler/FSharp.Compiler.Service.fsproj | 2 ++ 3 files changed, 4 insertions(+) diff --git a/buildtools/fslex/fslex.fsproj b/buildtools/fslex/fslex.fsproj index 5dfef2f0e31..b450de1668d 100644 --- a/buildtools/fslex/fslex.fsproj +++ b/buildtools/fslex/fslex.fsproj @@ -5,6 +5,7 @@ $(FSharpNetCoreProductTargetFramework) true LatestMajor + $(NoWarn);64;1182;1204 diff --git a/buildtools/fsyacc/fsyacc.fsproj b/buildtools/fsyacc/fsyacc.fsproj index 1ff8a110759..5f97b762e03 100644 --- a/buildtools/fsyacc/fsyacc.fsproj +++ b/buildtools/fsyacc/fsyacc.fsproj @@ -5,6 +5,7 @@ $(FSharpNetCoreProductTargetFramework) true LatestMajor + $(NoWarn);64;1182;1204 diff --git a/src/Compiler/FSharp.Compiler.Service.fsproj b/src/Compiler/FSharp.Compiler.Service.fsproj index 36b184502f1..cf3e820b879 100644 --- a/src/Compiler/FSharp.Compiler.Service.fsproj +++ b/src/Compiler/FSharp.Compiler.Service.fsproj @@ -10,6 +10,8 @@ $(NoWarn);75 $(NoWarn);1204 $(NoWarn);NU5125 + $(NoWarn);64;1182;1204 + $(OtherFlags) --warnaserror-:1182 FSharp.Compiler.Service true $(DefineConstants);COMPILER From 5caa6154467dadf46154fbdf426d69cac46ac724 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 13:47:25 +0200 Subject: [PATCH 15/22] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20241015.1 (#17891) Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 10.0.0-alpha.1.24514.1 -> To Version 10.0.0-alpha.1.24515.1 Co-authored-by: dotnet-maestro[bot] Co-authored-by: Tomas Grosup --- eng/Version.Details.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 92075c52737..19118639aa2 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,9 +1,9 @@ - + https://github.com/dotnet/source-build-reference-packages - f3889ab90d78377122a3e427fe9a74c03611a4bd + ccd0927e3823fb178c7151594f5d2eaba81bba81 From 8ff644a44fc9eb729a7131bb20e8e9c5d8c26f71 Mon Sep 17 00:00:00 2001 From: Jakub Majocha <1760221+majocha@users.noreply.github.com> Date: Thu, 24 Oct 2024 01:05:25 +0200 Subject: [PATCH 16/22] Preserve console encoding when using --utf8output switch without swapping console streams (#17761) * do not modify stdout * preserve original encoding * Revert "preserve original encoding" This reverts commit 9665470b8b0cd774bb15ffeae07a0d500438a484. * add a test * wip * fantomas * add fsi test * utf16 --------- Co-authored-by: Tomas Grosup --- src/Compiler/Driver/fsc.fs | 24 +++++----- src/Compiler/Interactive/fsi.fs | 22 ++++++--- src/Compiler/Service/service.fs | 8 ---- src/fsi/fsimain.fs | 10 ---- .../CompilerOptions/fsc/misc/utf8output.fs | 47 +++++++++++++++++++ .../FSharp.Compiler.ComponentTests.fsproj | 1 + 6 files changed, 75 insertions(+), 37 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/misc/utf8output.fs diff --git a/src/Compiler/Driver/fsc.fs b/src/Compiler/Driver/fsc.fs index ac4ee179538..a74f35f21b5 100644 --- a/src/Compiler/Driver/fsc.fs +++ b/src/Compiler/Driver/fsc.fs @@ -273,9 +273,6 @@ let SetProcessThreadLocals tcConfigB = | Some s -> Thread.CurrentThread.CurrentUICulture <- CultureInfo(s) | None -> () - if tcConfigB.utf8output then - Console.OutputEncoding <- Encoding.UTF8 - let ProcessCommandLineFlags (tcConfigB: TcConfigBuilder, lcidFromCodePage, argv) = let mutable inputFilesRef = [] @@ -550,6 +547,17 @@ let main1 | Some parallelReferenceResolution -> tcConfigB.parallelReferenceResolution <- parallelReferenceResolution | None -> () + if tcConfigB.utf8output && Console.OutputEncoding <> Encoding.UTF8 then + let previousEncoding = Console.OutputEncoding + Console.OutputEncoding <- Encoding.UTF8 + + disposables.Register( + { new IDisposable with + member _.Dispose() = + Console.OutputEncoding <- previousEncoding + } + ) + // Display the banner text, if necessary if not bannerAlreadyPrinted then Console.Write(GetBannerText tcConfigB) @@ -1242,16 +1250,6 @@ let CompileFromCommandLineArguments ) = use disposables = new DisposablesTracker() - let savedOut = Console.Out - - use _ = - { new IDisposable with - member _.Dispose() = - try - Console.SetOut(savedOut) - with _ -> - () - } main1 ( ctok, diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 74fcc37340c..c1c60d6e47d 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -846,7 +846,7 @@ type internal FsiStdinSyphon(errorWriter: TextWriter) = /// Encapsulates functions used to write to outWriter and errorWriter type internal FsiConsoleOutput(tcConfigB, outWriter: TextWriter, errorWriter: TextWriter) = - let nullOut = new StreamWriter(Stream.Null) :> TextWriter + let nullOut = TextWriter.Null let fprintfnn (os: TextWriter) fmt = Printf.kfprintf @@ -1203,11 +1203,6 @@ type internal FsiCommandLineOptions(fsi: FsiEvaluationSessionHostConfig, argv: s if tcConfigB.clearResultsCache then dependencyProvider.ClearResultsCache(tcConfigB.compilerToolPaths, getOutputDir tcConfigB, reportError rangeCmdArgs) - if tcConfigB.utf8output then - let prev = Console.OutputEncoding - Console.OutputEncoding <- Encoding.UTF8 - System.AppDomain.CurrentDomain.ProcessExit.Add(fun _ -> Console.OutputEncoding <- prev) - do let firstArg = match sourceFiles with @@ -4646,6 +4641,20 @@ type FsiEvaluationSession with e -> warning (e) + let restoreEncoding = + if tcConfigB.utf8output && Console.OutputEncoding <> Text.Encoding.UTF8 then + let previousEncoding = Console.OutputEncoding + Console.OutputEncoding <- Encoding.UTF8 + + Some( + { new IDisposable with + member _.Dispose() = + Console.OutputEncoding <- previousEncoding + } + ) + else + None + do updateBannerText () // resetting banner text after parsing options @@ -4789,6 +4798,7 @@ type FsiEvaluationSession member _.Dispose() = (tcImports :> IDisposable).Dispose() uninstallMagicAssemblyResolution.Dispose() + restoreEncoding |> Option.iter (fun x -> x.Dispose()) /// Load the dummy interaction, load the initial files, and, /// if interacting, start the background thread to read the standard input. diff --git a/src/Compiler/Service/service.fs b/src/Compiler/Service/service.fs index 5f6588bd770..3e42e03223c 100644 --- a/src/Compiler/Service/service.fs +++ b/src/Compiler/Service/service.fs @@ -100,14 +100,6 @@ module CompileHelpers = diagnostics.ToArray(), result - let setOutputStreams execute = - // Set the output streams, if requested - match execute with - | Some(writer, error) -> - Console.SetOut writer - Console.SetError error - | None -> () - [] // There is typically only one instance of this type in an IDE process. type FSharpChecker diff --git a/src/fsi/fsimain.fs b/src/fsi/fsimain.fs index c13f37c11bc..4b9e92704a7 100644 --- a/src/fsi/fsimain.fs +++ b/src/fsi/fsimain.fs @@ -358,16 +358,6 @@ let evaluateSession (argv: string[]) = let MainMain argv = ignore argv let argv = System.Environment.GetCommandLineArgs() - let savedOut = Console.Out - - use __ = - { new IDisposable with - member _.Dispose() = - try - Console.SetOut(savedOut) - with _ -> - () - } let timesFlag = argv |> Array.exists (fun x -> x = "/times" || x = "--times") diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/misc/utf8output.fs b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/misc/utf8output.fs new file mode 100644 index 00000000000..6c6216a8377 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/CompilerOptions/fsc/misc/utf8output.fs @@ -0,0 +1,47 @@ +// 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 +open System + +module utf8output = + + [] + let ``OutputEncoding is restored after executing compilation`` () = + let currentEncoding = Console.OutputEncoding + use restoreCurrentEncodingAfterTest = { new IDisposable with member _.Dispose() = Console.OutputEncoding <- currentEncoding } + + // UTF16 + let encoding = Text.Encoding.Unicode + + Console.OutputEncoding <- encoding + + Fs """printfn "Hello world" """ + |> asExe + |> withOptionsString "--utf8output" + |> compile + |> shouldSucceed + |> ignore + + Console.OutputEncoding.BodyName |> Assert.shouldBe encoding.BodyName + + [] + let ``OutputEncoding is restored after running script`` () = + let currentEncoding = Console.OutputEncoding + use restoreCurrentEncodingAfterTest = { new IDisposable with member _.Dispose() = Console.OutputEncoding <- currentEncoding } + + // UTF16 + let encoding = Text.Encoding.Unicode + + Console.OutputEncoding <- encoding + + Fsx """printfn "Hello world" """ + |> withOptionsString "--utf8output" + |> runFsi + |> shouldSucceed + |> ignore + + Console.OutputEncoding.BodyName |> Assert.shouldBe encoding.BodyName diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index af431847400..82c6d363b47 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -288,6 +288,7 @@ + From ee8af8a16965582537635bf13d91af4df6ebd68c Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 24 Oct 2024 11:57:55 +0100 Subject: [PATCH 17/22] Fix Internal error when analysing incomplete inherit member (#17905) * Internal error when analysing incomplete inherit member * release notes * release notes * update syntax tree tests * update baselines * Update src/Compiler/Service/ServiceParseTreeWalk.fs Co-authored-by: Brian Rourke Boll * Update src/Compiler/Driver/GraphChecking/FileContentMapping.fs Co-authored-by: Brian Rourke Boll * Update src/Compiler/Service/ServiceParsedInputOps.fs Co-authored-by: Brian Rourke Boll * Update src/Compiler/Service/ServiceParsedInputOps.fs Co-authored-by: Brian Rourke Boll * update salsa tests * try to debug the test using CI * Fix tests? --------- Co-authored-by: Brian Rourke Boll Co-authored-by: Petr --- .../.FSharp.Compiler.Service/9.0.200.md | 2 ++ src/Compiler/Checking/CheckDeclarations.fs | 2 +- .../GraphChecking/FileContentMapping.fs | 3 ++- src/Compiler/Service/ServiceParseTreeWalk.fs | 3 ++- src/Compiler/Service/ServiceParsedInputOps.fs | 7 ++--- src/Compiler/SyntaxTree/SyntaxTree.fs | 4 +-- src/Compiler/SyntaxTree/SyntaxTree.fsi | 2 +- src/Compiler/pars.fsy | 4 +-- .../ErrorMessages/ClassesTests.fs | 12 +++++++++ ...ervice.SurfaceArea.netstandard20.debug.bsl | 6 ++--- ...vice.SurfaceArea.netstandard20.release.bsl | 6 ++--- .../data/SyntaxTree/Member/Inherit 01.fs.bsl | 2 +- .../data/SyntaxTree/Member/Inherit 03.fs.bsl | 11 ++++---- .../data/SyntaxTree/Member/Inherit 04.fs.bsl | 11 ++++---- .../data/SyntaxTree/Member/Inherit 05.fs.bsl | 4 +-- .../data/SyntaxTree/Member/Inherit 08.fs.bsl | 4 +-- .../Tests.LanguageService.Completion.fs | 26 +++---------------- 17 files changed, 52 insertions(+), 57 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md index 15b5f1248e6..043b2b67178 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md @@ -6,6 +6,8 @@ * Ensure `frameworkTcImportsCache` mutations are thread-safe. ([PR #17795](https://github.com/dotnet/fsharp/pull/17795)) * Fix concurrency issue in `ILPreTypeDefImpl` ([PR #17812](https://github.com/dotnet/fsharp/pull/17812)) * Fix nullness inference for member val and other OO scenarios ([PR #17845](https://github.com/dotnet/fsharp/pull/17845)) +* Fix internal error when analyzing incomplete inherit member ([PR #17905](https://github.com/dotnet/fsharp/pull/17905)) + ### Added * Deprecate places where `seq` can be omitted. ([Language suggestion #1033](https://github.com/fsharp/fslang-suggestions/issues/1033), [PR #17772](https://github.com/dotnet/fsharp/pull/17772)) diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 31ce9be573c..a3dc4998630 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -4473,7 +4473,7 @@ module TcDeclarations = let implements2 = members |> List.choose (function SynMemberDefn.Interface (interfaceType=ty) -> Some(ty, ty.Range) | _ -> None) let inherits = members |> List.choose (function - | SynMemberDefn.Inherit (ty, idOpt, m, _) -> Some(ty, m, idOpt) + | SynMemberDefn.Inherit (Some ty, idOpt, m, _) -> Some(ty, m, idOpt) | SynMemberDefn.ImplicitInherit (ty, _, idOpt, m) -> Some(ty, m, idOpt) | _ -> None) diff --git a/src/Compiler/Driver/GraphChecking/FileContentMapping.fs b/src/Compiler/Driver/GraphChecking/FileContentMapping.fs index 938034623ba..0534c00feb4 100644 --- a/src/Compiler/Driver/GraphChecking/FileContentMapping.fs +++ b/src/Compiler/Driver/GraphChecking/FileContentMapping.fs @@ -220,7 +220,8 @@ let visitSynMemberDefn (md: SynMemberDefn) : FileContentEntry list = | SynMemberDefn.Interface(interfaceType, _, members, _) -> yield! visitSynType interfaceType yield! collectFromOption (List.collect visitSynMemberDefn) members - | SynMemberDefn.Inherit(baseType = t) -> yield! visitSynType t + | SynMemberDefn.Inherit(baseType = Some baseType) -> yield! visitSynType baseType + | SynMemberDefn.Inherit(baseType = None) -> () | SynMemberDefn.ValField(fieldInfo, _) -> yield! visitSynField fieldInfo | SynMemberDefn.NestedType _ -> () | SynMemberDefn.AutoProperty(attributes = attributes; typeOpt = typeOpt; synExpr = synExpr) -> diff --git a/src/Compiler/Service/ServiceParseTreeWalk.fs b/src/Compiler/Service/ServiceParseTreeWalk.fs index ca1a1c5e657..433142e5105 100644 --- a/src/Compiler/Service/ServiceParseTreeWalk.fs +++ b/src/Compiler/Service/ServiceParseTreeWalk.fs @@ -996,7 +996,8 @@ module SyntaxTraversal = |> pick x | ok -> ok - | SynMemberDefn.Inherit(synType, _identOption, range, _) -> traverseInherit (synType, range) + | SynMemberDefn.Inherit(Some synType, _identOption, range, _) -> traverseInherit (synType, range) + | SynMemberDefn.Inherit(None, _, _, _) -> None | SynMemberDefn.ValField _ -> None | SynMemberDefn.NestedType(synTypeDefn, _synAccessOption, _range) -> traverseSynTypeDefn path synTypeDefn diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index cfbefd49ade..3be806eaa9f 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -913,8 +913,8 @@ module ParsedInput = walkType t |> Option.orElseWith (fun () -> members |> Option.bind (List.tryPick walkMember)) - | SynMemberDefn.Inherit(baseType = t) -> walkType t - + | SynMemberDefn.Inherit(baseType = Some baseType) -> walkType baseType + | SynMemberDefn.Inherit(baseType = None) -> None | SynMemberDefn.ValField(fieldInfo = field) -> walkField field | SynMemberDefn.NestedType(tdef, _, _) -> walkTypeDefn tdef @@ -2240,7 +2240,8 @@ module ParsedInput = | SynMemberDefn.Interface(interfaceType = t; members = members) -> walkType t members |> Option.iter (List.iter walkMember) - | SynMemberDefn.Inherit(baseType = t) -> walkType t + | SynMemberDefn.Inherit(baseType = Some baseType) -> walkType baseType + | SynMemberDefn.Inherit(baseType = None) -> () | SynMemberDefn.ValField(fieldInfo = field) -> walkField field | SynMemberDefn.NestedType(tdef, _, _) -> walkTypeDefn tdef | SynMemberDefn.AutoProperty(attributes = Attributes attrs; typeOpt = t; synExpr = e) -> diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs index 81e893592b8..a30ea5d811b 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fs +++ b/src/Compiler/SyntaxTree/SyntaxTree.fs @@ -37,7 +37,7 @@ type SynLongIdent = member this.Range = match this with - | SynLongIdent([], _, _) -> failwith "rangeOfLidwd" + | SynLongIdent([], _, _) -> failwith "rangeOfLid" | SynLongIdent([ id ], [], _) -> id.idRange | SynLongIdent([ id ], [ m ], _) -> unionRanges id.idRange m | SynLongIdent(h :: t, [], _) -> unionRanges h.idRange (List.last t).idRange @@ -1496,7 +1496,7 @@ type SynMemberDefn = | Interface of interfaceType: SynType * withKeyword: range option * members: SynMemberDefns option * range: range - | Inherit of baseType: SynType * asIdent: Ident option * range: range * trivia: SynMemberDefnInheritTrivia + | Inherit of baseType: SynType option * asIdent: Ident option * range: range * trivia: SynMemberDefnInheritTrivia | ValField of fieldInfo: SynField * range: range diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fsi b/src/Compiler/SyntaxTree/SyntaxTree.fsi index 379362f407c..b63979ce3fc 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTree.fsi @@ -1670,7 +1670,7 @@ type SynMemberDefn = | Interface of interfaceType: SynType * withKeyword: range option * members: SynMemberDefns option * range: range /// An 'inherit' definition within a class - | Inherit of baseType: SynType * asIdent: Ident option * range: range * trivia: SynMemberDefnInheritTrivia + | Inherit of baseType: SynType option * asIdent: Ident option * range: range * trivia: SynMemberDefnInheritTrivia /// A 'val' definition within a class | ValField of fieldInfo: SynField * range: range diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index fac3f30a073..698527f24d9 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -2317,7 +2317,7 @@ inheritsDefn: | INHERIT atomTypeNonAtomicDeprecated optBaseSpec { let mDecl = unionRanges (rhs parseState 1) $2.Range let trivia = { InheritKeyword = rhs parseState 1 } - SynMemberDefn.Inherit($2, $3, mDecl, trivia) } + SynMemberDefn.Inherit(Some $2, $3, mDecl, trivia) } | INHERIT atomTypeNonAtomicDeprecated opt_HIGH_PRECEDENCE_APP atomicExprAfterType optBaseSpec { let mDecl = unionRanges (rhs parseState 1) $4.Range @@ -2327,7 +2327,7 @@ inheritsDefn: { let mDecl = (rhs parseState 1) let trivia = { InheritKeyword = (rhs parseState 1) } if not $2 then errorR (Error(FSComp.SR.parsTypeNameCannotBeEmpty (), mDecl)) - SynMemberDefn.Inherit(SynType.LongIdent(SynLongIdent([], [], [])), None, mDecl, trivia) } + SynMemberDefn.Inherit(None, None, mDecl, trivia) } optAsSpec: | asSpec diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs index f902fa14369..cb6e1ae7344 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs @@ -831,6 +831,18 @@ type Class() = (Error 961, Line 5, Col 5, Line 5, Col 12, "This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e.g. 'inherit BaseType(args)'.") (Error 946, Line 5, Col 13, Line 5, Col 15, "Cannot inherit from interface type. Use interface ... with instead.") ] + + [] + let ``This 'inherit' declaration specifies the inherited type but no arguments. Type name cannot be empty.`` () = + Fsx """ +type Class() = + inherit + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 3159, Line 3, Col 5, Line 3, Col 12, "Type name cannot be empty.") + ] [] let ``The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class.`` () = diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index f08d67883b7..e0ba696955a 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -8070,8 +8070,8 @@ FSharp.Compiler.Syntax.SynMemberDefn+ImplicitInherit: FSharp.Compiler.Text.Range FSharp.Compiler.Syntax.SynMemberDefn+ImplicitInherit: FSharp.Compiler.Text.Range range FSharp.Compiler.Syntax.SynMemberDefn+ImplicitInherit: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident] get_inheritAlias() FSharp.Compiler.Syntax.SynMemberDefn+ImplicitInherit: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident] inheritAlias -FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.Syntax.SynType baseType -FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.Syntax.SynType get_baseType() +FSharp.Compiler.Syntax.SynMemberDefn+Inherit: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynType] baseType +FSharp.Compiler.Syntax.SynMemberDefn+Inherit: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynType] get_baseType() FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.Text.Range range FSharp.Compiler.Syntax.SynMemberDefn+Inherit: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident] asIdent @@ -8153,7 +8153,7 @@ FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewIm FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitInherit(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Syntax.SynExpr, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia get_trivia() FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia trivia -FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia) +FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynType], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia) FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: FSharp.Compiler.Text.Range InheritKeyword FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: FSharp.Compiler.Text.Range get_InheritKeyword() FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: System.String ToString() diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index f08d67883b7..e0ba696955a 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -8070,8 +8070,8 @@ FSharp.Compiler.Syntax.SynMemberDefn+ImplicitInherit: FSharp.Compiler.Text.Range FSharp.Compiler.Syntax.SynMemberDefn+ImplicitInherit: FSharp.Compiler.Text.Range range FSharp.Compiler.Syntax.SynMemberDefn+ImplicitInherit: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident] get_inheritAlias() FSharp.Compiler.Syntax.SynMemberDefn+ImplicitInherit: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident] inheritAlias -FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.Syntax.SynType baseType -FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.Syntax.SynType get_baseType() +FSharp.Compiler.Syntax.SynMemberDefn+Inherit: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynType] baseType +FSharp.Compiler.Syntax.SynMemberDefn+Inherit: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynType] get_baseType() FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.Text.Range range FSharp.Compiler.Syntax.SynMemberDefn+Inherit: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident] asIdent @@ -8153,7 +8153,7 @@ FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewIm FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitInherit(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Syntax.SynExpr, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia get_trivia() FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia trivia -FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia) +FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynType], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia) FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: FSharp.Compiler.Text.Range InheritKeyword FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: FSharp.Compiler.Text.Range get_InheritKeyword() FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia: System.String ToString() diff --git a/tests/service/data/SyntaxTree/Member/Inherit 01.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 01.fs.bsl index f10dc2c0997..817c15422b4 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 01.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 01.fs.bsl @@ -12,7 +12,7 @@ ImplFile ObjectModel (Unspecified, [Inherit - (LongIdent (SynLongIdent ([I], [], [None])), None, + (Some (LongIdent (SynLongIdent ([I], [], [None]))), None, (4,4--4,13), { InheritKeyword = (4,4--4,11) })], (4,4--4,13)), [], None, (3,5--4,13), { LeadingKeyword = Type (3,0--3,4) diff --git a/tests/service/data/SyntaxTree/Member/Inherit 03.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 03.fs.bsl index d0101bb0dd4..76aeb2e2e47 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 03.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 03.fs.bsl @@ -12,12 +12,11 @@ ImplFile ObjectModel (Unspecified, [Inherit - (LongIdent (SynLongIdent ([], [], [])), None, - (4,4--4,11), { InheritKeyword = (4,4--4,11) })], - (4,4--4,11)), [], None, (3,5--4,11), - { LeadingKeyword = Type (3,0--3,4) - EqualsRange = Some (3,7--3,8) - WithKeyword = None })], (3,0--4,11))], + (None, None, (4,4--4,11), + { InheritKeyword = (4,4--4,11) })], (4,4--4,11)), [], + None, (3,5--4,11), { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,7--3,8) + WithKeyword = None })], (3,0--4,11))], PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, (1,0--4,11), { LeadingKeyword = Module (1,0--1,6) })], (true, true), { ConditionalDirectives = [] diff --git a/tests/service/data/SyntaxTree/Member/Inherit 04.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 04.fs.bsl index 7d0dcfc450c..2b1741c3714 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 04.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 04.fs.bsl @@ -12,12 +12,11 @@ ImplFile ObjectModel (Unspecified, [Inherit - (LongIdent (SynLongIdent ([], [], [])), None, - (4,4--4,11), { InheritKeyword = (4,4--4,11) })], - (4,4--4,11)), [], None, (3,5--4,11), - { LeadingKeyword = Type (3,0--3,4) - EqualsRange = Some (3,7--3,8) - WithKeyword = None })], (3,0--4,11)); + (None, None, (4,4--4,11), + { InheritKeyword = (4,4--4,11) })], (4,4--4,11)), [], + None, (3,5--4,11), { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,7--3,8) + WithKeyword = None })], (3,0--4,11)); Expr (Ident I, (6,0--6,1))], PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, (1,0--6,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true), diff --git a/tests/service/data/SyntaxTree/Member/Inherit 05.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 05.fs.bsl index ab71c976fe7..f2bdb9713e2 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 05.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 05.fs.bsl @@ -12,8 +12,8 @@ ImplFile ObjectModel (Unspecified, [Inherit - (LongIdent (SynLongIdent ([], [], [])), None, - (4,4--4,11), { InheritKeyword = (4,4--4,11) }); + (None, None, (4,4--4,11), + { InheritKeyword = (4,4--4,11) }); Member (SynBinding (None, Normal, false, false, [], diff --git a/tests/service/data/SyntaxTree/Member/Inherit 08.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 08.fs.bsl index 757d0a30638..1b0e4712cb5 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 08.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 08.fs.bsl @@ -12,8 +12,8 @@ ImplFile ObjectModel (Unspecified, [Inherit - (LongIdent (SynLongIdent ([], [], [])), None, - (4,4--4,11), { InheritKeyword = (4,4--4,11) }); + (None, None, (4,4--4,11), + { InheritKeyword = (4,4--4,11) }); Member (SynBinding (None, Normal, false, false, [], diff --git a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs index cb08d34ae88..9516280cba9 100644 --- a/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs +++ b/vsintegration/tests/UnitTests/LegacyLanguageService/Tests.LanguageService.Completion.fs @@ -997,7 +997,7 @@ for i in 0..a."] ] ] for ifs in shouldBeInterface do - AssertCtrlSpaceCompleteContains ifs "(*M*)" ["seq"] ["obj"] + AssertCtrlSpaceCompleteContains ifs "(*M*)" ["seq"] [] [] @@ -1026,7 +1026,7 @@ for i in 0..a."] ] ] for cls in shouldBeClass do - AssertCtrlSpaceCompleteContains cls "(*M*)" ["obj"] ["seq"] + AssertCtrlSpaceCompleteContains cls "(*M*)" ["obj"] [] [] member this.``Completion.DetectUnknownCompletionContext``() = @@ -1036,31 +1036,12 @@ for i in 0..a."] " inherit (*M*)" ] - AssertCtrlSpaceCompleteContains content "(*M*)" ["obj"; "seq"] ["abs"] + AssertCtrlSpaceCompleteContains content "(*M*)" ["obj"; "seq"] [] [] member this.``Completion.DetectInvalidCompletionContext``() = let shouldBeInvalid = [ - [ - "type X = struct" - " inherit (*M*)" - ] - [ - "[]" - "type X = class" - " inherit (*M*)" - ] - [ - "[]" - "type X = interface" - " inherit (*M*)" - ] - [ - "[]" - "type X = interface" - " inherit (*M*)" - ] [ "type X =" " inherit System (*M*)." @@ -1076,7 +1057,6 @@ for i in 0..a."] for invalid in shouldBeInvalid do AssertCtrlSpaceCompletionListIsEmpty invalid "(*M*)" - [] member this.``Completion.LongIdentifiers``() = // System.Diagnostics.Debugger.Launch() |> ignore From 8b0900c78e0fa1521ab06af06af410d8f7400414 Mon Sep 17 00:00:00 2001 From: ijklam <43789618+ijklam@users.noreply.github.com> Date: Thu, 24 Oct 2024 20:10:10 +0800 Subject: [PATCH 18/22] Disallow abstract member with access modifiers in sig file (#17802) * Disallow abstract member with access modifiers in sig file * release note * format * fix * fix test * use access modifier range to show error * update tests * update tests * show both FS0531 and FS0561 --------- Co-authored-by: ijklam <43789618+Tangent-90@users.noreply.github.com> Co-authored-by: Kevin Ransom (msft) --- .../.FSharp.Compiler.Service/9.0.200.md | 3 +- src/Compiler/Service/FSharpSource.fsi | 2 +- src/Compiler/SyntaxTree/ParseHelpers.fs | 8 +++ src/Compiler/SyntaxTree/ParseHelpers.fsi | 2 + src/Compiler/pars.fsy | 23 +++++--- .../PermittedLocations/PermittedLocations.fs | 59 +++++++++++++++---- .../AutoPropsWithModifierBeforeGetSet.fs | 13 ++-- 7 files changed, 82 insertions(+), 28 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md index 043b2b67178..b906a5ffec9 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md @@ -3,7 +3,8 @@ * Fix false negatives for passing null to "obj" arguments. Only "obj | null" can now subsume any type ([PR #17757](https://github.com/dotnet/fsharp/pull/17757)) * Fix internal error when calling 'AddSingleton' and other overloads only differing in generic arity ([PR #17804](https://github.com/dotnet/fsharp/pull/17804)) * Fix extension methods support for non-reference system assemblies ([PR #17799](https://github.com/dotnet/fsharp/pull/17799)) -* Ensure `frameworkTcImportsCache` mutations are thread-safe. ([PR #17795](https://github.com/dotnet/fsharp/pull/17795)) +* Ensure `frameworkTcImportsCache` mutations are threadsafe. ([PR #17795](https://github.com/dotnet/fsharp/pull/17795)) +* Disallow abstract member with access modifiers in sig file. ([PR #17802](https://github.com/dotnet/fsharp/pull/17802)) * Fix concurrency issue in `ILPreTypeDefImpl` ([PR #17812](https://github.com/dotnet/fsharp/pull/17812)) * Fix nullness inference for member val and other OO scenarios ([PR #17845](https://github.com/dotnet/fsharp/pull/17845)) * Fix internal error when analyzing incomplete inherit member ([PR #17905](https://github.com/dotnet/fsharp/pull/17905)) diff --git a/src/Compiler/Service/FSharpSource.fsi b/src/Compiler/Service/FSharpSource.fsi index ca272a51fef..6bdabbdedf1 100644 --- a/src/Compiler/Service/FSharpSource.fsi +++ b/src/Compiler/Service/FSharpSource.fsi @@ -26,7 +26,7 @@ type internal FSharpSource = abstract TimeStamp: DateTime /// Gets the internal text container. Text may be on-disk, in a stream, or a source text. - abstract internal GetTextContainer: unit -> Async + abstract GetTextContainer: unit -> Async /// Creates a FSharpSource from disk. Only used internally. static member internal CreateFromFile: filePath: string -> FSharpSource diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fs b/src/Compiler/SyntaxTree/ParseHelpers.fs index c11647ab0a5..59fb645bd0a 100644 --- a/src/Compiler/SyntaxTree/ParseHelpers.fs +++ b/src/Compiler/SyntaxTree/ParseHelpers.fs @@ -1229,3 +1229,11 @@ let mkValField mkSynField parseState idOpt typ isMutable access attribs mStaticOpt rangeStart (Some leadingKeyword) SynMemberDefn.ValField(field, field.Range) + +let leadingKeywordIsAbstract = + function + | SynLeadingKeyword.Abstract _ + | SynLeadingKeyword.AbstractMember _ + | SynLeadingKeyword.StaticAbstract _ + | SynLeadingKeyword.StaticAbstractMember _ -> true + | _ -> false diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fsi b/src/Compiler/SyntaxTree/ParseHelpers.fsi index c98e7897a32..f769b14a864 100644 --- a/src/Compiler/SyntaxTree/ParseHelpers.fsi +++ b/src/Compiler/SyntaxTree/ParseHelpers.fsi @@ -302,3 +302,5 @@ val mkSynField: rangeStart: range -> leadingKeyword: SynLeadingKeyword option -> SynField + +val leadingKeywordIsAbstract: SynLeadingKeyword -> bool diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 698527f24d9..0e56092fe54 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -985,8 +985,12 @@ classMemberSpfn: match optLiteralValue with | None -> m | Some e -> unionRanges m e.Range - + let flags, leadingKeyword = $3 + if leadingKeywordIsAbstract leadingKeyword then + [ $2; $5; getterAccess; setterAccess ] + |> List.iter (function None -> () | Some access -> errorR(Error(FSComp.SR.parsAccessibilityModsIllegalForAbstract(), access.Range))) + let flags = flags (getSetAdjuster arity) let trivia = { LeadingKeyword = leadingKeyword; InlineKeyword = $4; WithKeyword = mWith; EqualsRange = mEquals } let valSpfn = SynValSig($1, id, explicitValTyparDecls, ty, arity, isInline, false, doc, vis2, optLiteralValue, mWhole, trivia) @@ -2046,10 +2050,11 @@ classDefnMember: let ty = SynType.FromParseError(mInterface.EndRange) [ SynMemberDefn.Interface(ty, None, None, rhs2 parseState 1 3) ] } - | opt_attributes opt_access abstractMemberFlags opt_inline nameop opt_explicitValTyparDecls COLON topTypeWithTypeConstraints classMemberSpfnGetSet opt_ODECLEND - { let ty, arity = $8 - let isInline, doc, id, explicitValTyparDecls = (Option.isSome $4), grabXmlDoc(parseState, $1, 1), $5, $6 - let mWith, (getSet, getSetRangeOpt, getterAccess, setterAccess) = $9 + | opt_attributes opt_access abstractMemberFlags opt_access opt_inline nameop opt_explicitValTyparDecls COLON topTypeWithTypeConstraints classMemberSpfnGetSet opt_ODECLEND + { if Option.isSome $2 then errorR(Error(FSComp.SR.parsVisibilityDeclarationsShouldComePriorToIdentifier(), rhs parseState 2)) + let ty, arity = $9 + let isInline, doc, id, explicitValTyparDecls = (Option.isSome $5), grabXmlDoc(parseState, $1, 1), $6, $7 + let mWith, (getSet, getSetRangeOpt, getterAccess, setterAccess) = $10 let getSetAdjuster arity = match arity, getSet with SynValInfo([], _), SynMemberKind.Member -> SynMemberKind.PropertyGet | _ -> getSet let mWhole = let m = rhs parseState 1 @@ -2057,10 +2062,12 @@ classDefnMember: | None -> unionRanges m ty.Range | Some gs -> unionRanges m gs.Range |> unionRangeWithXmlDoc doc - if Option.isSome $2 || Option.isSome getterAccess || Option.isSome setterAccess - then errorR(Error(FSComp.SR.parsAccessibilityModsIllegalForAbstract(), mWhole)) + + [ $2; $4; getterAccess; setterAccess ] + |> List.iter (function None -> () | Some access -> errorR(Error(FSComp.SR.parsAccessibilityModsIllegalForAbstract(), access.Range))) + let mkFlags, leadingKeyword = $3 - let trivia = { LeadingKeyword = leadingKeyword; InlineKeyword = $4; WithKeyword = mWith; EqualsRange = None } + let trivia = { LeadingKeyword = leadingKeyword; InlineKeyword = $5; WithKeyword = mWith; EqualsRange = None } let vis2 = SynValSigAccess.Single(None) let valSpfn = SynValSig($1, id, explicitValTyparDecls, ty, arity, isInline, false, doc, vis2, None, mWhole, trivia) let trivia: SynMemberDefnAbstractSlotTrivia = { GetSetKeywords = getSetRangeOpt } diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/AccessibilityAnnotations/PermittedLocations/PermittedLocations.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/AccessibilityAnnotations/PermittedLocations/PermittedLocations.fs index 68eb881ff7f..7f4c02ab56f 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/AccessibilityAnnotations/PermittedLocations/PermittedLocations.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/AccessibilityAnnotations/PermittedLocations/PermittedLocations.fs @@ -27,12 +27,15 @@ module AccessibilityAnnotations_PermittedLocations = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 561, Line 18, Col 5, Line 18, Col 62, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") - (Error 561, Line 19, Col 5, Line 19, Col 62, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") - (Error 561, Line 20, Col 5, Line 20, Col 62, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") - (Error 10, Line 21, Col 14, Line 21, Col 20, "Unexpected keyword 'public' in member definition. Expected identifier, '(', '(*)' or other token.") - (Error 561, Line 21, Col 14, Line 22, Col 62, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") - (Error 10, Line 23, Col 14, Line 23, Col 22, "Unexpected keyword 'internal' in member definition. Expected identifier, '(', '(*)' or other token.") + (Error 531, Line 18, Col 5, Line 18, Col 11, "Accessibility modifiers should come immediately prior to the identifier naming a construct") + (Error 561, Line 18, Col 5, Line 18, Col 11, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 531, Line 19, Col 5, Line 19, Col 12, "Accessibility modifiers should come immediately prior to the identifier naming a construct") + (Error 561, Line 19, Col 5, Line 19, Col 12, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 531, Line 20, Col 5, Line 20, Col 13, "Accessibility modifiers should come immediately prior to the identifier naming a construct") + (Error 561, Line 20, Col 5, Line 20, Col 13, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 561, Line 21, Col 14, Line 21, Col 20, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 561, Line 22, Col 14, Line 22, Col 21, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 561, Line 23, Col 14, Line 23, Col 22, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") ] // SOURCE=E_accessibilityOnInterface01.fs SCFLAGS="--test:ErrorRanges" # E_accessibilityOnInterface01.fs @@ -42,7 +45,8 @@ module AccessibilityAnnotations_PermittedLocations = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 561, Line 13, Col 5, Line 13, Col 67, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 531, Line 13, Col 5, Line 13, Col 11, "Accessibility modifiers should come immediately prior to the identifier naming a construct") + (Error 561, Line 13, Col 5, Line 13, Col 11, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") ] // SOURCE=E_accessibilityOnInterface02.fs SCFLAGS="--test:ErrorRanges" # E_accessibilityOnInterface02.fs @@ -52,7 +56,8 @@ module AccessibilityAnnotations_PermittedLocations = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 561, Line 15, Col 5, Line 15, Col 68, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 531, Line 15, Col 5, Line 15, Col 12, "Accessibility modifiers should come immediately prior to the identifier naming a construct") + (Error 561, Line 15, Col 5, Line 15, Col 12, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") ] // SOURCE=E_accessibilityOnInterface03.fs SCFLAGS="--test:ErrorRanges" # E_accessibilityOnInterface03.fs @@ -62,7 +67,8 @@ module AccessibilityAnnotations_PermittedLocations = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 561, Line 15, Col 5, Line 15, Col 69, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 531, Line 15, Col 5, Line 15, Col 13, "Accessibility modifiers should come immediately prior to the identifier naming a construct") + (Error 561, Line 15, Col 5, Line 15, Col 13, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") ] // SOURCE=E_accessibilityOnInterface04.fs SCFLAGS="--test:ErrorRanges" # E_accessibilityOnInterface04.fs @@ -72,7 +78,7 @@ module AccessibilityAnnotations_PermittedLocations = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 10, Line 15, Col 14, Line 15, Col 20, "Unexpected keyword 'public' in member definition. Expected identifier, '(', '(*)' or other token.") + (Error 561, Line 15, Col 14, Line 15, Col 20, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") ] // SOURCE=E_accessibilityOnInterface05.fs SCFLAGS="--test:ErrorRanges" # E_accessibilityOnInterface05.fs @@ -82,7 +88,7 @@ module AccessibilityAnnotations_PermittedLocations = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 10, Line 15, Col 14, Line 15, Col 21, "Unexpected keyword 'private' in member definition. Expected identifier, '(', '(*)' or other token.") + (Error 561, Line 15, Col 14, Line 15, Col 21, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") ] // SOURCE=E_accessibilityOnInterface06.fs SCFLAGS="--test:ErrorRanges" # E_accessibilityOnInterface06.fs @@ -92,7 +98,7 @@ module AccessibilityAnnotations_PermittedLocations = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 10, Line 15, Col 14, Line 15, Col 22, "Unexpected keyword 'internal' in member definition. Expected identifier, '(', '(*)' or other token.") + (Error 561, Line 15, Col 14, Line 15, Col 22, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") ] // SOURCE=E_accessibilityOnRecords.fs SCFLAGS="--test:ErrorRanges" # E_accessibilityOnRecords.fs @@ -160,3 +166,32 @@ module AccessibilityAnnotations_PermittedLocations = |> withDiagnostics [ (Error 531, Line 8, Col 13, Line 8, Col 20, "Accessibility modifiers should come immediately prior to the identifier naming a construct") ] + + [] + let ``Signature File Test: abstract member cannot have access modifiers`` () = + Fsi """module Program + +type A = + abstract internal B: int ->int + abstract member internal E: int ->int + abstract member C: int with internal get, private set + abstract internal D: int with get, set + static abstract internal B2: int ->int + static abstract member internal E2: int ->int + static abstract member C2: int with internal get, private set + static abstract internal D2: int with get, set""" + |> withOptions ["--nowarn:3535"] + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 0561, Line 4, Col 14, Line 4, Col 22, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 5, Col 21, Line 5, Col 29, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 6, Col 33, Line 6, Col 41, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 6, Col 47, Line 6, Col 54, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 7, Col 14, Line 7, Col 22, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 8, Col 21, Line 8, Col 29, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 9, Col 28, Line 9, Col 36, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 10, Col 41, Line 10, Col 49, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 10, Col 55, Line 10, Col 62, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 11, Col 21, Line 11, Col 29, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + ] diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/AutoPropsWithModifierBeforeGetSet.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/AutoPropsWithModifierBeforeGetSet.fs index 676746d96f5..7e7cdff06cc 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/AutoPropsWithModifierBeforeGetSet.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/AutoPropsWithModifierBeforeGetSet.fs @@ -110,11 +110,12 @@ let ``Abstract Properties Test: access modifiers are not allowed`` () = |> typecheck |> shouldFail |> withDiagnostics [ - (Error 0561, Line 6, Col 5, Line 6, Col 51, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") - (Error 0561, Line 8, Col 5, Line 8, Col 51, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") - (Error 0561, Line 10, Col 5, Line 10, Col 60, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") - (Error 0561, Line 12, Col 5, Line 12, Col 46, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") - (Error 0561, Line 14, Col 5, Line 14, Col 46, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 6, Col 34, Line 6, Col 42, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 8, Col 39, Line 8, Col 47, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 10, Col 34, Line 10, Col 42, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 10, Col 48, Line 10, Col 56, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 12, Col 34, Line 12, Col 42, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") + (Error 0561, Line 14, Col 34, Line 14, Col 42, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") ] [] @@ -132,7 +133,7 @@ type A = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 240, Line 1, Col 1, Line 9, Col 42, "The signature file 'Program' does not have a corresponding implementation file. If an implementation file exists then check the 'module' and 'namespace' declarations in the signature and implementation files match.") + (Error 0561, Line 9, Col 31, Line 9, Col 38, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.") ] [] From 08a0649d0eb4d49c2a1277f2595cbc9804ba58c2 Mon Sep 17 00:00:00 2001 From: Jakub Majocha <1760221+majocha@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:47:06 +0200 Subject: [PATCH 19/22] Restore one test to original (#17923) --- .../Microsoft.FSharp.Control/Cancellation.fs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Cancellation.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Cancellation.fs index cecfaec7590..a2a97e4d58c 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Cancellation.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Control/Cancellation.fs @@ -265,11 +265,11 @@ type CancellationType() = let cts = new CancellationTokenSource() let tcs = System.Threading.Tasks.TaskCompletionSource<_>() - let test() = + let t = async { do! tcs.Task |> Async.AwaitTask } - |> StartAsTaskProperCancel None (Some cts.Token) :> Task + |> StartAsTaskProperCancel None (Some cts.Token) // First cancel the token, then set the task as cancelled. async { @@ -277,14 +277,15 @@ type CancellationType() = cts.Cancel() do! Async.Sleep 100 tcs.TrySetException (TimeoutException "Task timed out after token.") - |> ignore + |> ignore } |> Async.Start - task { - let! agg = Assert.ThrowsAsync(test) - let inner = agg.InnerException - Assert.True(inner :? TimeoutException, $"Excepted TimeoutException wrapped in an AggregateException, but got %A{inner}") - } + try + let res = t.Wait(2000) + let msg = sprintf "Excepted TimeoutException wrapped in an AggregateException, but got %A" res + printfn "failure msg: %s" msg + Assert.Fail (msg) + with :? AggregateException as agg -> () // Simpler regression test for https://github.com/dotnet/fsharp/issues/3254 [] From 3940e0de63ac975c328487df28954c6963afcf32 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Fri, 25 Oct 2024 15:29:26 +0100 Subject: [PATCH 20/22] Better ranges for implicit `inherit` error reporting. (#17893) * Better ranges for implicit `Inherit` error reporting. * release notes * format * Better check * Update src/Compiler/Checking/CheckDeclarations.fs Co-authored-by: Tomas Grosup * PR comments * do not use 959 * fix PR comments and add more tests * moving 959 to type definition range --------- Co-authored-by: Tomas Grosup --- .../.FSharp.Compiler.Service/9.0.200.md | 1 + src/Compiler/Checking/CheckDeclarations.fs | 31 ++++---- .../GraphChecking/FileContentMapping.fs | 2 +- .../Service/FSharpParseFileResults.fs | 2 +- .../Service/ServiceInterfaceStubGenerator.fs | 2 +- src/Compiler/Service/ServiceParseTreeWalk.fs | 2 +- src/Compiler/Service/ServiceParsedInputOps.fs | 4 +- src/Compiler/SyntaxTree/SyntaxTree.fs | 7 +- src/Compiler/SyntaxTree/SyntaxTree.fsi | 7 +- src/Compiler/pars.fsy | 3 +- .../ErrorMessages/ClassesTests.fs | 79 +++++++++++++++++++ ...ervice.SurfaceArea.netstandard20.debug.bsl | 4 +- ...vice.SurfaceArea.netstandard20.release.bsl | 4 +- .../data/SyntaxTree/Member/Inherit 02.fs.bsl | 10 +-- 14 files changed, 128 insertions(+), 30 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md index b906a5ffec9..c0c5b75b958 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md @@ -25,5 +25,6 @@ * Better ranges for CE `use` error reporting. ([PR #17811](https://github.com/dotnet/fsharp/pull/17811)) * Better ranges for `inherit` error reporting. ([PR #17879](https://github.com/dotnet/fsharp/pull/17879)) * Better ranges for `inherit` `struct` error reporting. ([PR #17886](https://github.com/dotnet/fsharp/pull/17886)) +* Better ranges for `inherit` objects error reporting. ([PR #17893](https://github.com/dotnet/fsharp/pull/17893)) ### Breaking Changes diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index a3dc4998630..80c1a656c2d 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -1090,7 +1090,7 @@ module MutRecBindingChecking = [Phase2AIncrClassCtor (staticCtorInfo, Some incrCtorInfo)], innerState - | Some (SynMemberDefn.ImplicitInherit (ty, arg, _baseIdOpt, m)), _ -> + | Some (SynMemberDefn.ImplicitInherit (ty, arg, _baseIdOpt, m, _)), _ -> if tcref.TypeOrMeasureKind = TyparKind.Measure then error(Error(FSComp.SR.tcMeasureDeclarationsRequireStaticMembers(), m)) @@ -3324,7 +3324,6 @@ module EstablishTypeDefinitionCores = else None | SynTypeDefnSimpleRepr.General (kind, inherits, slotsigs, fields, isConcrete, _, _, _) -> let kind = InferTyconKind g (kind, attrs, slotsigs, fields, inSig, isConcrete, m) - match inheritedTys with | [] -> match kind with @@ -3335,9 +3334,9 @@ module EstablishTypeDefinitionCores = | [(ty, m)] -> let inheritRange = - match inherits with - | [] -> m - | (synType, _, _) :: _ -> synType.Range + match inherits with + | [] -> m + | (synType, _, _) :: _ -> synType.Range if not firstPass && not (match kind with SynTypeDefnKind.Class -> true | _ -> false) then errorR (Error(FSComp.SR.tcStructsInterfacesEnumsDelegatesMayNotInheritFromOtherTypes(), inheritRange)) CheckSuperType cenv ty inheritRange @@ -3345,11 +3344,15 @@ module EstablishTypeDefinitionCores = if firstPass then errorR(Error(FSComp.SR.tcCannotInheritFromVariableType(), inheritRange)) Some g.obj_ty_noNulls // a "super" that is a variable type causes grief later - else - + else Some ty - | _ -> - error(Error(FSComp.SR.tcTypesCannotInheritFromMultipleConcreteTypes(), m)) + | _ -> + match inherits with + | [] -> () + | _ :: inherits -> + for synType, _, _ in inherits do + errorR(Error(FSComp.SR.tcTypesCannotInheritFromMultipleConcreteTypes(), synType.Range)) + None | SynTypeDefnSimpleRepr.Enum _ -> Some(g.system_Enum_ty) @@ -4278,7 +4281,7 @@ module TcDeclarations = // multiple (binding or slotsig or field or interface or inherit). // i.e. not local-bindings, implicit ctor or implicit inherit (or tycon?). // atMostOne inherit. - let private CheckMembersForm ds = + let private CheckMembersForm ds m = match ds with | d :: ds when isImplicitCtor d -> // Implicit construction @@ -4290,7 +4293,7 @@ module TcDeclarations = // Skip over 'let' and 'do' bindings let _, ds = ds |> List.takeUntil (function SynMemberDefn.LetBindings _ -> false | _ -> true) - // Skip over 'let' and 'do' bindings + // Skip over member bindings, abstract slots, interfaces and auto properties let _, ds = ds |> List.takeUntil (allFalse [isMember;isAbstractSlot;isInterface;isAutoProperty]) match ds with @@ -4299,7 +4302,7 @@ module TcDeclarations = | SynMemberDefn.Interface (range=m) :: _ -> errorR(InternalError("List.takeUntil is wrong, have interface", m)) | SynMemberDefn.ImplicitCtor (range=m) :: _ -> errorR(InternalError("implicit class construction with two implicit constructions", m)) | SynMemberDefn.AutoProperty (range=m) :: _ -> errorR(InternalError("List.takeUntil is wrong, have auto property", m)) - | SynMemberDefn.ImplicitInherit (range=m) :: _ -> errorR(Error(FSComp.SR.tcTypeDefinitionsWithImplicitConstructionMustHaveOneInherit(), m)) + | SynMemberDefn.ImplicitInherit _ :: _ -> errorR(Error(FSComp.SR.tcTypeDefinitionsWithImplicitConstructionMustHaveOneInherit(), m)) | SynMemberDefn.LetBindings (range=m) :: _ -> errorR(Error(FSComp.SR.tcTypeDefinitionsWithImplicitConstructionMustHaveLocalBindingsBeforeMembers(), m)) | SynMemberDefn.Inherit (trivia= { InheritKeyword = m }) :: _ -> errorR(Error(FSComp.SR.tcInheritDeclarationMissingArguments(), m)) | SynMemberDefn.NestedType (range=m) :: _ -> errorR(Error(FSComp.SR.tcTypesCannotContainNestedTypes(), m)) @@ -4467,14 +4470,14 @@ module TcDeclarations = | SynTypeDefnRepr.ObjectModel(kind, members, m) -> let members = desugarGetSetMembers members - CheckMembersForm members + CheckMembersForm members synTyconInfo.Range let fields = members |> List.choose (function SynMemberDefn.ValField (fieldInfo = f) -> Some f | _ -> None) let implements2 = members |> List.choose (function SynMemberDefn.Interface (interfaceType=ty) -> Some(ty, ty.Range) | _ -> None) let inherits = members |> List.choose (function | SynMemberDefn.Inherit (Some ty, idOpt, m, _) -> Some(ty, m, idOpt) - | SynMemberDefn.ImplicitInherit (ty, _, idOpt, m) -> Some(ty, m, idOpt) + | SynMemberDefn.ImplicitInherit (ty, _, idOpt, m, _) -> Some(ty, m, idOpt) | _ -> None) //let nestedTycons = cspec |> List.choose (function SynMemberDefn.NestedType (x, _, _) -> Some x | _ -> None) diff --git a/src/Compiler/Driver/GraphChecking/FileContentMapping.fs b/src/Compiler/Driver/GraphChecking/FileContentMapping.fs index 0534c00feb4..7be965522f6 100644 --- a/src/Compiler/Driver/GraphChecking/FileContentMapping.fs +++ b/src/Compiler/Driver/GraphChecking/FileContentMapping.fs @@ -212,7 +212,7 @@ let visitSynMemberDefn (md: SynMemberDefn) : FileContentEntry list = yield! collectFromOption visitBinding memberDefnForGet yield! collectFromOption visitBinding memberDefnForSet | SynMemberDefn.ImplicitCtor(ctorArgs = pat) -> yield! visitPat pat - | SynMemberDefn.ImplicitInherit(inheritType, inheritArgs, _, _) -> + | SynMemberDefn.ImplicitInherit(inheritType, inheritArgs, _, _, _) -> yield! visitSynType inheritType yield! visitSynExpr inheritArgs | SynMemberDefn.LetBindings(bindings = bindings) -> yield! List.collect visitBinding bindings diff --git a/src/Compiler/Service/FSharpParseFileResults.fs b/src/Compiler/Service/FSharpParseFileResults.fs index 7b273f71430..612057578f7 100644 --- a/src/Compiler/Service/FSharpParseFileResults.fs +++ b/src/Compiler/Service/FSharpParseFileResults.fs @@ -817,7 +817,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput, | SynMemberDefn.Inherit(range = m) -> // can break on the "inherit" clause yield! checkRange m - | SynMemberDefn.ImplicitInherit(_, arg, _, m) -> + | SynMemberDefn.ImplicitInherit(_, arg, _, m, _) -> // can break on the "inherit" clause yield! checkRange m yield! walkExpr true arg diff --git a/src/Compiler/Service/ServiceInterfaceStubGenerator.fs b/src/Compiler/Service/ServiceInterfaceStubGenerator.fs index f0ddc777b14..fb3e8dfbecc 100644 --- a/src/Compiler/Service/ServiceInterfaceStubGenerator.fs +++ b/src/Compiler/Service/ServiceInterfaceStubGenerator.fs @@ -825,7 +825,7 @@ module InterfaceStubGenerator = | SynMemberDefn.Open _ | SynMemberDefn.ImplicitCtor _ | SynMemberDefn.Inherit _ -> None - | SynMemberDefn.ImplicitInherit(_, expr, _, _) -> walkExpr expr + | SynMemberDefn.ImplicitInherit(_, expr, _, _, _) -> walkExpr expr and walkBinding (SynBinding(expr = expr)) = walkExpr expr diff --git a/src/Compiler/Service/ServiceParseTreeWalk.fs b/src/Compiler/Service/ServiceParseTreeWalk.fs index 433142e5105..4c55c78a437 100644 --- a/src/Compiler/Service/ServiceParseTreeWalk.fs +++ b/src/Compiler/Service/ServiceParseTreeWalk.fs @@ -958,7 +958,7 @@ module SyntaxTraversal = | SynMemberDefn.ImplicitCtor(ctorArgs = pat) -> traverseSynSimplePats path pat - | SynMemberDefn.ImplicitInherit(synType, synExpr, _identOption, range) -> + | SynMemberDefn.ImplicitInherit(synType, synExpr, _identOption, range, _) -> [ dive () synType.Range (fun () -> match traverseInherit (synType, range) with diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index 3be806eaa9f..2ed457116b6 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -905,7 +905,7 @@ module ParsedInput = | SynMemberDefn.ImplicitCtor(attributes = Attributes attrs; ctorArgs = pat) -> List.tryPick walkAttribute attrs |> Option.orElseWith (fun _ -> walkPat pat) - | SynMemberDefn.ImplicitInherit(t, e, _, _) -> walkType t |> Option.orElseWith (fun () -> walkExpr e) + | SynMemberDefn.ImplicitInherit(t, e, _, _, _) -> walkType t |> Option.orElseWith (fun () -> walkExpr e) | SynMemberDefn.LetBindings(bindings, _, _, _) -> List.tryPick walkBinding bindings @@ -2233,7 +2233,7 @@ module ParsedInput = | SynMemberDefn.ImplicitCtor(attributes = Attributes attrs; ctorArgs = pat) -> List.iter walkAttribute attrs walkPat pat - | SynMemberDefn.ImplicitInherit(t, e, _, _) -> + | SynMemberDefn.ImplicitInherit(t, e, _, _, _) -> walkType t walkExpr e | SynMemberDefn.LetBindings(bindings, _, _, _) -> List.iter walkBinding bindings diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs index a30ea5d811b..d0c39dc1494 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fs +++ b/src/Compiler/SyntaxTree/SyntaxTree.fs @@ -1488,7 +1488,12 @@ type SynMemberDefn = range: range * trivia: SynMemberDefnImplicitCtorTrivia - | ImplicitInherit of inheritType: SynType * inheritArgs: SynExpr * inheritAlias: Ident option * range: range + | ImplicitInherit of + inheritType: SynType * + inheritArgs: SynExpr * + inheritAlias: Ident option * + range: range * + trivia: SynMemberDefnInheritTrivia | LetBindings of bindings: SynBinding list * isStatic: bool * isRecursive: bool * range: range diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fsi b/src/Compiler/SyntaxTree/SyntaxTree.fsi index b63979ce3fc..0b24535623b 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTree.fsi @@ -1654,7 +1654,12 @@ type SynMemberDefn = trivia: SynMemberDefnImplicitCtorTrivia /// An implicit inherit definition, 'inherit (args...) as base' - | ImplicitInherit of inheritType: SynType * inheritArgs: SynExpr * inheritAlias: Ident option * range: range + | ImplicitInherit of + inheritType: SynType * + inheritArgs: SynExpr * + inheritAlias: Ident option * + range: range * + trivia: SynMemberDefnInheritTrivia /// A 'let' definition within a class | LetBindings of bindings: SynBinding list * isStatic: bool * isRecursive: bool * range: range diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 0e56092fe54..b21a51d345c 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -2328,7 +2328,8 @@ inheritsDefn: | INHERIT atomTypeNonAtomicDeprecated opt_HIGH_PRECEDENCE_APP atomicExprAfterType optBaseSpec { let mDecl = unionRanges (rhs parseState 1) $4.Range - SynMemberDefn.ImplicitInherit($2, $4, $5, mDecl) } + let trivia = { InheritKeyword = rhs parseState 1 } + SynMemberDefn.ImplicitInherit($2, $4, $5, mDecl, trivia) } | INHERIT ends_coming_soon_or_recover { let mDecl = (rhs parseState 1) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs index cb6e1ae7344..e86621d7093 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs @@ -861,4 +861,83 @@ type C5 = class inherit System.MulticastDelegate override x.ToString() = "" end (Error 771, Line 4, Col 25, Line 4, Col 36, "The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class") (Error 771, Line 5, Col 25, Line 5, Col 40, "The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class"); (Error 771, Line 6, Col 25, Line 6, Col 49, "The types System.ValueType, System.Enum, System.Delegate, System.MulticastDelegate and System.Array cannot be used as super types in an object expression or class") + ] + + + [] + let ``Types can inherit from a single concrete type`` () = + Fsx """ +type ClassA() = class end + +type Class() = + inherit ClassA() + """ + |> typecheck + |> shouldSucceed + + [] + let ``Types cannot inherit from multiple concrete types.`` () = + Fsx """ +type ClassA() = class end + +type ClassB() = class end + +type ClassC() = class end + +type Class() = + inherit ClassA() + inherit ClassB() + inherit ClassC() + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 959, Line 8, Col 6, Line 8, Col 11, "Type definitions may only have one 'inherit' specification and it must be the first declaration") + (Error 932, Line 10, Col 13, Line 10, Col 19, "Types cannot inherit from multiple concrete types") + (Error 932, Line 11, Col 13, Line 11, Col 19, "Types cannot inherit from multiple concrete types") + ] + + [] + let ``Types cannot inherit from multiple concrete types. Type name cannot be empty.`` () = + Fsx """ +type IA = interface end + +type I = + inherit IA + inherit + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 3159, Line 6, Col 5, Line 6, Col 12, "Type name cannot be empty.") + ] + + [] + let ``Inheriting multiple base interfaces`` () = + Fsx """ +type IA = interface end +type IB = interface end + +type I = + inherit IA + inherit IB + """ + |> typecheck + |> shouldSucceed + + [] + let ``Class inheriting multiple base interfaces`` () = + Fsx """ +type IA = interface end +type IB = interface end + +type I() = + inherit IA + inherit IB + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 961, Line 6, Col 5, Line 6, Col 12, "This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e.g. 'inherit BaseType(args)'.") + (Error 932, Line 7, Col 13, Line 7, Col 15, "Types cannot inherit from multiple concrete types") ] \ No newline at end of file diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index e0ba696955a..5f4436a79f2 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -8150,7 +8150,9 @@ FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewAb FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewAutoProperty(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynAttributeList], Boolean, FSharp.Compiler.Syntax.Ident, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynType], FSharp.Compiler.Syntax.SynMemberKind, FSharp.Compiler.Syntax.SynMemberFlags, FSharp.Compiler.Syntax.SynMemberFlags, FSharp.Compiler.Xml.PreXmlDoc, FSharp.Compiler.Syntax.SynValSigAccess, FSharp.Compiler.Syntax.SynExpr, FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnAutoPropertyTrivia) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewGetSetMember(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynBinding], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynBinding], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberGetSetTrivia) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitCtor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynAccess], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynAttributeList], FSharp.Compiler.Syntax.SynPat, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Xml.PreXmlDoc, FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnImplicitCtorTrivia) -FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitInherit(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Syntax.SynExpr, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range) +FSharp.Compiler.Syntax.SynMemberDefn+ImplicitInherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia get_trivia() +FSharp.Compiler.Syntax.SynMemberDefn+ImplicitInherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia trivia +FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitInherit(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Syntax.SynExpr, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia) FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia get_trivia() FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia trivia FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynType], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia) diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index e0ba696955a..5f4436a79f2 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -8150,7 +8150,9 @@ FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewAb FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewAutoProperty(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynAttributeList], Boolean, FSharp.Compiler.Syntax.Ident, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynType], FSharp.Compiler.Syntax.SynMemberKind, FSharp.Compiler.Syntax.SynMemberFlags, FSharp.Compiler.Syntax.SynMemberFlags, FSharp.Compiler.Xml.PreXmlDoc, FSharp.Compiler.Syntax.SynValSigAccess, FSharp.Compiler.Syntax.SynExpr, FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnAutoPropertyTrivia) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewGetSetMember(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynBinding], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynBinding], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberGetSetTrivia) FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitCtor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynAccess], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynAttributeList], FSharp.Compiler.Syntax.SynPat, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Xml.PreXmlDoc, FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnImplicitCtorTrivia) -FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitInherit(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Syntax.SynExpr, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range) +FSharp.Compiler.Syntax.SynMemberDefn+ImplicitInherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia get_trivia() +FSharp.Compiler.Syntax.SynMemberDefn+ImplicitInherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia trivia +FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewImplicitInherit(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Syntax.SynExpr, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia) FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia get_trivia() FSharp.Compiler.Syntax.SynMemberDefn+Inherit: FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia trivia FSharp.Compiler.Syntax.SynMemberDefn: FSharp.Compiler.Syntax.SynMemberDefn NewInherit(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.SynType], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynMemberDefnInheritTrivia) diff --git a/tests/service/data/SyntaxTree/Member/Inherit 02.fs.bsl b/tests/service/data/SyntaxTree/Member/Inherit 02.fs.bsl index 51185750c32..3a9482667e2 100644 --- a/tests/service/data/SyntaxTree/Member/Inherit 02.fs.bsl +++ b/tests/service/data/SyntaxTree/Member/Inherit 02.fs.bsl @@ -13,11 +13,11 @@ ImplFile (Unspecified, [ImplicitInherit (LongIdent (SynLongIdent ([T2], [], [None])), - Const (Unit, (4,14--4,16)), None, (4,4--4,16))], - (4,4--4,16)), [], None, (3,5--4,16), - { LeadingKeyword = Type (3,0--3,4) - EqualsRange = Some (3,8--3,9) - WithKeyword = None })], (3,0--4,16))], + Const (Unit, (4,14--4,16)), None, (4,4--4,16), + { InheritKeyword = (4,4--4,11) })], (4,4--4,16)), [], + None, (3,5--4,16), { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,8--3,9) + WithKeyword = None })], (3,0--4,16))], PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, (1,0--4,16), { LeadingKeyword = Module (1,0--1,6) })], (true, true), { ConditionalDirectives = [] From a7b13037cce774aa978920f1aaaafd45626d08ad Mon Sep 17 00:00:00 2001 From: Jakub Majocha <1760221+majocha@users.noreply.github.com> Date: Fri, 25 Oct 2024 16:46:45 +0200 Subject: [PATCH 21/22] potential OCE in graph processsing (#17921) Co-authored-by: Petr --- src/Compiler/Driver/GraphChecking/GraphProcessing.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Compiler/Driver/GraphChecking/GraphProcessing.fs b/src/Compiler/Driver/GraphChecking/GraphProcessing.fs index 218c9d6b2ac..33dd1c42c46 100644 --- a/src/Compiler/Driver/GraphChecking/GraphProcessing.fs +++ b/src/Compiler/Driver/GraphChecking/GraphProcessing.fs @@ -252,6 +252,7 @@ let processGraphAsync<'Item, 'Result when 'Item: equality and 'Item: comparison> let rec queueNode node = Async.Start( async { + use! _catch = Async.OnCancel(completionSignal.TrySetCanceled >> ignore) let! res = processNode node |> Async.Catch match res with From 686032982194a6dd916478d3092aa4c98194bcdc Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 17:54:41 -0700 Subject: [PATCH 22/22] Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20240912.2 (#17919) optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime From Version 1.0.0-prerelease.23614.4 -> To Version 1.0.0-prerelease.24462.2 Co-authored-by: dotnet-maestro[bot] Co-authored-by: Kevin Ransom (msft) --- eng/Version.Details.xml | 20 ++++++++++---------- eng/Versions.props | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 19118639aa2..ec75e2b3ec2 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -52,25 +52,25 @@ 91b9734abbad751d575c002b30778c88d978993c - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 15f6d606bfc7cbb65587dd7bc1ec6e9ef283f7e3 + 9d7532585ce71e30ab55f0364d3cecccaf0775d1 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 15f6d606bfc7cbb65587dd7bc1ec6e9ef283f7e3 + 9d7532585ce71e30ab55f0364d3cecccaf0775d1 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 15f6d606bfc7cbb65587dd7bc1ec6e9ef283f7e3 + 9d7532585ce71e30ab55f0364d3cecccaf0775d1 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 15f6d606bfc7cbb65587dd7bc1ec6e9ef283f7e3 + 9d7532585ce71e30ab55f0364d3cecccaf0775d1 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 15f6d606bfc7cbb65587dd7bc1ec6e9ef283f7e3 + 9d7532585ce71e30ab55f0364d3cecccaf0775d1 diff --git a/eng/Versions.props b/eng/Versions.props index 4252f548c66..658ed0f5d9e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -196,10 +196,10 @@ 2.2.0 - 1.0.0-prerelease.23614.4 - 1.0.0-prerelease.23614.4 - 1.0.0-prerelease.23614.4 - 1.0.0-prerelease.23614.4 - 1.0.0-prerelease.23614.4 + 1.0.0-prerelease.24462.2 + 1.0.0-prerelease.24462.2 + 1.0.0-prerelease.24462.2 + 1.0.0-prerelease.24462.2 + 1.0.0-prerelease.24462.2