From 7e08e7e508eafa6131f8369cffca04fbddb1b566 Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Mon, 24 Jun 2024 17:51:41 -0400 Subject: [PATCH 1/8] =?UTF-8?q?CustomOperations=20=E2=86=92=20ComputationE?= =?UTF-8?q?xpressions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{CustomOperations.fs => ComputationExpressions.fs} | 2 +- .../FSharp.Compiler.ComponentTests.fsproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/{CustomOperations.fs => ComputationExpressions.fs} (95%) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/CustomOperations.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs similarity index 95% rename from tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/CustomOperations.fs rename to tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs index 28e9ff22c7a..33bd36ce66f 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/CustomOperations.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs @@ -1,4 +1,4 @@ -namespace Conformance.Expressions.ComputationExpressions +namespace Conformance.Expressions.ComputationExpressions open Xunit open FSharp.Test.Compiler diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 419776657f5..c54a52ee7cf 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -79,8 +79,8 @@ - - + + From c1dea0fb9b7d58d52863128c98f68bf00051686a Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Wed, 26 Jun 2024 10:49:36 -0400 Subject: [PATCH 2/8] RFC FS-1144: Empty-bodied computation expressions --- .../Checking/CheckComputationExpressions.fs | 16 +- src/Compiler/Checking/CheckExpressions.fs | 27 +- src/Compiler/FSComp.txt | 2 + src/Compiler/Facilities/LanguageFeatures.fs | 3 + src/Compiler/Facilities/LanguageFeatures.fsi | 1 + src/Compiler/xlf/FSComp.txt.cs.xlf | 10 + src/Compiler/xlf/FSComp.txt.de.xlf | 10 + src/Compiler/xlf/FSComp.txt.es.xlf | 10 + src/Compiler/xlf/FSComp.txt.fr.xlf | 10 + src/Compiler/xlf/FSComp.txt.it.xlf | 10 + src/Compiler/xlf/FSComp.txt.ja.xlf | 10 + src/Compiler/xlf/FSComp.txt.ko.xlf | 10 + src/Compiler/xlf/FSComp.txt.pl.xlf | 10 + src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 10 + src/Compiler/xlf/FSComp.txt.ru.xlf | 10 + src/Compiler/xlf/FSComp.txt.tr.xlf | 10 + src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 10 + src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 10 + .../ComputationExpressions.fs | 267 +++++++++++++++--- 19 files changed, 403 insertions(+), 43 deletions(-) diff --git a/src/Compiler/Checking/CheckComputationExpressions.fs b/src/Compiler/Checking/CheckComputationExpressions.fs index fa56149ac7f..4fc0c8844ef 100644 --- a/src/Compiler/Checking/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/CheckComputationExpressions.fs @@ -1086,6 +1086,8 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol && hasMethInfo "Delay" && YieldFree cenv comp) + let origComp = comp + /// /// Try translate the syntax sugar /// @@ -1633,7 +1635,19 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol (not enableImplicitYield) && isNil (TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AtMostOneResult cenv env m ad "Zero" builderTy) then - error (Error(FSComp.SR.tcRequireBuilderMethod ("Zero"), m)) + match origComp with + // builder { } + // + // The compiler inserts a dummy () in CheckExpressions.fs for + // empty-bodied computation expressions. In this case, the user + // has not actually written any "control construct" in the body, + // and so we use a more specific error message for clarity. + | SynExpr.Const(SynConst.Unit, mUnit) when + g.langVersion.SupportsFeature LanguageFeature.EmptyBodiedComputationExpressions + && Range.equals mUnit range0 + -> + error (Error(FSComp.SR.tcEmptyBodyRequiresBuilderZeroMethod (), mWhole)) + | _ -> error (Error(FSComp.SR.tcRequireBuilderMethod ("Zero"), m)) Some(translatedCtxt (mkSynCall "Zero" m [])) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 89253bd6783..6bdf94ed9ff 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -8189,6 +8189,10 @@ and Propagate (cenv: cenv) (overallTy: OverallTy) (env: TcEnv) tpenv (expr: Appl // seq { ... } | SynExpr.ComputationExpr _ -> () + // async { } + // seq { } + | SynExpr.Record (None, None, [], _) when g.langVersion.SupportsFeature LanguageFeature.EmptyBodiedComputationExpressions -> () + // expr[idx] // expr[idx1, idx2] // expr[idx1..] @@ -8453,6 +8457,16 @@ and TcApplicationThen (cenv: cenv) (overallTy: OverallTy) env tpenv mExprAndArg let mArg = synArg.Range let mLeftExpr = leftExpr.Range + /// Treat an application of a value to an empty record expression + /// as a computation expression with a single unit expression. + /// Insert a (), i.e., such that builder { } ≡ builder { () }. + /// This transformation is only valid for language + /// versions that support this feature. + let (|EmptyFieldListAsUnit|_|) recordFields = + match recordFields with + | [] when g.langVersion.SupportsFeature LanguageFeature.EmptyBodiedComputationExpressions -> Some (EmptyFieldListAsUnit (SynExpr.Const (SynConst.Unit, range0))) + | _ -> None + // If the type of 'synArg' unifies as a function type, then this is a function application, otherwise // it is an error or a computation expression or indexer or delegate invoke match UnifyFunctionTypeUndoIfFailed cenv denv mLeftExpr exprTy with @@ -8474,11 +8488,15 @@ and TcApplicationThen (cenv: cenv) (overallTy: OverallTy) env tpenv mExprAndArg // though users don't realise that. let synArg = match synArg with - | SynExpr.ComputationExpr (false, comp, m) when + // seq { comp } + // seq { } + | SynExpr.ComputationExpr (false, comp, m) + | SynExpr.Record (None, None, EmptyFieldListAsUnit comp, m) when (match leftExpr with | ApplicableExpr(expr=Expr.Op(TOp.Coerce, _, [SeqExpr g], _)) -> true | _ -> false) -> SynExpr.ComputationExpr (true, comp, m) + | _ -> synArg let arg, tpenv = @@ -8519,8 +8537,11 @@ and TcApplicationThen (cenv: cenv) (overallTy: OverallTy) env tpenv mExprAndArg | _ -> None, delayed TcIndexingThen cenv env overallTy mExprAndArg m tpenv setInfo synLeftExprOpt leftExpr.Expr exprTy expandedIndexArgs indexArgs delayed - // Perhaps 'leftExpr' is a computation expression builder, and 'arg' is '{ ... }' - | SynExpr.ComputationExpr (false, comp, _m) -> + // Perhaps 'leftExpr' is a computation expression builder, and 'arg' is '{ ... }' or '{ }': + // leftExpr { comp } + // leftExpr { } + | SynExpr.ComputationExpr (false, comp, _m) + | SynExpr.Record (None, None, EmptyFieldListAsUnit comp, _m) -> let bodyOfCompExpr, tpenv = cenv.TcComputationExpression cenv env overallTy tpenv (mLeftExpr, leftExpr.Expr, exprTy, comp) TcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv bodyOfCompExpr) (tyOfExpr g bodyOfCompExpr) ExprAtomicFlag.NonAtomic delayed diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index f74fc3da3e3..55484591abc 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -561,6 +561,7 @@ tcCouldNotFindIDisposable,"Couldn't find Dispose on IDisposable, or it was overl 706,tcInvalidUnitsOfMeasurePrefix,"Units-of-measure cannot be used as prefix arguments to a type. Rewrite as postfix arguments in angle brackets." 707,tcUnitsOfMeasureInvalidInTypeConstructor,"Unit-of-measure cannot be used in type constructor application" 708,tcRequireBuilderMethod,"This control construct may only be used if the computation expression builder defines a '%s' method" +708,tcEmptyBodyRequiresBuilderZeroMethod,"An empty body may only be used if the computation expression builder defines a 'Zero' method." 709,tcTypeHasNoNestedTypes,"This type has no nested types" 711,tcUnexpectedSymbolInTypeExpression,"Unexpected %s in type expression" 712,tcTypeParameterInvalidAsTypeConstructor,"Type parameter cannot be used as type constructor" @@ -1755,3 +1756,4 @@ featureReuseSameFieldsInStructUnions,"Share underlying fields in a [] di featureParsedHashDirectiveArgumentNonString,"# directives with non-quoted string arguments" 3869,featureParsedHashDirectiveUnexpectedInteger,"Unexpected integer literal '%d'." 3869,featureParsedHashDirectiveUnexpectedIdentifier,"Unexpected identifier '%s'." +featureEmptyBodiedComputationExpressions,"Support for computation expressions with empty bodies: builder {{ }}" diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index c8378c1042f..f6baf0dcf3b 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -90,6 +90,7 @@ type LanguageFeature = | LowerIntegralRangesToFastLoops | LowerSimpleMappingsInComprehensionsToDirectCallsToMap | ParsedHashDirectiveArgumentNonQuotes + | EmptyBodiedComputationExpressions /// LanguageVersion management type LanguageVersion(versionText) = @@ -207,6 +208,7 @@ type LanguageVersion(versionText) = LanguageFeature.LowerIntegralRangesToFastLoops, previewVersion LanguageFeature.LowerSimpleMappingsInComprehensionsToDirectCallsToMap, previewVersion LanguageFeature.ParsedHashDirectiveArgumentNonQuotes, previewVersion + LanguageFeature.EmptyBodiedComputationExpressions, previewVersion ] static let defaultLanguageVersion = LanguageVersion("default") @@ -356,6 +358,7 @@ type LanguageVersion(versionText) = | LanguageFeature.LowerSimpleMappingsInComprehensionsToDirectCallsToMap -> FSComp.SR.featureLowerSimpleMappingsInComprehensionsToDirectCallsToMap () | LanguageFeature.ParsedHashDirectiveArgumentNonQuotes -> FSComp.SR.featureParsedHashDirectiveArgumentNonString () + | LanguageFeature.EmptyBodiedComputationExpressions -> FSComp.SR.featureEmptyBodiedComputationExpressions () /// 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 354d657bc40..ff60b7442f7 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -81,6 +81,7 @@ type LanguageFeature = | LowerIntegralRangesToFastLoops | LowerSimpleMappingsInComprehensionsToDirectCallsToMap | ParsedHashDirectiveArgumentNonQuotes + | EmptyBodiedComputationExpressions /// LanguageVersion management type LanguageVersion = diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index e8b29f9dd54..199d58ba6f8 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -302,6 +302,11 @@ literál float32 bez tečky + + Support for computation expressions with empty bodies: builder {{ }} + Support for computation expressions with empty bodies: builder {{ }} + + Enforce AttributeTargets Vynutit AttributeTargets @@ -1247,6 +1252,11 @@ Zkrácená syntaxe lambda je podporována pouze pro atomické výrazy, jako je metoda, vlastnost, pole nebo indexer v implicitní argumentu _. Příklad: let f = _. Length'. + + An empty body may only be used if the computation expression builder defines a 'Zero' method. + An empty body may only be used if the computation expression builder defines a 'Zero' method. + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Syntaxe expr1[expr2] se používá pro indexování. Pokud chcete povolit indexování, zvažte možnost přidat anotaci typu, nebo pokud voláte funkci, přidejte mezeru, třeba expr1 [expr2]. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 26932a4dc81..34ee51909be 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -302,6 +302,11 @@ punktloses float32-Literal + + Support for computation expressions with empty bodies: builder {{ }} + Support for computation expressions with empty bodies: builder {{ }} + + Enforce AttributeTargets AttributeTargets erzwingen @@ -1247,6 +1252,11 @@ Die Lambdasyntax der Kurzform wird nur für atomische Ausdrücke wie Methode, Eigenschaft, Feld oder Indexer für das implizite Argument "_" unterstützt. Beispiel: "let f = _. Länge". + + An empty body may only be used if the computation expression builder defines a 'Zero' method. + An empty body may only be used if the computation expression builder defines a 'Zero' method. + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Die Syntax "expr1[expr2]" wird für die Indizierung verwendet. Fügen Sie ggf. eine Typanmerkung hinzu, um die Indizierung zu aktivieren, oder fügen Sie beim Aufrufen einer Funktion ein Leerzeichen hinzu, z. B. "expr1 [expr2]". diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 5ae9f079d23..97cedff5dc4 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -302,6 +302,11 @@ literal float32 sin punto + + Support for computation expressions with empty bodies: builder {{ }} + Support for computation expressions with empty bodies: builder {{ }} + + Enforce AttributeTargets Aplicar AttributeTargets @@ -1247,6 +1252,11 @@ La sintaxis lambda abreviada solo se admite para expresiones atómicas, como el método, la propiedad, el campo o el indexador en el argumento '_' implícito. Por ejemplo: 'let f = _.Length'. + + An empty body may only be used if the computation expression builder defines a 'Zero' method. + An empty body may only be used if the computation expression builder defines a 'Zero' method. + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. La sintaxis "expr1[expr2]" se usa para la indexación. Considere la posibilidad de agregar una anotación de tipo para habilitar la indexación, si se llama a una función, agregue un espacio, por ejemplo, "expr1 [expr2]". diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index a8ae73b3c65..8336143887c 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -302,6 +302,11 @@ littéral float32 sans point + + Support for computation expressions with empty bodies: builder {{ }} + Support for computation expressions with empty bodies: builder {{ }} + + Enforce AttributeTargets Appliquer AttributeTargets @@ -1247,6 +1252,11 @@ La syntaxe lambda raccourcie est prise en charge uniquement pour les expressions atomiques, telles que la méthode, la propriété, le champ ou l’indexeur sur l’argument ’_’ implicite. Par exemple : « let f = _. Longueur ». + + An empty body may only be used if the computation expression builder defines a 'Zero' method. + An empty body may only be used if the computation expression builder defines a 'Zero' method. + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. La syntaxe « expr1[expr2] » est utilisée pour l’indexation. Envisagez d’ajouter une annotation de type pour activer l’indexation, ou si vous appelez une fonction, ajoutez un espace, par exemple « expr1 [expr2] ». diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 8bfde9a01b8..eb2aaec5305 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -302,6 +302,11 @@ valore letterale float32 senza punti + + Support for computation expressions with empty bodies: builder {{ }} + Support for computation expressions with empty bodies: builder {{ }} + + Enforce AttributeTargets Imponi destinazioni attributo @@ -1247,6 +1252,11 @@ La sintassi lambda a sintassi abbreviata è supportata solo per le espressioni atomiche, ad esempio metodo, proprietà, campo o indicizzatore nell'argomento '_' implicito. Ad esempio: 'let f = _. Lunghezza'. + + An empty body may only be used if the computation expression builder defines a 'Zero' method. + An empty body may only be used if the computation expression builder defines a 'Zero' method. + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. La sintassi 'expr1[expr2]' viene usata per l'indicizzazione. Provare ad aggiungere un'annotazione di tipo per abilitare l'indicizzazione oppure se la chiamata a una funzione aggiunge uno spazio, ad esempio 'expr1 [expr2]'. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 3c1f9932d0c..fef3e7db33d 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -302,6 +302,11 @@ ドットなしの float32 リテラル + + Support for computation expressions with empty bodies: builder {{ }} + Support for computation expressions with empty bodies: builder {{ }} + + Enforce AttributeTargets AttributeTargets を適用する @@ -1247,6 +1252,11 @@ 短縮ラムダ構文は、暗黙的な '_' 引数のメソッド、プロパティ、フィールド、インデクサーなどのアトミック式でのみサポートされています。例: 'let f = _.Length'。 + + An empty body may only be used if the computation expression builder defines a 'Zero' method. + An empty body may only be used if the computation expression builder defines a 'Zero' method. + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. 構文 'expr1[expr2]' はインデックス作成に使用されます。インデックスを有効にするために型の注釈を追加するか、関数を呼び出す場合には、'expr1 [expr2]' のようにスペースを入れます。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index a960ad4399f..dc1d8334e95 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -302,6 +302,11 @@ 점이 없는 float32 리터럴 + + Support for computation expressions with empty bodies: builder {{ }} + Support for computation expressions with empty bodies: builder {{ }} + + Enforce AttributeTargets AttributeTargets 적용 @@ -1247,6 +1252,11 @@ 줄임 람다 구문은 암시적 '_' 인수의 메서드, 속성, 필드 또는 인덱서와 같은 원자성 식에 대해서만 지원됩니다. 예: 'let f = _.Length'. + + An empty body may only be used if the computation expression builder defines a 'Zero' method. + An empty body may only be used if the computation expression builder defines a 'Zero' method. + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. 인덱싱에는 'expr1[expr2]' 구문이 사용됩니다. 인덱싱을 사용하도록 설정하기 위해 형식 주석을 추가하는 것을 고려하거나 함수를 호출하는 경우 공백을 추가하세요(예: 'expr1 [expr2]'). diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index bd2facc3cba..d7a6d1ba814 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -302,6 +302,11 @@ bezkropkowy literał float32 + + Support for computation expressions with empty bodies: builder {{ }} + Support for computation expressions with empty bodies: builder {{ }} + + Enforce AttributeTargets Wymuszaj elementy AttributeTargets @@ -1247,6 +1252,11 @@ Składnia lambda skrótu jest obsługiwana tylko w przypadku wyrażeń niepodzielnych, takich jak metoda, właściwość, pole lub indeksator w dorozumianym argumencie „_”. Na przykład: „let f = _. Length”. + + An empty body may only be used if the computation expression builder defines a 'Zero' method. + An empty body may only be used if the computation expression builder defines a 'Zero' method. + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Do indeksowania używana jest składnia „expr1[expr2]”. Rozważ dodanie adnotacji typu, aby umożliwić indeksowanie, lub jeśli wywołujesz funkcję dodaj spację, np. „expr1 [expr2]”. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 59138d83890..57c562c050a 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -302,6 +302,11 @@ literal float32 sem ponto + + Support for computation expressions with empty bodies: builder {{ }} + Support for computation expressions with empty bodies: builder {{ }} + + Enforce AttributeTargets Impor AttributeTargets @@ -1247,6 +1252,11 @@ A sintaxe lambda abreviada só tem suporte para expressões atômicas, como método, propriedade, campo ou indexador no argumento '_' implícito. Por exemplo: 'let f = _. Comprimento'. + + An empty body may only be used if the computation expression builder defines a 'Zero' method. + An empty body may only be used if the computation expression builder defines a 'Zero' method. + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. A sintaxe 'expr1[expr2]' é usada para indexação. Considere adicionar uma anotação de tipo para habilitar a indexação ou, se chamar uma função, adicione um espaço, por exemplo, 'expr1 [expr2]'. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 58c625f0746..2dcc335b628 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -302,6 +302,11 @@ литерал float32 без точки + + Support for computation expressions with empty bodies: builder {{ }} + Support for computation expressions with empty bodies: builder {{ }} + + Enforce AttributeTargets Принудительно применить AttributeTargets @@ -1247,6 +1252,11 @@ Сокращенный синтаксис лямбда-выражений поддерживается только для атомарных выражений, таких как метод, свойство, поле или индексатор подразумеваемого аргумента «_». Например: 'let f = _.Length'. + + An empty body may only be used if the computation expression builder defines a 'Zero' method. + An empty body may only be used if the computation expression builder defines a 'Zero' method. + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Для индексирования используется синтаксис "expr1[expr2]". Рассмотрите возможность добавления аннотации типа для включения индексации или при вызове функции добавьте пробел, например "expr1 [expr2]". diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index cfe703430c0..1ba13ab3ede 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -302,6 +302,11 @@ noktasız float32 sabit değeri + + Support for computation expressions with empty bodies: builder {{ }} + Support for computation expressions with empty bodies: builder {{ }} + + Enforce AttributeTargets AttributeTargets'ı zorla @@ -1247,6 +1252,11 @@ Toplu lambda söz dizimi yalnızca örtülü '_' bağımsız değişkeninde yöntem, özellik, alan veya dizin oluşturucu gibi atomik ifadeler için destekleniyor. Örnek: 'let f = _.Length'. + + An empty body may only be used if the computation expression builder defines a 'Zero' method. + An empty body may only be used if the computation expression builder defines a 'Zero' method. + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. Söz dizimi “expr1[expr2]” dizin oluşturma için kullanılıyor. Dizin oluşturmayı etkinleştirmek için bir tür ek açıklama eklemeyi düşünün veya bir işlev çağırıyorsanız bir boşluk ekleyin, örn. “expr1 [expr2]”. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index d707003f18f..b3a3fa421c5 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -302,6 +302,11 @@ 无点 float32 文本 + + Support for computation expressions with empty bodies: builder {{ }} + Support for computation expressions with empty bodies: builder {{ }} + + Enforce AttributeTargets 强制使用 AttributeTargets @@ -1247,6 +1252,11 @@ 仅原子表达式支持速记 lambda 语法,例如隐含的“_”参数上的方法、属性、字段或索引器。例如:“let f = _.Length”。 + + An empty body may only be used if the computation expression builder defines a 'Zero' method. + An empty body may only be used if the computation expression builder defines a 'Zero' method. + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. 语法“expr1[expr2]”用于索引。考虑添加类型批注来启用索引,或者在调用函数添加空格,例如“expr1 [expr2]”。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 5cc67b951b6..1beb02fecd5 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -302,6 +302,11 @@ 無點號的 float32 常值 + + Support for computation expressions with empty bodies: builder {{ }} + Support for computation expressions with empty bodies: builder {{ }} + + Enforce AttributeTargets 強制使用 AttributeTargets @@ -1247,6 +1252,11 @@ 只有不可部分完成運算式才支援速記 Lambda 語法,例如隱含 '_' 引數上的方法、屬性、欄位或索引子。例如: 'let f = _.Length'。 + + An empty body may only be used if the computation expression builder defines a 'Zero' method. + An empty body may only be used if the computation expression builder defines a 'Zero' method. + + The syntax 'expr1[expr2]' is used for indexing. Consider adding a type annotation to enable indexing, or if calling a function add a space, e.g. 'expr1 [expr2]'. 語法 'expr1[expr2]' 已用於編製索引。請考慮新增類型註釋來啟用編製索引,或是呼叫函式並新增空格,例如 'expr1 [expr2]'。 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs index 33bd36ce66f..6dac5a398d2 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs @@ -1,43 +1,232 @@ -namespace Conformance.Expressions.ComputationExpressions +module Conformance.Expressions.ComputationExpressions open Xunit open FSharp.Test.Compiler -module CustomOperations = - - [] - let ``[] without explicit name is allowed, uses method name as operation name`` () = - FSharp """ - module CustomOperationTest - type CBuilder() = - [] - member this.Foo _ = "Foo" - [] - member this.foo _ = "foo" - [] - member this.bar _ = "bar" - member this.Yield _ = () - member this.Zero _ = () - - - [] - let main _ = - let cb = CBuilder() - - let x = cb { Foo } - let y = cb { foo } - let z = cb { bar } - printfn $"{x}" - printfn $"{y}" - - if x <> "Foo" then - failwith "not Foo" - if y <> "foo" then - failwith "not foo" - if z <> "bar" then - failwith "not bar" - 0 - """ - |> asExe - |> compileAndRun - |> shouldSucceed \ No newline at end of file +[] +let ``[] without explicit name is allowed, uses method name as operation name`` () = + FSharp """ + module CustomOperationTest + type CBuilder() = + [] + member this.Foo _ = "Foo" + [] + member this.foo _ = "foo" + [] + member this.bar _ = "bar" + member this.Yield _ = () + member this.Zero _ = () + + + [] + let main _ = + let cb = CBuilder() + + let x = cb { Foo } + let y = cb { foo } + let z = cb { bar } + printfn $"{x}" + printfn $"{y}" + + if x <> "Foo" then + failwith "not Foo" + if y <> "foo" then + failwith "not foo" + if z <> "bar" then + failwith "not bar" + 0 + """ + |> asExe + |> compileAndRun + |> shouldSucceed + +/// Tests for empty-bodied computation expressions: builder { } +module EmptyBodied = + /// F# 8.0 and below do not support empty-bodied computation expressions. + module Unsupported = + [] + let ``seq { } does not compile`` () = + Fsx """ + let xs : int seq = seq { } + """ + |> withLangVersion80 + |> asExe + |> compile + |> shouldFail + |> withErrorCode 789 + |> withErrorMessage "'{ }' is not a valid expression. Records must include at least one field. Empty sequences are specified by using Seq.empty or an empty list '[]'." + + [] + let ``async { } does not compile`` () = + Fsx """ + let a : Async = async { } + """ + |> withLangVersion80 + |> asExe + |> compile + |> shouldFail + |> withErrorCode 3 + |> withErrorMessage "This value is not a function and cannot be applied." + + [] + let ``builder { } does not compile`` () = + FSharp """ + type Builder () = + member _.Zero () = Seq.empty + member _.Delay f = f + member _.Run f = f () + + let builder = Builder () + + let xs : int seq = builder { } + """ + |> withLangVersion80 + |> asExe + |> compile + |> shouldFail + |> withErrorCode 3 + |> withErrorMessage "This value is not a function and cannot be applied." + + [] + let ``builder { () } and no Zero: FS0708`` () = + FSharp """ + type Builder () = + member _.Delay f = f + member _.Run f = f () + + let builder = Builder () + + let xs : int seq = builder { () } + """ + |> withLangVersion80 + |> asExe + |> compile + |> shouldFail + |> withErrorCode 708 + |> withErrorMessage "This control construct may only be used if the computation expression builder defines a 'Zero' method" + + [] + let ``builder { () } ≡ seq { () } when Zero () = Seq.empty`` () = + Fsx """ + type Builder () = + member _.Zero () = Seq.empty + member _.Delay f = f + member _.Run f = f () + + let builder = Builder () + + if List.ofSeq (builder { () }) <> List.ofSeq (seq { () }) then + failwith "builder { () } ≢ seq { () }" + """ + |> withLangVersion80 + |> runFsi + |> shouldSucceed + + [] + let ``Unchecked﹒defaultof<'a> { }`` () = + FSharp """ + Unchecked.defaultof<'a> { } + """ + |> withLangVersion80 + |> asExe + |> compile + |> shouldFail + |> withErrorCode 789 + |> withErrorMessage "'{ }' is not a valid expression. Records must include at least one field. Empty sequences are specified by using Seq.empty or an empty list '[]'." + + /// F# 9.0 and above support empty-bodied computation expressions. + module Supported = + /// The language version that supports empty-bodied computation expressions. + /// TODO: Update this to the appropriate version when the feature comes out of preview. + let [] SupportedLanguageVersion = "preview" + + [] + let ``seq { } ≡ seq { () }`` () = + Fsx """ + if List.ofSeq (seq { }) <> List.ofSeq (seq { () }) then + failwith "seq { } ≢ seq { () }" + """ + |> withLangVersion SupportedLanguageVersion + |> runFsi + |> shouldSucceed + + [] + let ``async { } ≡ async { () }`` () = + Fsx """ + if + [|(); ()|] <> ( + [|async { }; async { () }|] + |> Async.Parallel + |> Async.RunSynchronously + ) + then + failwith "async { } ≢ async { () }" + """ + |> withLangVersion SupportedLanguageVersion + |> runFsi + |> shouldSucceed + + [] + let ``builder { () } and no Zero: FS0708`` () = + FSharp """ + type Builder () = + member _.Delay f = f + member _.Run f = f () + + let builder = Builder () + + let xs : int seq = builder { () } + """ + |> withLangVersion SupportedLanguageVersion + |> asExe + |> compile + |> shouldFail + |> withErrorCode 708 + |> withErrorMessage "This control construct may only be used if the computation expression builder defines a 'Zero' method" + + [] + let ``builder { } and no Zero: FS0708 and new message`` () = + FSharp """ + type Builder () = + member _.Delay f = f + member _.Run f = f () + + let builder = Builder () + + let xs : int seq = builder { } + """ + |> withLangVersion SupportedLanguageVersion + |> asExe + |> compile + |> shouldFail + |> withErrorCode 708 + |> withErrorMessage "An empty body may only be used if the computation expression builder defines a 'Zero' method." + + [] + let ``builder { } ≡ seq { } when Zero () = Seq.empty`` () = + Fsx """ + type Builder () = + member _.Zero () = Seq.empty + member _.Delay f = f + member _.Run f = f () + + let builder = Builder () + + if List.ofSeq (builder { }) <> List.ofSeq (seq { }) then + failwith "builder { } ≢ seq { }" + """ + |> withLangVersion SupportedLanguageVersion + |> runFsi + |> shouldSucceed + + [] + let ``Unchecked﹒defaultof<'a> { }`` () = + FSharp """ + Unchecked.defaultof<'a> { } + """ + |> withLangVersion SupportedLanguageVersion + |> asExe + |> compile + |> shouldFail + |> withErrorCode 789 + |> withErrorMessage "'{ }' is not a valid expression. Records must include at least one field. Empty sequences are specified by using Seq.empty or an empty list '[]'." From 946e91cfa78e69658a95d8e8421ef47a7033ce9c Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Wed, 26 Jun 2024 12:20:02 -0400 Subject: [PATCH 3/8] Dedent --- .../FSharp.Compiler.ComponentTests.fsproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index c54a52ee7cf..aa343573791 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -80,7 +80,7 @@ - + From 1da0c60159fef7a267df4cf04c18e6318bdc0c65 Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Wed, 26 Jun 2024 12:28:45 -0400 Subject: [PATCH 4/8] Update release notes --- docs/release-notes/.FSharp.Compiler.Service/8.0.400.md | 1 + docs/release-notes/.Language/preview.md | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md index 0f491fc6808..c17dfef67f8 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md @@ -26,6 +26,7 @@ * Allow ParsedHashDirectives to have argument types other than strings ([Issue #17240](https://github.com/dotnet/fsharp/issues/16447), [PR #17209](https://github.com/dotnet/fsharp/pull/17209)) * Parser: better recovery for unfinished patterns ([PR #17231](https://github.com/dotnet/fsharp/pull/17231)) * Parser: recover on empty match clause ([PR #17233](https://github.com/dotnet/fsharp/pull/17233)) +* Support empty-bodied computation expressions. ([Language suggestion #1232](https://github.com/fsharp/fslang-suggestions/issues/1232), [PR #17352](https://github.com/dotnet/fsharp/pull/17352)) ### Changed * Enforce `AttributeTargets.Interface` ([PR #17173](https://github.com/dotnet/fsharp/pull/17173)) diff --git a/docs/release-notes/.Language/preview.md b/docs/release-notes/.Language/preview.md index 49f990c8c3d..7b25b17a179 100644 --- a/docs/release-notes/.Language/preview.md +++ b/docs/release-notes/.Language/preview.md @@ -8,6 +8,7 @@ * Allow returning bool instead of unit option for partial active patterns. ([Language suggestion #1041](https://github.com/fsharp/fslang-suggestions/issues/1041), [PR #16473](https://github.com/dotnet/fsharp/pull/16473)) * Allow #nowarn to support the FS prefix on error codes to disable warnings ([Issue #17206](https://github.com/dotnet/fsharp/issues/16447), [PR #17209](https://github.com/dotnet/fsharp/pull/17209)) * Allow ParsedHashDirectives to have argument types other than strings ([Issue #17240](https://github.com/dotnet/fsharp/issues/16447), [PR #17209](https://github.com/dotnet/fsharp/pull/17209)) +* Support empty-bodied computation expressions. ([Language suggestion #1232](https://github.com/fsharp/fslang-suggestions/issues/1232), [PR #17352](https://github.com/dotnet/fsharp/pull/17352)) ### Fixed From ac8e74b7a5329c822418e45e528b24b8c839282d Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Wed, 26 Jun 2024 15:00:02 -0400 Subject: [PATCH 5/8] Add tests for resumable state machine CEs (`task`) --- .../ComputationExpressions.fs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs index 6dac5a398d2..fe9e2e3d482 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs @@ -68,6 +68,20 @@ module EmptyBodied = |> withErrorCode 3 |> withErrorMessage "This value is not a function and cannot be applied." + [] + let ``task { } does not compile`` () = + Fsx """ + open System.Threading.Tasks + + let t : Task = task { } + """ + |> withLangVersion80 + |> asExe + |> compile + |> shouldFail + |> withErrorCode 3 + |> withErrorMessage "This value is not a function and cannot be applied." + [] let ``builder { } does not compile`` () = FSharp """ @@ -140,6 +154,12 @@ module EmptyBodied = /// TODO: Update this to the appropriate version when the feature comes out of preview. let [] SupportedLanguageVersion = "preview" + /// warning FS3511: This state machine is not statically compilable. + /// A resumable code invocation at '(,--,)' could not be reduced. + /// An alternative dynamic implementation will be used, which may be slower. + /// Consider adjusting your code to ensure this state machine is statically compilable, or else suppress this warning. + let [] FS3511 = 3511 + [] let ``seq { } ≡ seq { () }`` () = Fsx """ @@ -166,6 +186,37 @@ module EmptyBodied = |> runFsi |> shouldSucceed + [] + let ``task { } ≡ task { () }`` () = + let src = + Fsx """ +open System.Threading.Tasks + +if + [|(); ()|] <> (Task.WhenAll (task { }, task { () })).GetAwaiter().GetResult() +then + failwith "task { } ≢ task { () }" + """ + + do + src + |> withLangVersion SupportedLanguageVersion + |> runFsi + |> shouldFail + |> withStdErrContainsAllInOrder [ + "This state machine is not statically compilable. A resumable code invocation at '(5,33--5,37)' could not be reduced. An alternative dynamic implementation will be used, which may be slower. Consider adjusting your code to ensure this state machine is statically compilable, or else suppress this warning." + "This state machine is not statically compilable. A resumable code invocation at '(5,43--5,47)' could not be reduced. An alternative dynamic implementation will be used, which may be slower. Consider adjusting your code to ensure this state machine is statically compilable, or else suppress this warning." + ] + |> ignore + + do + src + |> withLangVersion SupportedLanguageVersion + |> withNoWarn FS3511 + |> runFsi + |> shouldSucceed + |> ignore + [] let ``builder { () } and no Zero: FS0708`` () = FSharp """ From ebae6c83b45ad83ab165a4edfb99e6a61ed41d86 Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Thu, 27 Jun 2024 09:16:18 -0400 Subject: [PATCH 6/8] Adjust `task` test for clarity * The warning caused by https://github.com/dotnet/fsharp/issues/12038 distracted from the test's intent. Wrapping the code in a function removes the warning. --- .../ComputationExpressions.fs | 40 ++++++------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs index fe9e2e3d482..c5e398c953b 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs @@ -154,12 +154,6 @@ module EmptyBodied = /// TODO: Update this to the appropriate version when the feature comes out of preview. let [] SupportedLanguageVersion = "preview" - /// warning FS3511: This state machine is not statically compilable. - /// A resumable code invocation at '(,--,)' could not be reduced. - /// An alternative dynamic implementation will be used, which may be slower. - /// Consider adjusting your code to ensure this state machine is statically compilable, or else suppress this warning. - let [] FS3511 = 3511 - [] let ``seq { } ≡ seq { () }`` () = Fsx """ @@ -192,30 +186,20 @@ module EmptyBodied = Fsx """ open System.Threading.Tasks -if - [|(); ()|] <> (Task.WhenAll (task { }, task { () })).GetAwaiter().GetResult() -then - failwith "task { } ≢ task { () }" +// We wrap this in a function to avoid https://github.com/dotnet/fsharp/issues/12038 +let f () = + if + [|(); ()|] <> Task.WhenAll(task { }, task { () }).GetAwaiter().GetResult() + then + failwith "task { } ≢ task { () }" + +f () """ - do - src - |> withLangVersion SupportedLanguageVersion - |> runFsi - |> shouldFail - |> withStdErrContainsAllInOrder [ - "This state machine is not statically compilable. A resumable code invocation at '(5,33--5,37)' could not be reduced. An alternative dynamic implementation will be used, which may be slower. Consider adjusting your code to ensure this state machine is statically compilable, or else suppress this warning." - "This state machine is not statically compilable. A resumable code invocation at '(5,43--5,47)' could not be reduced. An alternative dynamic implementation will be used, which may be slower. Consider adjusting your code to ensure this state machine is statically compilable, or else suppress this warning." - ] - |> ignore - - do - src - |> withLangVersion SupportedLanguageVersion - |> withNoWarn FS3511 - |> runFsi - |> shouldSucceed - |> ignore + src + |> withLangVersion SupportedLanguageVersion + |> runFsi + |> shouldSucceed [] let ``builder { () } and no Zero: FS0708`` () = From d238a3e1119b32d8cfdf3de16737f861918efaf6 Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Thu, 27 Jun 2024 09:23:13 -0400 Subject: [PATCH 7/8] No longer need dedenting --- .../ComputationExpressions.fs | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs index c5e398c953b..2738c701134 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs @@ -182,21 +182,18 @@ module EmptyBodied = [] let ``task { } ≡ task { () }`` () = - let src = - Fsx """ -open System.Threading.Tasks - -// We wrap this in a function to avoid https://github.com/dotnet/fsharp/issues/12038 -let f () = - if - [|(); ()|] <> Task.WhenAll(task { }, task { () }).GetAwaiter().GetResult() - then - failwith "task { } ≢ task { () }" + Fsx """ + open System.Threading.Tasks -f () - """ + // We wrap this in a function to avoid https://github.com/dotnet/fsharp/issues/12038 + let f () = + if + [|(); ()|] <> Task.WhenAll(task { }, task { () }).GetAwaiter().GetResult() + then + failwith "task { } ≢ task { () }" - src + f () + """ |> withLangVersion SupportedLanguageVersion |> runFsi |> shouldSucceed From acb630271004a52825f4dd17d509c5d42563183f Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Fri, 28 Jun 2024 17:28:21 -0400 Subject: [PATCH 8/8] Link RFC PR --- docs/release-notes/.FSharp.Compiler.Service/8.0.400.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md index 4ef0f9ba9d6..2687dc328e9 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md @@ -27,7 +27,7 @@ * Parser: better recovery for unfinished patterns ([PR #17231](https://github.com/dotnet/fsharp/pull/17231)) * Expose inner exception information of TypeProviders to help diagnostics in IDE ([PR #17251](https://github.com/dotnet/fsharp/pull/17251)) * Parser: recover on empty match clause ([PR #17233](https://github.com/dotnet/fsharp/pull/17233)) -* Support empty-bodied computation expressions. ([Language suggestion #1232](https://github.com/fsharp/fslang-suggestions/issues/1232), [PR #17352](https://github.com/dotnet/fsharp/pull/17352)) +* Support empty-bodied computation expressions. ([Language suggestion #1232](https://github.com/fsharp/fslang-suggestions/issues/1232), [RFC FS-1144 (PR #774)](https://github.com/fsharp/fslang-design/pull/774), [PR #17352](https://github.com/dotnet/fsharp/pull/17352)) ### Changed * Enforce `AttributeTargets.Interface` ([PR #17173](https://github.com/dotnet/fsharp/pull/17173))