From 4f262997272d74eadb3e2d307d0021e5208f1bfe Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 8 Sep 2026 11:41:40 +0200 Subject: [PATCH 1/9] Reject NativePtr.stackalloc inside a try handler/finally (FS3916) NativePtr.stackalloc emits the 'localloc' IL instruction, which the JIT rejects inside an exception-handling region, causing InvalidProgramException at method load. Detect this during PostInferenceChecks and emit compile-time error FS3916 when stackalloc is applied inside a 'with' handler or 'finally' block. A withinHandler env flag is set on the handler/finally bodies and reset at closure and method boundaries so stackalloc in a lambda or object-expression method defined in a handler stays legal. Part of issue #20295 (Case 1). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../.FSharp.Compiler.Service/11.0.100.md | 1 + src/Compiler/Checking/PostInferenceChecks.fs | 17 +++- src/Compiler/FSComp.txt | 1 + src/Compiler/TypedTree/TcGlobals.fs | 2 + src/Compiler/TypedTree/TcGlobals.fsi | 2 + 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 ++ .../Libraries/NativeInterop.fs | 82 +++++++++++++++++++ 19 files changed, 167 insertions(+), 3 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index ed1e382d6c7..4e20ee59fe9 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -1,5 +1,6 @@ ### Fixed +* Fix `NativePtr.stackalloc` used inside the `with` handler, filter or `finally` block of a `try` expression producing an assembly that throws `InvalidProgramException` at method load. The `localloc` IL instruction it emits is rejected by the runtime inside an exception-handling region, so this is now reported at compile time as error FS3916. ([Issue #20295](https://github.com/dotnet/fsharp/issues/20295)) * Fix `NativePtr.stackalloc` nested in a larger expression (e.g. a call argument or the right of an assignment) producing an assembly that throws `InvalidProgramException` at load. ([Issue #8083](https://github.com/dotnet/fsharp/issues/8083), [PR #20302](https://github.com/dotnet/fsharp/pull/20302)) * Fix internal error "Unexpected generalized type variables when compiling an active pattern" when an active pattern is used in a `let` binding whose right-hand side is a generic value, e.g. `let (T) = id`. Such a binding is now checked like the equivalent `match` and is not generalized. ([Issue #16856](https://github.com/dotnet/fsharp/issues/16856), [PR #20383](https://github.com/dotnet/fsharp/pull/20383)) * Fix Release-only (`--optimize+`) `System.InvalidProgramException` from `Seq.collect` / `yield!` over a value-type (struct) collection implementing `seq<'T>` (e.g. `ImmutableArray<_>`) when materialised with `List.ofSeq` / `Seq.toList` / `Seq.toArray` or a list/array comprehension. The collector lowering now boxes a struct sub-collection to `seq<'T>` before calling `AddMany`/`AddManyAndClose` (matching the coercion the type checker already inserts for `yield!`), and uses `unit` as the try/finally result type instead of the body type (removing a spurious `ldnull` store). ([Issue #20203](https://github.com/dotnet/fsharp/issues/20203)) diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index 1d5798320b4..80f41d00dc4 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -100,6 +100,9 @@ type env = /// Are we expecting a resumable code block etc resumableCode: Resumable + + /// Are we inside the 'with' handler, filter, or 'finally' block of a 'try'? + withinHandler: bool } override _.ToString() = "" @@ -1248,6 +1251,11 @@ and CheckExpr (cenv: cenv) (env: env) origExpr (ctxt: PermitByRefExpr) : Limit = // Check an application | Expr.App (f, _fty, tyargs, argsl, m) -> + (match f with + | OptionalCoerce(Expr.Val (vref, _, _)) + when env.withinHandler && cenv.reportErrors && valRefEq g vref g.nativeptr_stackalloc_vref -> + errorR(Error(FSComp.SR.chkNativePtrStackallocInHandler(), m)) + | _ -> ()) CheckApplication cenv env expr (f, tyargs, argsl, m) ctxt | Expr.Lambda (_, _, _, argvs, _, m, bodyTy) -> @@ -1473,6 +1481,7 @@ and CheckMethod cenv env baseValOpt ty (TObjExprMethod(_, attribs, tps, vs, body { env with resumableCode = Resumable.ResumableExpr false } else { env with resumableCode = Resumable.None } + let env = { env with withinHandler = false } CheckAttribs cenv env attribs CheckNoReraise cenv None body CheckEscapes cenv true m (match baseValOpt with Some x -> x :: vs | None -> vs) body |> ignore @@ -1514,7 +1523,7 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = | TOp.TryFinally _, [_], [Expr.Lambda (_, _, _, [_], e1, _, _); Expr.Lambda (_, _, _, [_], e2, _, _)] -> CheckTypeInstNoInnerByrefs cenv env m tyargs // result of a try/finally can be a byref let limit = CheckExpr cenv env e1 ctxt // result of a try/finally can be a byref if in a position where the overall expression is can be a byref - CheckExprNoByrefs cenv env e2 + CheckExprNoByrefs cenv { env with withinHandler = true } e2 limit | TOp.IntegerForLoop _, _, [Expr.Lambda (_, _, _, [_], e1, _, _);Expr.Lambda (_, _, _, [_], e2, _, _);Expr.Lambda (_, _, _, [_], e3, _, _)] -> @@ -1525,7 +1534,7 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = CheckTypeInstNoInnerByrefs cenv env m tyargs // result of a try/catch can be a byref let limit1 = CheckExpr cenv env e1 ctxt // result of a try/catch can be a byref if in a position where the overall expression is can be a byref // [(* e2; -- don't check filter body - duplicates logic in 'catch' body *) e3] - let limit2 = CheckExpr cenv env e3 ctxt // result of a try/catch can be a byref if in a position where the overall expression is can be a byref + let limit2 = CheckExpr cenv { env with withinHandler = true } e3 ctxt // result of a try/catch can be a byref if in a position where the overall expression is can be a byref CombineTwoLimits limit1 limit2 | TOp.ILCall (_, _, _, _, _, _, _, ilMethRef, enclTypeInst, methInst, retTypes), _, _ -> @@ -1810,6 +1819,7 @@ and CheckLambdas isTop (memberVal: Val option) cenv env inlined valReprInfo alwa let restArgs = List.concat vsl let syntacticArgs = thisAndBase @ restArgs let env = BindArgVals env restArgs + let env = { env with withinHandler = false } match memInfo with | None -> () @@ -2852,7 +2862,8 @@ let CheckImplFile (g, amap, reportErrors, infoReader, internalsVisibleToPaths, v external=false returnScope = 0 isInAppExpr = false - resumableCode = Resumable.None } + resumableCode = Resumable.None + withinHandler = false } CheckImplFileContents cenv env implFileTy implFileContents CheckAttribs cenv env extraAttribs diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 7a53eae36f3..06c4e93c112 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1821,3 +1821,4 @@ featureRecordSpreads,"record type and expression spreads" 3913,tcExtendedLayoutCannotBeUsedOnUnions,"The 'ExtendedLayoutAttribute' cannot be applied to discriminated unions" 3914,tcExtendedLayoutStructMustHaveInstanceField,"A struct with the 'ExtendedLayoutAttribute' must have at least one instance field" 3915,tcTupleTypeExtensionTooManyElements,"Tuple type extensions are supported only for tuples of up to 7 elements, but this tuple type has %d elements. Extensions of larger tuples are not supported." +3916,chkNativePtrStackallocInHandler,"'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded." diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 24b2e645bfb..210849e0067 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -885,6 +885,7 @@ type TcGlobals( let v_option_defaultValue_info = makeIntrinsicValRef(fslib_MFOptionModule_nleref, "defaultValue" , None , Some "DefaultValue" , [vara], ([[varaTy]; [mkOptionTy varaTy]], varaTy)) let v_nativeptr_tobyref_info = makeIntrinsicValRef(fslib_MFNativePtrModule_nleref, "toByRef" , None , Some "ToByRefInlined", [vara], ([[mkNativePtrTy varaTy]], mkByrefTy varaTy)) + let v_nativeptr_stackalloc_info = makeIntrinsicValRef(fslib_MFNativePtrModule_nleref, "stackalloc" , None , Some "StackAllocate", [vara], ([[v_int32_ty]], mkNativePtrTy varaTy)) let v_seq_collect_info = makeIntrinsicValRef(fslib_MFSeqModule_nleref, "collect" , None , Some "Collect", [vara;varb;varc], ([[varaTy --> varbTy]; [mkSeqTy varaTy]], mkSeqTy varcTy)) let v_seq_delay_info = makeIntrinsicValRef(fslib_MFSeqModule_nleref, "delay" , None , Some "Delay" , [varb], ([[v_unit_ty --> mkSeqTy varbTy]], mkSeqTy varbTy)) @@ -1757,6 +1758,7 @@ type TcGlobals( member val seq_singleton_vref = ValRefForIntrinsic v_seq_singleton_info member val seq_collect_vref = ValRefForIntrinsic v_seq_collect_info member val nativeptr_tobyref_vref = ValRefForIntrinsic v_nativeptr_tobyref_info + member val nativeptr_stackalloc_vref = ValRefForIntrinsic v_nativeptr_stackalloc_info member val seq_using_vref = ValRefForIntrinsic v_seq_using_info member val seq_delay_vref = ValRefForIntrinsic v_seq_delay_info member val seq_append_vref = ValRefForIntrinsic v_seq_append_info diff --git a/src/Compiler/TypedTree/TcGlobals.fsi b/src/Compiler/TypedTree/TcGlobals.fsi index 8356b16ccfc..a8f1dc89357 100644 --- a/src/Compiler/TypedTree/TcGlobals.fsi +++ b/src/Compiler/TypedTree/TcGlobals.fsi @@ -791,6 +791,8 @@ type internal TcGlobals = member nativeptr_tobyref_vref: TypedTree.ValRef + member nativeptr_stackalloc_vref: TypedTree.ValRef + member new_decimal_info: IntrinsicValRef member new_format_info: IntrinsicValRef diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 9649b05a722..8ada5a8834d 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -132,6 +132,11 @@ The interface '{0}' cannot be used as a type argument because the static abstract member '{1}' does not have a most specific implementation in the interface. + + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + + The member or function '{0}' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way. Člen nebo funkce „{0}“ má atribut „TailCallAttribute“, ale nepoužívá se koncovým (tail) rekurzivním způsobem. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 80c89f42d06..a1f16d17807 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -132,6 +132,11 @@ The interface '{0}' cannot be used as a type argument because the static abstract member '{1}' does not have a most specific implementation in the interface. + + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + + The member or function '{0}' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way. Der Member oder die Funktion "{0}" weist das Attribut "TailCallAttribute" auf, wird jedoch nicht endrekursiv verwendet. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 3452a9f4074..afb4e5f07af 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -132,6 +132,11 @@ The interface '{0}' cannot be used as a type argument because the static abstract member '{1}' does not have a most specific implementation in the interface. + + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + + The member or function '{0}' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way. El miembro o la función “{0}” tiene el atributo “TailCallAttribute”, pero no se usa de forma de recursión de cola. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 1c029f7d57c..b7828962564 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -132,6 +132,11 @@ The interface '{0}' cannot be used as a type argument because the static abstract member '{1}' does not have a most specific implementation in the interface. + + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + + The member or function '{0}' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way. Le membre ou la fonction « {0} » possède l'attribut « TailCallAttribute », mais n'est pas utilisé de manière récursive. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 8006c24faa0..94a7c0fbab6 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -132,6 +132,11 @@ The interface '{0}' cannot be used as a type argument because the static abstract member '{1}' does not have a most specific implementation in the interface. + + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + + The member or function '{0}' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way. Il membro o la funzione "{0}" ha l'attributo "TailCallAttribute", ma non è in uso in modo ricorsivo finale. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 5dffc6c4d0a..2a8e7665298 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -132,6 +132,11 @@ The interface '{0}' cannot be used as a type argument because the static abstract member '{1}' does not have a most specific implementation in the interface. + + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + + The member or function '{0}' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way. メンバーまたは関数 '{0}' には 'TailCallAttribute' 属性がありますが、末尾の再帰的な方法では使用されていません。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 841f583de03..8677a6549f9 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -132,6 +132,11 @@ The interface '{0}' cannot be used as a type argument because the static abstract member '{1}' does not have a most specific implementation in the interface. + + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + + The member or function '{0}' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way. 멤버 또는 함수 '{0}'에 'TailCallAttribute' 특성이 있지만 비상 재귀적인 방식으로 사용되고 있지 않습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 0696a3f904f..53c7cb6f5e9 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -132,6 +132,11 @@ The interface '{0}' cannot be used as a type argument because the static abstract member '{1}' does not have a most specific implementation in the interface. + + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + + The member or function '{0}' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way. Składowa lub funkcja „{0}” ma atrybut „TailCallAttribute”, ale nie jest używana w sposób cykliczny końca. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 92fc3e6c918..48a7a706712 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -132,6 +132,11 @@ The interface '{0}' cannot be used as a type argument because the static abstract member '{1}' does not have a most specific implementation in the interface. + + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + + The member or function '{0}' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way. O membro ou a função "{0}" tem o atributo "TailCallAttribute", mas não está sendo usado de maneira recursiva em cauda. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index e4fefadb0bf..6962d93e1ff 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -132,6 +132,11 @@ The interface '{0}' cannot be used as a type argument because the static abstract member '{1}' does not have a most specific implementation in the interface. + + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + + The member or function '{0}' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way. Элемент или функция "{0}" содержит атрибут "TailCallAttribute", но не используется в рекурсивном хвостовом режиме. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index fbcca933879..986fca815dc 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -132,6 +132,11 @@ The interface '{0}' cannot be used as a type argument because the static abstract member '{1}' does not have a most specific implementation in the interface. + + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + + The member or function '{0}' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way. Üye veya '{0}' işlevi, 'TailCallAttribute' özniteliğine sahip ancak kuyruk özyinelemeli bir şekilde kullanılmıyor. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index e38cf4f9d73..2f509732719 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -132,6 +132,11 @@ The interface '{0}' cannot be used as a type argument because the static abstract member '{1}' does not have a most specific implementation in the interface. + + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + + The member or function '{0}' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way. 成员或函数“{0}”具有 "TailCallAttribute" 属性,但未以尾递归方式使用。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index cafc3b32a6a..836c32e0f30 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -132,6 +132,11 @@ The interface '{0}' cannot be used as a type argument because the static abstract member '{1}' does not have a most specific implementation in the interface. + + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + 'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded. + + The member or function '{0}' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way. 成員或函式 '{0}' 具有 'TailCallAttribute' 屬性,但未以尾遞迴方式使用。 diff --git a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs index f44304fad85..4cd241556f5 100644 --- a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs +++ b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs @@ -171,3 +171,85 @@ let call (s: Sink) = IL_000f: callvirt instance int32 Test/Sink::Put(native int) IL_0014: ret }""" ] + + // Regression tests for https://github.com/dotnet/fsharp/issues/20295 (Case 1): 'NativePtr.stackalloc' + // emits the 'localloc' IL instruction, which the JIT rejects inside an exception-handling region. + // Such code used to compile and then throw InvalidProgramException at method load; it must now be + // rejected at compile time with FS3916. + [] + [ NativePtr.stackalloc 1 |> ignore")>] + [ NativePtr.stackalloc 1 |> ignore")>] + [ 1 |> ignore")>] + [ (try () with _ -> NativePtr.stackalloc 1 |> ignore)")>] + let ``stackalloc in a handler is rejected`` (handler: string) = + $""" +module Test +open Microsoft.FSharp.NativeInterop +let f () = {handler} +""" + |> FSharp + |> withNoWarn 9 + |> compile + |> shouldFail + |> withErrorCode 3916 + + [] + let ``stackalloc in the try body is allowed`` () = + FSharp """ +module Test +open Microsoft.FSharp.NativeInterop +let f () = try NativePtr.stackalloc 1 |> ignore with _ -> () +""" + |> withNoWarn 9 + |> compile + |> shouldSucceed + + [] + let ``stackalloc in a lambda inside a handler is allowed`` () = + FSharp """ +module Test +open Microsoft.FSharp.NativeInterop +let f () = try () with _ -> (fun () -> NativePtr.stackalloc 1 |> ignore) () +""" + |> withNoWarn 9 + |> compile + |> shouldSucceed + + [] + let ``stackalloc in an object-expression method inside a handler is allowed`` () = + FSharp """ +module Test +open Microsoft.FSharp.NativeInterop +let f () = + try () + with _ -> + let d = { new System.IDisposable with member _.Dispose() = NativePtr.stackalloc 1 |> ignore } + d.Dispose() +""" + |> withNoWarn 9 + |> compile + |> shouldSucceed + + [] + let ``stackalloc outside any try compiles and runs`` () = + FSharp """ +module Test +open Microsoft.FSharp.NativeInterop +[] +let main _ = + NativePtr.stackalloc 1 |> ignore + printfn "ok" + 0 +""" + |> withNoWarn 9 + |> compileExeAndRun + |> shouldSucceed + + [] + let ``handler without stackalloc is unaffected`` () = + FSharp """ +module Test +let f () = try () with _ -> printfn "handled" +""" + |> compile + |> shouldSucceed From 455dee5b7fba43f4fc0331fd632bc6faeff37def Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 8 Sep 2026 12:48:52 +0200 Subject: [PATCH 2/9] Reject NativePtr.stackalloc in an inlinable lambda inside a handler (FS3916) An immediately-applied lambda in a 'try' handler is inlined into the handler's IL region by the optimizer, so its 'localloc' still lands inside the exception-handling region and throws InvalidProgramException under --optimize+. The CheckLambdas 'withinHandler = false' reset was based on the false premise that every lambda becomes a separate method; remove it so lambda bodies inside a handler are conservatively checked. Genuine method boundaries (object-expression/interface methods) keep their reset via CheckMethod and remain legal (verified by compileExeAndRun). Part of issue #20295 (Case 1). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/Checking/PostInferenceChecks.fs | 1 - .../Libraries/NativeInterop.fs | 22 +++++++++---------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index 80f41d00dc4..ab29dcc6670 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -1819,7 +1819,6 @@ and CheckLambdas isTop (memberVal: Val option) cenv env inlined valReprInfo alwa let restArgs = List.concat vsl let syntacticArgs = thisAndBase @ restArgs let env = BindArgVals env restArgs - let env = { env with withinHandler = false } match memInfo with | None -> () diff --git a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs index 4cd241556f5..a057135c7e5 100644 --- a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs +++ b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs @@ -181,6 +181,9 @@ let call (s: Sink) = [ NativePtr.stackalloc 1 |> ignore")>] [ 1 |> ignore")>] [ (try () with _ -> NativePtr.stackalloc 1 |> ignore)")>] + // An immediately-applied lambda in a handler is inlined into the handler's IL region by the + // optimizer, so its 'localloc' still lands inside the exception region and must be rejected. + [ (fun () -> NativePtr.stackalloc 1 |> ignore) ()")>] let ``stackalloc in a handler is rejected`` (handler: string) = $""" module Test @@ -199,17 +202,6 @@ let f () = {handler} module Test open Microsoft.FSharp.NativeInterop let f () = try NativePtr.stackalloc 1 |> ignore with _ -> () -""" - |> withNoWarn 9 - |> compile - |> shouldSucceed - - [] - let ``stackalloc in a lambda inside a handler is allowed`` () = - FSharp """ -module Test -open Microsoft.FSharp.NativeInterop -let f () = try () with _ -> (fun () -> NativePtr.stackalloc 1 |> ignore) () """ |> withNoWarn 9 |> compile @@ -225,10 +217,16 @@ let f () = with _ -> let d = { new System.IDisposable with member _.Dispose() = NativePtr.stackalloc 1 |> ignore } d.Dispose() +[] +let main _ = + f () + printfn "ok" + 0 """ |> withNoWarn 9 - |> compile + |> compileExeAndRun |> shouldSucceed + |> withStdOutContains "ok" [] let ``stackalloc outside any try compiles and runs`` () = From 59c362369133cd5a65782cf122aa85c67f1a11de Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 8 Sep 2026 14:17:53 +0200 Subject: [PATCH 3/9] Hoist localloc base-ctor args before uninitialized 'this' (issue #20295 Case 2) NativePtr.stackalloc used as a chained base-constructor argument emitted 'localloc' while an uninitialized 'this' was pending on the evaluation stack, which the JIT rejects (InvalidProgramException at method load). The uninitialized 'this' cannot be spilled to a local, so the existing spill mechanism could not clear the stack. When a base/self-ctor argument may emit 'localloc', evaluate the arguments into locals first (at a clean stack), then push 'this' and reload them. Left-to-right evaluation order is preserved and ordinary base ctors emit byte-identical IL. The fix is applied in both GenApp and GenILCall. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/CodeGen/IlxGen.fs | 97 +++++++++++++--- .../Libraries/NativeInterop.fs | 105 ++++++++++++++++++ 2 files changed, 186 insertions(+), 16 deletions(-) diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index ceeec0a69ec..6bc4f60a212 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -3166,6 +3166,21 @@ let ComputeDebugPointForBinding g bind = // Generate expressions //------------------------------------------------------------------------- +/// True if evaluating this expression may emit the 'localloc' IL instruction (e.g. NativePtr.stackalloc, +/// which the optimizer inlines to inline IL containing 'localloc' before IlxGen runs). +let exprMayLocalloc expr = + (false, expr) + ||> FoldExpr + { ExprFolder0 with + exprIntercept = + (fun _exprF noInterceptF z expr -> + z + || (match expr with + | Expr.Op(TOp.ILAsm(instrs, _), _, _, _) -> instrs |> List.contains I_localloc + | _ -> false) + || noInterceptF false expr) + } + let rec GenExpr cenv cgbuf eenv (expr: Expr) sequel = cenv.stackGuard.Guard(fun () -> @@ -4717,21 +4732,47 @@ and GenApp (cenv: cenv) cgbuf eenv (f, fty, tyargs, curriedArgs, m) sequel = else mspec.DeclaringType - if isSuperInit || isSelfInit then - CG.EmitInstr cgbuf (pop 0) (Push [ thisTy ]) mkLdarg0 - let pendingUninitializedThis = (isSuperInit || isSelfInit) && not valu - if pendingUninitializedThis then + let genArgs () = + if not cenv.g.generateWitnesses || witnessInfos.IsEmpty then + () // no witness args + else + let _ctyargs, mtyargs = List.splitAt ctps.Length tyargs + GenWitnessArgs cenv cgbuf eenv m mtps mtyargs + + GenUntupledArgsDiscardingLoneUnit cenv cgbuf eenv m vref.NumObjArgs curriedArgInfos nowArgs + + // An uninitialized 'this' cannot be spilled, so a 'localloc' emitted by a base/self-ctor + // argument while 'this' is pending on the stack yields invalid IL (InvalidProgramException at + // load). When that can happen, evaluate the args into locals first (at a clean stack), then + // push 'this' and reload them; left-to-right evaluation order is preserved and ordinary ctors + // are unaffected. + let hoistArgsBeforeThis = + pendingUninitializedThis && List.exists exprMayLocalloc nowArgs + + if hoistArgsBeforeThis then + let stackBefore = cgbuf.GetCurrentStack() + genArgs () + + let argTys = + let stackAfter = cgbuf.GetCurrentStack() + stackAfter |> List.truncate (stackAfter.Length - stackBefore.Length) + + let argLocals = [ for ty in argTys -> cgbuf.SpillToLocal(ty, false) ] + CG.EmitInstr cgbuf (pop 0) (Push [ thisTy ]) mkLdarg0 cgbuf.StartUninitializedThisOnStack() - if not cenv.g.generateWitnesses || witnessInfos.IsEmpty then - () // no witness args + for local in List.rev argLocals do + cgbuf.ReloadFromLocal local else - let _ctyargs, mtyargs = List.splitAt ctps.Length tyargs - GenWitnessArgs cenv cgbuf eenv m mtps mtyargs + if isSuperInit || isSelfInit then + CG.EmitInstr cgbuf (pop 0) (Push [ thisTy ]) mkLdarg0 + + if pendingUninitializedThis then + cgbuf.StartUninitializedThisOnStack() - GenUntupledArgsDiscardingLoneUnit cenv cgbuf eenv m vref.NumObjArgs curriedArgInfos nowArgs + genArgs () // Generate laterArgs (for effects) and save LocalScope "callstack" cgbuf (fun scopeMarks -> @@ -5809,17 +5850,41 @@ and GenILCall else ilMethSpec.DeclaringType - // Load the 'this' pointer to pass to the superclass constructor. This argument is not - // in the expression tree since it can't be treated like an ordinary value - if isSuperInit then - CG.EmitInstr cgbuf (pop 0) (Push [ thisTy ]) mkLdarg0 - + // An uninitialized 'this' cannot be spilled, so a 'localloc' emitted by a base-ctor argument while + // 'this' is pending on the stack produces invalid IL (InvalidProgramException at load). When that + // can happen, evaluate the args into locals first (at a clean stack), then push 'this' and reload + // them. Left-to-right evaluation order is preserved; ordinary base ctors are unaffected. let pendingUninitializedThis = isSuperInit && not valu - if pendingUninitializedThis then + let hoistArgsBeforeThis = + pendingUninitializedThis && List.exists exprMayLocalloc argExprs + + if hoistArgsBeforeThis then + let g = cenv.g + + let argLocals = + [ + for argExpr in argExprs -> + let ilTy = argExpr |> tyOfExpr g |> GenType cenv m eenv.tyenv + GenExpr cenv cgbuf eenv argExpr Continue + cgbuf.SpillToLocal(ilTy, false) + ] + + CG.EmitInstr cgbuf (pop 0) (Push [ thisTy ]) mkLdarg0 cgbuf.StartUninitializedThisOnStack() - GenExprs cenv cgbuf eenv argExprs + for local in argLocals do + cgbuf.ReloadFromLocal local + else + // Load the 'this' pointer to pass to the superclass constructor. This argument is not + // in the expression tree since it can't be treated like an ordinary value + if isSuperInit then + CG.EmitInstr cgbuf (pop 0) (Push [ thisTy ]) mkLdarg0 + + if pendingUninitializedThis then + cgbuf.StartUninitializedThisOnStack() + + GenExprs cenv cgbuf eenv argExprs let il = if newobj then diff --git a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs index a057135c7e5..323969a116d 100644 --- a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs +++ b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs @@ -251,3 +251,108 @@ let f () = try () with _ -> printfn "handled" """ |> compile |> shouldSucceed + + // Regression tests for https://github.com/dotnet/fsharp/issues/20295 (Case 2): a 'NativePtr.stackalloc' + // used as a chained base-constructor argument loads the uninitialized 'this' before evaluating the + // argument, so its 'localloc' ran with 'this' pending on the stack and could not be spilled - the + // emitted IL threw InvalidProgramException at load. The args are now hoisted into locals before 'this'. + [] + let ``stackalloc as a base-ctor argument`` () = + FSharp """ +module Test +open Microsoft.FSharp.NativeInterop +type A(p: nativeptr) = class end +type B() = inherit A(NativePtr.stackalloc 1) +[] +let main _ = + B() |> ignore + printfn "ok" + 0 +""" + |> withNoWarn 9 + |> compileExeAndRun + |> shouldSucceed + |> withStdOutContains "ok" + + [] + let ``stackalloc as one of several base-ctor arguments`` () = + FSharp """ +module Test +open Microsoft.FSharp.NativeInterop +type A(n: int, p: nativeptr) = class end +type B() = inherit A(1, NativePtr.stackalloc 1) +[] +let main _ = + B() |> ignore + printfn "ok" + 0 +""" + |> withNoWarn 9 + |> compileExeAndRun + |> shouldSucceed + |> withStdOutContains "ok" + + [] + let ``stackalloc as a generic base-ctor argument`` () = + FSharp """ +module Test +open Microsoft.FSharp.NativeInterop +type A<'T when 'T: unmanaged>(p: nativeptr<'T>) = class end +type B() = inherit A(NativePtr.stackalloc 1) +[] +let main _ = + B() |> ignore + printfn "ok" + 0 +""" + |> withNoWarn 9 + |> compileExeAndRun + |> shouldSucceed + |> withStdOutContains "ok" + + // The hoist evaluates the base-ctor args left-to-right into locals before pushing 'this'; a + // side-effecting normal arg before the stackalloc arg must still run first. + [] + let ``stackalloc base-ctor argument preserves left-to-right order`` () = + FSharp """ +module Test +open Microsoft.FSharp.NativeInterop +let trace = System.Text.StringBuilder() +let step (name: string) x = trace.Append name |> ignore; x +type A(n: int, p: nativeptr) = class end +type B() = inherit A(step "a" 1, step "b" (NativePtr.stackalloc 1)) +[] +let main _ = + B() |> ignore + if string trace <> "ab" then failwithf "wrong order: %O" trace + printfn "ok" + 0 +""" + |> withNoWarn 9 + |> compileExeAndRun + |> shouldSucceed + |> withStdOutContains "ok" + + // No-regression: an ordinary base ctor without a 'localloc' argument must not hoist - the arg is + // pushed directly onto 'this', with no extra local introduced by the hoist. + [] + let ``ordinary base-ctor argument is not hoisted`` () = + FSharp """ +module Test +type A(n: int) = class end +type B() = inherit A(1) +""" + |> compile + |> shouldSucceed + |> verifyILContains [ + """.method public specialname rtspecialname instance void .ctor() cil managed + { + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: callvirt instance void Test/A::.ctor(int32) + IL_0007: ldarg.0 + IL_0008: pop + IL_0009: ret + }""" ] From 917fa7ba2e998e8a40f9433f6dcab460c99910d4 Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 8 Sep 2026 15:12:11 +0200 Subject: [PATCH 4/9] Consolidate Case-2 base-ctor stackalloc run tests into one theory (#20295) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Libraries/NativeInterop.fs | 56 +++++-------------- 1 file changed, 15 insertions(+), 41 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs index 323969a116d..0740d201750 100644 --- a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs +++ b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs @@ -256,55 +256,29 @@ let f () = try () with _ -> printfn "handled" // used as a chained base-constructor argument loads the uninitialized 'this' before evaluating the // argument, so its 'localloc' ran with 'this' pending on the stack and could not be spilled - the // emitted IL threw InvalidProgramException at load. The args are now hoisted into locals before 'this'. - [] - let ``stackalloc as a base-ctor argument`` () = - FSharp """ -module Test -open Microsoft.FSharp.NativeInterop -type A(p: nativeptr) = class end -type B() = inherit A(NativePtr.stackalloc 1) -[] -let main _ = - B() |> ignore - printfn "ok" - 0 -""" - |> withNoWarn 9 - |> compileExeAndRun - |> shouldSucceed - |> withStdOutContains "ok" - - [] - let ``stackalloc as one of several base-ctor arguments`` () = - FSharp """ -module Test -open Microsoft.FSharp.NativeInterop -type A(n: int, p: nativeptr) = class end -type B() = inherit A(1, NativePtr.stackalloc 1) -[] -let main _ = - B() |> ignore - printfn "ok" - 0 -""" - |> withNoWarn 9 - |> compileExeAndRun - |> shouldSucceed - |> withStdOutContains "ok" - - [] - let ``stackalloc as a generic base-ctor argument`` () = - FSharp """ + [] + // simple nativeptr base-ctor arg + [) = class end", + "type B() = inherit A(NativePtr.stackalloc 1)")>] + // stackalloc as one of several base-ctor args + [) = class end", + "type B() = inherit A(1, NativePtr.stackalloc 1)")>] + // generic base type instantiated concretely + [(p: nativeptr<'T>) = class end", + "type B() = inherit A(NativePtr.stackalloc 1)")>] + let ``stackalloc as a base-ctor argument compiles and runs`` (baseType: string) (derived: string) = + $""" module Test open Microsoft.FSharp.NativeInterop -type A<'T when 'T: unmanaged>(p: nativeptr<'T>) = class end -type B() = inherit A(NativePtr.stackalloc 1) +{baseType} +{derived} [] let main _ = B() |> ignore printfn "ok" 0 """ + |> FSharp |> withNoWarn 9 |> compileExeAndRun |> shouldSucceed From 8f53ed68065cfd35e8559f6d015913e702113d00 Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 8 Sep 2026 15:30:37 +0200 Subject: [PATCH 5/9] Finalize #20295: release note for NativePtr.stackalloc base-ctor hoist Adds a Fixed release note for the Case-2 base-constructor argument hoist. Verified xlf/surface-area baselines are in sync and formatting is clean; ran full regression (NativeInterop 17/17, Byref 138/138, Language RegressionTests 29/29, SurfaceAreaTest green). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/release-notes/.FSharp.Compiler.Service/11.0.100.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index 4e20ee59fe9..439f1eb82c0 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -1,6 +1,7 @@ ### Fixed * Fix `NativePtr.stackalloc` used inside the `with` handler, filter or `finally` block of a `try` expression producing an assembly that throws `InvalidProgramException` at method load. The `localloc` IL instruction it emits is rejected by the runtime inside an exception-handling region, so this is now reported at compile time as error FS3916. ([Issue #20295](https://github.com/dotnet/fsharp/issues/20295)) +* Fix `NativePtr.stackalloc` used as a chained base-constructor argument producing an assembly that throws `InvalidProgramException` at method load; the base-constructor arguments are now hoisted into locals before the uninitialized `this` is pushed. ([Issue #20295](https://github.com/dotnet/fsharp/issues/20295)) * Fix `NativePtr.stackalloc` nested in a larger expression (e.g. a call argument or the right of an assignment) producing an assembly that throws `InvalidProgramException` at load. ([Issue #8083](https://github.com/dotnet/fsharp/issues/8083), [PR #20302](https://github.com/dotnet/fsharp/pull/20302)) * Fix internal error "Unexpected generalized type variables when compiling an active pattern" when an active pattern is used in a `let` binding whose right-hand side is a generic value, e.g. `let (T) = id`. Such a binding is now checked like the equivalent `match` and is not generalized. ([Issue #16856](https://github.com/dotnet/fsharp/issues/16856), [PR #20383](https://github.com/dotnet/fsharp/pull/20383)) * Fix Release-only (`--optimize+`) `System.InvalidProgramException` from `Seq.collect` / `yield!` over a value-type (struct) collection implementing `seq<'T>` (e.g. `ImmutableArray<_>`) when materialised with `List.ofSeq` / `Seq.toList` / `Seq.toArray` or a list/array comprehension. The collector lowering now boxes a struct sub-collection to `seq<'T>` before calling `AddMany`/`AddManyAndClose` (matching the coercion the type checker already inserts for `yield!`), and uses `unit` as the try/finally result type instead of the body type (removing a spurious `ldnull` store). ([Issue #20203](https://github.com/dotnet/fsharp/issues/20203)) From 6e87905b0fd0e01113d7b6d38143fd04536128b1 Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 8 Sep 2026 17:43:00 +0200 Subject: [PATCH 6/9] Move NativePtr.stackalloc-in-handler check to codegen (FS3916, issue #20295 Case 1) The syntactic PostInferenceChecks detection ran before inlining and closure conversion, so it could not tell an escaping closure (whose 'localloc' lands in its own method and is legal) from an inlined/immediately-applied lambda or a 'let inline' wrapper (whose 'localloc' lands in the handler region and is illegal). This produced both a false positive (rejecting legal escaping closures) and a false negative ('let inline' wrapper compiled and threw InvalidProgramException at load). Detect 'localloc' emission inside a catch/filter/finally/fault region at codegen instead, via a new eenv.withinExnHandler flag set on the handler bodies in GenTryWith/GenTryFinally and reset at method/closure boundaries. By that point inlining and closure conversion have run, so the true exception-handling region is known: escaping closures stay legal, inlined localloc is rejected. The try body keeps 'localloc' legal per ECMA-335. Removes the now-unused withinHandler plumbing and the nativeptr_stackalloc_vref intrinsic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/Checking/PostInferenceChecks.fs | 16 ++------ src/Compiler/CodeGen/IlxGen.fs | 18 +++++++++ src/Compiler/TypedTree/TcGlobals.fs | 2 - src/Compiler/TypedTree/TcGlobals.fsi | 2 - .../Libraries/NativeInterop.fs | 39 ++++++++++++++++++- 5 files changed, 59 insertions(+), 18 deletions(-) diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index ab29dcc6670..1d5798320b4 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -100,9 +100,6 @@ type env = /// Are we expecting a resumable code block etc resumableCode: Resumable - - /// Are we inside the 'with' handler, filter, or 'finally' block of a 'try'? - withinHandler: bool } override _.ToString() = "" @@ -1251,11 +1248,6 @@ and CheckExpr (cenv: cenv) (env: env) origExpr (ctxt: PermitByRefExpr) : Limit = // Check an application | Expr.App (f, _fty, tyargs, argsl, m) -> - (match f with - | OptionalCoerce(Expr.Val (vref, _, _)) - when env.withinHandler && cenv.reportErrors && valRefEq g vref g.nativeptr_stackalloc_vref -> - errorR(Error(FSComp.SR.chkNativePtrStackallocInHandler(), m)) - | _ -> ()) CheckApplication cenv env expr (f, tyargs, argsl, m) ctxt | Expr.Lambda (_, _, _, argvs, _, m, bodyTy) -> @@ -1481,7 +1473,6 @@ and CheckMethod cenv env baseValOpt ty (TObjExprMethod(_, attribs, tps, vs, body { env with resumableCode = Resumable.ResumableExpr false } else { env with resumableCode = Resumable.None } - let env = { env with withinHandler = false } CheckAttribs cenv env attribs CheckNoReraise cenv None body CheckEscapes cenv true m (match baseValOpt with Some x -> x :: vs | None -> vs) body |> ignore @@ -1523,7 +1514,7 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = | TOp.TryFinally _, [_], [Expr.Lambda (_, _, _, [_], e1, _, _); Expr.Lambda (_, _, _, [_], e2, _, _)] -> CheckTypeInstNoInnerByrefs cenv env m tyargs // result of a try/finally can be a byref let limit = CheckExpr cenv env e1 ctxt // result of a try/finally can be a byref if in a position where the overall expression is can be a byref - CheckExprNoByrefs cenv { env with withinHandler = true } e2 + CheckExprNoByrefs cenv env e2 limit | TOp.IntegerForLoop _, _, [Expr.Lambda (_, _, _, [_], e1, _, _);Expr.Lambda (_, _, _, [_], e2, _, _);Expr.Lambda (_, _, _, [_], e3, _, _)] -> @@ -1534,7 +1525,7 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = CheckTypeInstNoInnerByrefs cenv env m tyargs // result of a try/catch can be a byref let limit1 = CheckExpr cenv env e1 ctxt // result of a try/catch can be a byref if in a position where the overall expression is can be a byref // [(* e2; -- don't check filter body - duplicates logic in 'catch' body *) e3] - let limit2 = CheckExpr cenv { env with withinHandler = true } e3 ctxt // result of a try/catch can be a byref if in a position where the overall expression is can be a byref + let limit2 = CheckExpr cenv env e3 ctxt // result of a try/catch can be a byref if in a position where the overall expression is can be a byref CombineTwoLimits limit1 limit2 | TOp.ILCall (_, _, _, _, _, _, _, ilMethRef, enclTypeInst, methInst, retTypes), _, _ -> @@ -2861,8 +2852,7 @@ let CheckImplFile (g, amap, reportErrors, infoReader, internalsVisibleToPaths, v external=false returnScope = 0 isInAppExpr = false - resumableCode = Resumable.None - withinHandler = false } + resumableCode = Resumable.None } CheckImplFileContents cenv env implFileTy implFileContents CheckAttribs cenv env extraAttribs diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 6bc4f60a212..b38575123f7 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -1261,6 +1261,12 @@ and IlxGenEnv = /// Are we under the scope of a try, catch or finally? If so we can't tailcall. SEH = structured exception handling withinSEH: bool + /// Are we within the 'with'/filter/'finally'/fault handler region of a 'try' (but not merely its try body)? + /// The JIT rejects the 'localloc' IL instruction (emitted by NativePtr.stackalloc) inside such a region, so + /// emitting it here is reported as error FS3916. This is checked at codegen, after inlining and closure + /// conversion, so an escaping closure whose 'localloc' lives in its own method stays legal. + withinExnHandler: bool + /// Suppresses filter block emission inside finally/fault handlers (workaround for dotnet/runtime#112406). insideFinallyOrFaultHandler: bool @@ -3055,6 +3061,7 @@ let CodeGenThen (cenv: cenv) mgbuf (entryPointInfo, methodName, eenv, alreadyUse cgbuf { eenv with withinSEH = false + withinExnHandler = false insideFinallyOrFaultHandler = false liveLocals = IntMap.empty () innerVals = innerVals @@ -5219,6 +5226,7 @@ and GenTryWith cenv cgbuf eenv (e1, valForFilter: Val, filterExpr, valForHandler let eenvinner = { eenvinner with + withinExnHandler = true exitSequel = sequelOnBranches } // We emit the debug point for the 'with' keyword span on the start of the filter @@ -5289,6 +5297,7 @@ and GenTryWith cenv cgbuf eenv (e1, valForFilter: Val, filterExpr, valForHandler let eenvinner = { eenvinner with + withinExnHandler = true exitSequel = exitSequel } @@ -5334,6 +5343,7 @@ and GenTryFinally cenv cgbuf eenv (bodyExpr, handlerExpr, m, resTy, spTry, spFin let eenvHandler = { eenvinner with + withinExnHandler = true insideFinallyOrFaultHandler = true } @@ -5641,6 +5651,13 @@ and GenAsmCode cenv cgbuf eenv (il, tyargs, args, returnTys, m) sequel = && ilReturnTys |> List.forall (fun ty -> ty <> ILType.Void) -> + // The JIT rejects 'localloc' inside an exception-handling region, producing an + // InvalidProgramException at method load. By this point inlining and closure conversion have run, + // so eenv.withinExnHandler reflects the true handler region: an escaping closure carrying the + // 'localloc' into its own method has had the flag reset and stays legal. + if eenv.withinExnHandler then + errorR (Error(FSComp.SR.chkNativePtrStackallocInHandler (), m)) + CG.EmitLocallocCode cgbuf (fun () -> GenExprs cenv cgbuf eenv args CG.EmitInstrs cgbuf (pop args.Length) (Push ilReturnTys) ilAfterInst) @@ -13131,6 +13148,7 @@ let GetEmptyIlxGenEnv (g: TcGlobals) ccu = innerVals = [] sigToImplRemapInfo = [] (* "module remap info" *) withinSEH = false + withinExnHandler = false insideFinallyOrFaultHandler = false isInLoop = false initLocals = true diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 210849e0067..24b2e645bfb 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -885,7 +885,6 @@ type TcGlobals( let v_option_defaultValue_info = makeIntrinsicValRef(fslib_MFOptionModule_nleref, "defaultValue" , None , Some "DefaultValue" , [vara], ([[varaTy]; [mkOptionTy varaTy]], varaTy)) let v_nativeptr_tobyref_info = makeIntrinsicValRef(fslib_MFNativePtrModule_nleref, "toByRef" , None , Some "ToByRefInlined", [vara], ([[mkNativePtrTy varaTy]], mkByrefTy varaTy)) - let v_nativeptr_stackalloc_info = makeIntrinsicValRef(fslib_MFNativePtrModule_nleref, "stackalloc" , None , Some "StackAllocate", [vara], ([[v_int32_ty]], mkNativePtrTy varaTy)) let v_seq_collect_info = makeIntrinsicValRef(fslib_MFSeqModule_nleref, "collect" , None , Some "Collect", [vara;varb;varc], ([[varaTy --> varbTy]; [mkSeqTy varaTy]], mkSeqTy varcTy)) let v_seq_delay_info = makeIntrinsicValRef(fslib_MFSeqModule_nleref, "delay" , None , Some "Delay" , [varb], ([[v_unit_ty --> mkSeqTy varbTy]], mkSeqTy varbTy)) @@ -1758,7 +1757,6 @@ type TcGlobals( member val seq_singleton_vref = ValRefForIntrinsic v_seq_singleton_info member val seq_collect_vref = ValRefForIntrinsic v_seq_collect_info member val nativeptr_tobyref_vref = ValRefForIntrinsic v_nativeptr_tobyref_info - member val nativeptr_stackalloc_vref = ValRefForIntrinsic v_nativeptr_stackalloc_info member val seq_using_vref = ValRefForIntrinsic v_seq_using_info member val seq_delay_vref = ValRefForIntrinsic v_seq_delay_info member val seq_append_vref = ValRefForIntrinsic v_seq_append_info diff --git a/src/Compiler/TypedTree/TcGlobals.fsi b/src/Compiler/TypedTree/TcGlobals.fsi index a8f1dc89357..8356b16ccfc 100644 --- a/src/Compiler/TypedTree/TcGlobals.fsi +++ b/src/Compiler/TypedTree/TcGlobals.fsi @@ -791,8 +791,6 @@ type internal TcGlobals = member nativeptr_tobyref_vref: TypedTree.ValRef - member nativeptr_stackalloc_vref: TypedTree.ValRef - member new_decimal_info: IntrinsicValRef member new_format_info: IntrinsicValRef diff --git a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs index 0740d201750..5b6e4e9641c 100644 --- a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs +++ b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs @@ -196,8 +196,45 @@ let f () = {handler} |> shouldFail |> withErrorCode 3916 + // A 'let inline' wrapper around 'stackalloc' is inlined into the handler's IL region, so its + // 'localloc' still lands inside the exception region and must be rejected. The pre-codegen syntactic + // check missed this because the wrapper hid the 'stackalloc' call behind an inlinable function. [] - let ``stackalloc in the try body is allowed`` () = + let ``stackalloc via an inline wrapper inside a handler is rejected`` () = + FSharp """ +module Test +open Microsoft.FSharp.NativeInterop +let inline alloc () = NativePtr.stackalloc 1 |> ignore +let f () = try () with _ -> alloc () +""" + |> withNoWarn 9 + |> compile + |> shouldFail + |> withErrorCode 3916 + + // An escaping closure defined in a handler is compiled to its own method, so its 'localloc' lives + // outside the exception region and is legal. Such code must not be rejected (regression guard against + // the pre-codegen syntactic check's false positive). + [] + let ``stackalloc in an escaping closure inside a handler is allowed`` () = + FSharp """ +module Test +open Microsoft.FSharp.NativeInterop +let f () = + try () + with _ -> + let g = fun () -> NativePtr.stackalloc 1 |> ignore + System.Action(g).Invoke() +[] +let main _ = + f () + printfn "ran-closure" + 0 +""" + |> withNoWarn 9 + |> compileExeAndRun + |> shouldSucceed + |> withStdOutContains "ran-closure" FSharp """ module Test open Microsoft.FSharp.NativeInterop From f5245514db5882c1e9fc9e7b7a38cfa277f9468c Mon Sep 17 00:00:00 2001 From: Copilot Date: Tue, 8 Sep 2026 18:18:18 +0200 Subject: [PATCH 7/9] Restore dropped 'stackalloc in the try body is allowed' test header (#20295) The prior commit's test edit stripped the [] let header, orphaning the try-body assertion inside the escaping-closure test and breaking the ComponentTests build with FS0020. Restore it as its own Fact. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Libraries/NativeInterop.fs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs index 5b6e4e9641c..df5f07573e5 100644 --- a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs +++ b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs @@ -235,6 +235,11 @@ let main _ = |> compileExeAndRun |> shouldSucceed |> withStdOutContains "ran-closure" + + // 'localloc' is legal in the protected 'try' body itself (only handler/filter/finally/fault + // regions reject it), so 'stackalloc' directly inside a 'try' must still compile. + [] + let ``stackalloc in the try body is allowed`` () = FSharp """ module Test open Microsoft.FSharp.NativeInterop From f0587a9f973453393aa162d5063f3a87dc50f1b1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 9 Sep 2026 16:08:56 +0000 Subject: [PATCH 8/9] Fix net472 stackalloc test action type Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs index df5f07573e5..593d8ebcf08 100644 --- a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs +++ b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs @@ -224,7 +224,7 @@ let f () = try () with _ -> let g = fun () -> NativePtr.stackalloc 1 |> ignore - System.Action(g).Invoke() + System.Action(g).Invoke() [] let main _ = f () From da86fec1110676f4fad403f29686fce176bf1e08 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Sep 2026 10:34:47 +0000 Subject: [PATCH 9/9] Order explicit type args by constraint dependencies before unifying (#20342) * Order explicit type args by constraint dependencies before unifying A generic value/method with a subtype constraint that references a later type parameter (Register<'a,'b when 'a :> I<'b>>) failed with FS0001 when the argument implements the interface at several instantiations. The explicit type arguments are now unified in dependency order so a parameter referenced by another's constraint is solved first. Fixes #20103 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8ce30fb9-238f-4bb2-8f31-71e8d173c2ca * Address review feedback Add equal-arity competing overloads with explicit selection assertions and explicit/inferred type arguments. Verify dependency ordering and rollback through red-green and a failed-candidate undo mutation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 137c3de0-8937-4b62-aff3-13ce91c4cdcb --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Copilot-Session: 8ce30fb9-238f-4bb2-8f31-71e8d173c2ca Copilot-Session: 137c3de0-8937-4b62-aff3-13ce91c4cdcb --- .../.FSharp.Compiler.Service/11.0.100.md | 3 + docs/release-notes/.FSharp.Core/11.0.100.md | 2 + docs/release-notes/.Language/preview.md | 2 + docs/release-notes/.VisualStudio/18.vNext.md | 1 + eng/Version.Details.props | 10 +- eng/Version.Details.xml | 22 +- eng/common/Get-GitHubAppToken.ps1 | 123 +- eng/common/build.sh | 10 +- eng/common/core-templates/job/job.yml | 12 + eng/common/core-templates/job/onelocbuild.yml | 52 +- .../core-templates/steps/astred-artifacts.yml | 103 ++ .../steps/get-github-app-token.yml | 29 +- eng/common/cross/build-rootfs.sh | 20 +- global.json | 2 +- src/Compiler/Checking/ConstraintSolver.fs | 8 +- .../Checking/Expressions/CheckExpressions.fs | 12 +- src/Compiler/Checking/PostInferenceChecks.fs | 22 + src/Compiler/Checking/SignatureConformance.fs | 15 +- src/Compiler/CodeGen/IlxGen.fs | 37 +- src/Compiler/FSComp.txt | 6 +- src/Compiler/Facilities/LanguageFeatures.fs | 6 + src/Compiler/Facilities/LanguageFeatures.fsi | 2 + src/Compiler/Optimize/Optimizer.fs | 108 +- src/Compiler/TypedTree/TcGlobals.fs | 13 + src/Compiler/TypedTree/TcGlobals.fsi | 4 + src/Compiler/TypedTree/TypedTree.fs | 10 + src/Compiler/TypedTree/TypedTree.fsi | 5 + .../TypedTree/TypedTreeOps.Attributes.fs | 1 + .../TypedTree/TypedTreeOps.ExprOps.fs | 50 + .../TypedTree/TypedTreeOps.ExprOps.fsi | 6 + .../TypedTree/TypedTreeOps.FreeVars.fs | 53 +- .../TypedTree/TypedTreeOps.FreeVars.fsi | 9 +- src/Compiler/TypedTree/WellKnownAttribs.fs | 1 + src/Compiler/TypedTree/WellKnownAttribs.fsi | 1 + src/Compiler/Utilities/illib.fs | 16 + src/Compiler/Utilities/illib.fsi | 5 + src/Compiler/xlf/FSComp.txt.cs.xlf | 20 + src/Compiler/xlf/FSComp.txt.de.xlf | 20 + src/Compiler/xlf/FSComp.txt.es.xlf | 20 + src/Compiler/xlf/FSComp.txt.fr.xlf | 20 + src/Compiler/xlf/FSComp.txt.it.xlf | 20 + src/Compiler/xlf/FSComp.txt.ja.xlf | 20 + src/Compiler/xlf/FSComp.txt.ko.xlf | 20 + src/Compiler/xlf/FSComp.txt.pl.xlf | 20 + src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 20 + src/Compiler/xlf/FSComp.txt.ru.xlf | 20 + src/Compiler/xlf/FSComp.txt.tr.xlf | 20 + src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 20 + src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 20 + src/FSharp.Core/array.fs | 140 +- src/FSharp.Core/array.fsi | 48 +- src/FSharp.Core/list.fs | 204 ++- src/FSharp.Core/list.fsi | 44 +- src/FSharp.Core/prim-types.fs | 5 + src/FSharp.Core/prim-types.fsi | 12 + tests/AheadOfTime/Trimming/check.ps1 | 4 +- .../Signatures/SignatureEnforcedAttributes.fs | 19 + .../TypesAndTypeConstraints.fs | 157 ++ .../EmittedIL/DebugInlineAsCall.fs | 36 +- .../DebugInlineAsCall/Resumable 01.bsl | 101 +- .../DebugInlineAsCall/Resumable 02.bsl | 365 +++- .../DebugInlineAsCall/Resumable 03.bsl | 31 +- .../Resumable 04 - Builder Run is inlined.bsl | 100 ++ ...eCode and partially resolved type args.bsl | 112 +- ...ed trait from composed inline function.bsl | 71 +- ...TLR_MutualInnerRec_StructuralAssertions.fs | 68 + .../EmittedIL/OptimizeClosureIfNotInlined.fs | 248 +++ .../FSharp.Compiler.ComponentTests.fsproj | 1 + .../Language/StateMachineTests.fs | 121 ++ .../Libraries/NativeInterop.fs | 6 +- ...p.Core.SurfaceArea.netstandard20.debug.bsl | 7 + ...Core.SurfaceArea.netstandard20.release.bsl | 7 + ...p.Core.SurfaceArea.netstandard21.debug.bsl | 9 +- ...Core.SurfaceArea.netstandard21.release.bsl | 9 +- .../CodeGen/EmittedIL/TaskGeneratedCode.fs | 1598 ++++++++++++----- .../Navigation/FindUsagesService.fs | 6 +- 76 files changed, 3527 insertions(+), 1043 deletions(-) create mode 100644 eng/common/core-templates/steps/astred-artifacts.yml create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 04 - Builder Run is inlined.bsl create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/OptimizeClosureIfNotInlined.fs diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index f0b26a996be..3eb6652f8fe 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -8,6 +8,7 @@ * Fix Release-only (`--optimize+`) `System.InvalidProgramException` from `Seq.collect` / `yield!` over a value-type (struct) collection implementing `seq<'T>` (e.g. `ImmutableArray<_>`) when materialised with `List.ofSeq` / `Seq.toList` / `Seq.toArray` or a list/array comprehension. The collector lowering now boxes a struct sub-collection to `seq<'T>` before calling `AddMany`/`AddManyAndClose` (matching the coercion the type checker already inserts for `yield!`), and uses `unit` as the try/finally result type instead of the body type (removing a spurious `ldnull` store). ([Issue #20203](https://github.com/dotnet/fsharp/issues/20203)) * Fix recursive inline SRTP resolution being truncated by one currying level (e.g. FSharpPlus `memoizeN`), a regression from the function-domain unification order change in [PR #15181](https://github.com/dotnet/fsharp/pull/15181); the contravariant domain now keeps the inference variable that still carries the pending member constraint. ([PR #20247](https://github.com/dotnet/fsharp/pull/20247)) * Fix exponential (2^N) compile time in pattern matching with shared guards and partial active patterns. ([Issue #18425](https://github.com/dotnet/fsharp/issues/18425), [PR #20244](https://github.com/dotnet/fsharp/pull/20244)) +* Fix incorrect Debug lowering of inline builders that compose low-level resumable state machines. ([Issue #20466](https://github.com/dotnet/fsharp/issues/20466), [PR #20469](https://github.com/dotnet/fsharp/pull/20469)) * Fix incorrect `StructLayout(Size = 1)` emission for data-less struct unions where the compiler-generated tag field makes the actual runtime size larger. ([PR #19759](https://github.com/dotnet/fsharp/pull/19759)) * Fix FS0750 "This construct may only be used within computation expressions" incorrectly raised for `let!`/`use!`/`do!` appearing in the right-hand side of a plain `let` binding inside a computation expression. The right-hand side is now desugared as a nested computation of the same builder whose result is bound with `let!`, keeping its bindings correctly scoped. ([Issue #19457](https://github.com/dotnet/fsharp/issues/19457), [PR #19868](https://github.com/dotnet/fsharp/pull/19868)) * Stop leaking a `System.Diagnostics.Metrics.MeterListener` per `Cache` in DEBUG builds. Each cache created a `CacheMetrics.CacheMetricsListener` (which starts a `MeterListener` registered in the process-global metrics registry) and never disposed it, so listeners accumulated for the lifetime of the process. Because every cache hit/miss/add published to all registered listeners, the per-operation cost grew linearly with the number of leaked listeners, so repeated checks (and Debug FCS test runs) slowed down over time. The per-cache `CacheMetricsListener` and the per-instance `cacheId` tag are removed; `DebugDisplay` and tests now read the existing name-aggregated stats populated by the single `ListenToAll` listener, so no per-cache listener is created and no per-operation cost is added. ([PR #19995](https://github.com/dotnet/fsharp/pull/19995)) @@ -83,6 +84,7 @@ * Fix UoM value type `ToString()` returning garbage values when `--checknulls+` is enabled, caused by double address-taking in codegen. ([Issue #19435](https://github.com/dotnet/fsharp/issues/19435), [PR #19440](https://github.com/dotnet/fsharp/pull/19440)) * Fix accessibility and type-matching for extension method lookups. ([Issue #19349](https://github.com/dotnet/fsharp/issues/19349), [PR #19536](https://github.com/dotnet/fsharp/pull/19536)) * Fix completion inconsistently showing some obsolete members (fields and events) while hiding others (methods and properties). All obsolete members are now consistently hidden by default. ([Issue #13512](https://github.com/dotnet/fsharp/issues/13512), [PR #19506](https://github.com/dotnet/fsharp/pull/19506)) +* Explicit generic type arguments are now unified in constraint-dependency order, so a subtype constraint that references a later type parameter (e.g. `Register<'a, 'b when 'a :> I<'b>>` called as ``) no longer fails with FS0001 when the argument implements the interface at several instantiations. ([Issue #20103](https://github.com/dotnet/fsharp/issues/20103), [PR #20342](https://github.com/dotnet/fsharp/pull/20342)) * Fix O(n) `TypeStructure.GetHashCode` performance regression causing sustained high CPU in IDE mode with generative type providers. ([Issue #18925](https://github.com/dotnet/fsharp/issues/18925), [PR #19369](https://github.com/dotnet/fsharp/pull/19369)) * Fix TypeLoadException when creating delegate with voidptr parameter. (Issue [#11132](https://github.com/dotnet/fsharp/issues/11132), [PR #19338](https://github.com/dotnet/fsharp/pull/19338)) * Suppress tail calls when localloc (NativePtr.stackalloc) is used. (Issue [#13447](https://github.com/dotnet/fsharp/issues/13447), [PR #19338](https://github.com/dotnet/fsharp/pull/19338)) @@ -196,6 +198,7 @@ * IL: use empty tables for members when possible ([PR #20249](https://github.com/dotnet/fsharp/pull/20249)) * Make Entity's adhoc members list lazy ([PR #20286](https://github.com/dotnet/fsharp/pull/20286/changes)) * Constraint solver: `TryD` is now `inline` with `[]` on its always-run continuation, so the argument closures are no longer allocated at the (very hot) constraint-solver call sites; `IgnoreFailedMemberConstraintResolution` is `inline` so its forwarded continuation stays a literal. ([PR #20367](https://github.com/dotnet/fsharp/pull/20367)) +* `[]` adapts opaque callbacks once instead of checking their arity on every call. Lifted recursive methods no longer trigger unrelated file initialization, which could deadlock. ([PR #20422](https://github.com/dotnet/fsharp/pull/20422)) * `DelayedILModuleReader` no longer boxes its cached `ILModuleReader` on every read: the field is typed `ILModuleReader | null` and matched directly. ([PR #20413](https://github.com/dotnet/fsharp/pull/20413)) * Optimizer: passing a partial application of a non-inline module-level function to an `[]` parameter (e.g. `xs |> Option.map (f a b)`) no longer allocates a per-call `FSharpFunc` closure when a captured argument is non-trivial (a field read, a call). Under optimization the argument is eta-expanded to a lambda with its captured evaluations floated above the binding, so the parameter's uses beta-reduce and the closure is eliminated. Captured arguments are still evaluated exactly once, in their original left-to-right order, and the binding keeps its sequence point. Partial applications of inline/SRTP functions and curried members can still allocate closures. ([PR #20487](https://github.com/dotnet/fsharp/pull/20487)) diff --git a/docs/release-notes/.FSharp.Core/11.0.100.md b/docs/release-notes/.FSharp.Core/11.0.100.md index 9a89e373ae1..d5e5bae763d 100644 --- a/docs/release-notes/.FSharp.Core/11.0.100.md +++ b/docs/release-notes/.FSharp.Core/11.0.100.md @@ -1,5 +1,7 @@ ### Fixed +* Add `inline` and `[]` to allocation-free `List` and `Array` higher-order functions (`fold`, `fold2`, `foldBack`, `foldBack2`, `reduce`, `reduceBack`, `iter2`, `iteri`, `iteri2`, `find`, `findIndex`, `findBack`, `findIndexBack`, `pick`, `tryPick`, `exists`, `exists2`, `forall`, `forall2`, `skipWhile`), eliminating the per-call closure allocation when a capturing lambda is passed. Error paths are routed through hidden non-inline helpers so localized exception messages are preserved. ([RFC FS-1115](https://github.com/fsharp/fslang-design/blob/main/RFCs/FS-1115-InlineIfLambda-in-FSharp-Core.md), [PR #20422](https://github.com/dotnet/fsharp/pull/20422)) + * Mirror compiler-semantic attributes (e.g. `[]`, `[]`) in `.fsi` signature files to match `.fs` implementations. ([Issue #19560](https://github.com/dotnet/fsharp/issues/19560), [PR #19880](https://github.com/dotnet/fsharp/pull/19880)) * Fix `Array2D` AOT compatibility: `create`, `init` and `rebase` no longer emit `IL3050`; `map`, `mapi` and `copy` no longer emit it on `net10.0`; the `*Based` operations now warn at the call site before the runtime failure they already had. ([Language Suggestion #1454](https://github.com/fsharp/fslang-suggestions/issues/1454), [PR #20338](https://github.com/dotnet/fsharp/pull/20338)) * Fix `Array.exists2` documentation examples to use equal-length arrays; the previous examples would throw `ArgumentException` at runtime instead of returning the documented `false`/`true` values. ([PR #19672](https://github.com/dotnet/fsharp/pull/19672)) diff --git a/docs/release-notes/.Language/preview.md b/docs/release-notes/.Language/preview.md index d15ec5177c9..0a39bab5fa6 100644 --- a/docs/release-notes/.Language/preview.md +++ b/docs/release-notes/.Language/preview.md @@ -25,6 +25,7 @@ * Warn (FS3884) when a function or delegate value is used as an interpolated string argument, since it will be formatted via `ToString` rather than being applied. ([PR #19289](https://github.com/dotnet/fsharp/pull/19289)) * Added `MethodOverloadsCache` language feature (preview) that caches overload resolution results for repeated method calls, significantly improving compilation performance. ([PR #19072](https://github.com/dotnet/fsharp/pull/19072)) * Added `ErrorOnMissingSignatureAttribute` preview language feature: makes FS3888 (compiler-semantic attribute on the `.fs` but not on the `.fsi`) an error instead of a warning. ([Issue #19560](https://github.com/dotnet/fsharp/issues/19560), [PR #19880](https://github.com/dotnet/fsharp/pull/19880)) +* `[]`, paired with `[]` on a curried arity 2–5 callback of an inlined function, makes the optimizer adapt the callback once via `OptimizedClosures` when it is passed opaquely rather than as a known lambda (feature `OptimizeClosureIfNotInlined`). ([PR #20422](https://github.com/dotnet/fsharp/pull/20422)) * Support common types of `NotNullIfNotNullAttribute` usage. If a method parameter is marked with `NotNullIfNotNullAttribute`, the compiler will now honor this attribute and mark the return type as non-null. ([PR #19977](https://github.com/dotnet/fsharp/pull/19977)) * Spread operator for records ([RFC FS-1151](https://github.com/fsharp/fslang-design/pull/805), [PR #18927](https://github.com/dotnet/fsharp/pull/18927)) * Added `AccessProtectedBaseFieldFromClosure` preview language feature: a derived member can now read a `protected` base-class field from an ordinary closure (lambda, delegate, `async`/`seq`/`lazy`, `function`, or list/array literal), which previously failed with FS1097 even though direct access compiles. Object expressions remain unsupported — bind the field to a local function or expose it through a member. ([Issue #5302](https://github.com/dotnet/fsharp/issues/5302)) @@ -35,6 +36,7 @@ ### Fixed +* Explicit generic type arguments are now unified in constraint-dependency order, so a subtype constraint that references a later type parameter (e.g. `Register<'a, 'b when 'a :> I<'b>>` called as ``) no longer fails with FS0001 when the argument implements the interface at several instantiations. ([Issue #20103](https://github.com/dotnet/fsharp/issues/20103), [PR #20342](https://github.com/dotnet/fsharp/pull/20342)) * Bitwise operators (`|||`, `&&&`, `^^^`) on enums whose underlying type is not an integer type (e.g. `char`) are now a compile-time error (FS0001, consistent with `~~~`, `<<<`, `>>>`) instead of a runtime `NotSupportedException`. ([Issue #11785](https://github.com/dotnet/fsharp/issues/11785), [PR #20322](https://github.com/dotnet/fsharp/pull/20322)) ### Changed diff --git a/docs/release-notes/.VisualStudio/18.vNext.md b/docs/release-notes/.VisualStudio/18.vNext.md index ba03f663967..4a00e4c91a2 100644 --- a/docs/release-notes/.VisualStudio/18.vNext.md +++ b/docs/release-notes/.VisualStudio/18.vNext.md @@ -22,3 +22,4 @@ * Unused analyzers: disable in VS when file has errors ([PR #19892](https://github.com/dotnet/fsharp/pull/19892)) * Move to Roslyn's unified ExternalAccess library ([PR #20099](https://github.com/dotnet/fsharp/pull/20099)) * Remove trailing whitespace from source files. No functional change: whitespace inside string literals and inactive `#if` regions is preserved. ([PR #20355](https://github.com/dotnet/fsharp/pull/20355)) +* `FSharpFindUsagesService.onSymbolFound` looks up a reference's definition item with `voption` instead of `option`. No functional change. ([PR #20534](https://github.com/dotnet/fsharp/pull/20534)) diff --git a/eng/Version.Details.props b/eng/Version.Details.props index 4d5faf033c2..c504d4076db 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -6,12 +6,12 @@ This file should be imported by eng/Versions.props - 11.0.0-beta.26456.1 + 11.0.0-beta.26461.5 - 18.12.0-1.26454.5 - 18.12.0-1.26454.5 - 18.12.0-1.26454.5 - 18.12.0-1.26454.5 + 18.12.0-1.26461.2 + 18.12.0-1.26461.2 + 18.12.0-1.26461.2 + 18.12.0-1.26461.2 1.0.0-prerelease.26451.1 1.0.0-prerelease.26451.1 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9e4b828d967..d5073d709aa 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,22 +1,22 @@ - + - + https://github.com/dotnet/msbuild - fcb368d8894f6448382f20304c659f383d210f61 + 5ee62bf0fa0db8677723d09c3481bfde5fe0fbf7 - + https://github.com/dotnet/msbuild - fcb368d8894f6448382f20304c659f383d210f61 + 5ee62bf0fa0db8677723d09c3481bfde5fe0fbf7 - + https://github.com/dotnet/msbuild - fcb368d8894f6448382f20304c659f383d210f61 + 5ee62bf0fa0db8677723d09c3481bfde5fe0fbf7 - + https://github.com/dotnet/msbuild - fcb368d8894f6448382f20304c659f383d210f61 + 5ee62bf0fa0db8677723d09c3481bfde5fe0fbf7 https://github.com/dotnet/roslyn @@ -82,9 +82,9 @@ - + https://github.com/dotnet/arcade - 66b75e61d883abd9e3af86a811c3809a8d9142ca + 1574a0ce35761b7ce5e783074cc2f9567d278396 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/common/Get-GitHubAppToken.ps1 b/eng/common/Get-GitHubAppToken.ps1 index ea776bd6bc2..ec005e487c3 100644 --- a/eng/common/Get-GitHubAppToken.ps1 +++ b/eng/common/Get-GitHubAppToken.ps1 @@ -1,13 +1,11 @@ # Mints a short-lived GitHub App installation access token by signing a JWT -# with a private key stored in Azure Key Vault (RSA, RS256). The signed JWT is -# exchanged with the GitHub API for a token scoped to a single installation. +# with an RSA private key (RS256). The signed JWT is exchanged with the GitHub +# API for a token scoped to a single installation. # # Requirements: -# - A GitHub App whose private key has been uploaded into Key Vault as an RSA -# key (the PEM converted to a Key Vault *key*, NOT stored as a secret). -# - The caller (the federated Azure service connection used to run this script) -# must have the `Key Vault Crypto User` role (or at minimum the `Sign` -# action) on that key. +# - A GitHub App ID and PEM private key stored as Azure Key Vault secrets. +# - The federated Azure service connection running this script must have +# `Get` access to those two secrets. # - The App must be installed on the target organization/account # (`InstallationOwner`) with the permissions/repositories it needs. # @@ -16,17 +14,17 @@ [CmdletBinding()] param( - # Name of the Key Vault that holds the GitHub App's RSA signing key. + # Name of the Key Vault holding the GitHub App credentials. [Parameter(Mandatory = $true)] [string] $KeyVaultName, - # Name of the RSA key inside the Key Vault (the App's private key). + # Secret Manager projection containing the GitHub App ID. [Parameter(Mandatory = $true)] - [string] $KeyName, + [string] $AppIdSecretName, - # The GitHub App's Client ID (the value to put in the `iss` JWT claim). + # Secret Manager projection containing the PEM private key. [Parameter(Mandatory = $true)] - [string] $AppClientId, + [string] $AppPrivateKeySecretName, # Login of the organization or user account whose installation we should # mint the token for (e.g. `dotnet`, `microsoft`). @@ -39,16 +37,69 @@ param( [Parameter(Mandatory = $false)] [string] $OutputVariableName ) - $ErrorActionPreference = 'Stop' $PSNativeCommandUseErrorActionPreference = $true . $PSScriptRoot\pipeline-logging-functions.ps1 +if ($KeyVaultName -notmatch '^[A-Za-z][A-Za-z0-9-]{1,22}[A-Za-z0-9]$' -or $KeyVaultName.Contains('--')) { + Write-PipelineTelemetryError -Category 'Build' -Message "KeyVaultName '$KeyVaultName' is not a valid Azure Key Vault name." + exit 1 +} + function ConvertTo-Base64Url([byte[]] $bytes) { return [Convert]::ToBase64String($bytes).TrimEnd('=').Replace('+', '-').Replace('/', '_') } +$previousNativeCommandErrorPreference = $PSNativeCommandUseErrorActionPreference +try { + # Azure CLI can emit non-fatal Python warnings to stderr. + $PSNativeCommandUseErrorActionPreference = $false + $keyVaultAccessToken = az account get-access-token ` + --resource https://vault.azure.net ` + --query accessToken ` + --output tsv ` + --only-show-errors + $tokenExitCode = $LASTEXITCODE +} +catch { + Write-PipelineTelemetryError -Category 'Build' -Message "Failed to acquire an Azure Key Vault access token: $_" + exit 1 +} +finally { + $PSNativeCommandUseErrorActionPreference = $previousNativeCommandErrorPreference +} +if ($tokenExitCode -ne 0 -or [string]::IsNullOrWhiteSpace($keyVaultAccessToken)) { + Write-PipelineTelemetryError -Category 'Build' -Message "'az account get-access-token' exited with code $tokenExitCode while acquiring an Azure Key Vault access token." + exit 1 +} + +function Get-KeyVaultSecret([string] $SecretName) { + # Use the data-plane REST API because `az keyvault secret show` can fail + # with Errno 22 on hosted Windows agents when reading these projections. + $escapedSecretName = [Uri]::EscapeDataString($SecretName) + $secretUri = "https://$KeyVaultName.vault.azure.net/secrets/$escapedSecretName`?api-version=7.4" + try { + $response = Invoke-RestMethod ` + -Uri $secretUri ` + -Headers @{ Authorization = "Bearer $keyVaultAccessToken" } ` + -Method Get + } + catch { + Write-PipelineTelemetryError -Category 'Build' -Message "Failed to read secret '$SecretName' from vault '$KeyVaultName': $_. Verify the secret exists and the service connection has 'Key Vault Secrets User' access to it." + exit 1 + } + if ([string]::IsNullOrWhiteSpace($response.value)) { + Write-PipelineTelemetryError -Category 'Build' -Message "Secret '$SecretName' in vault '$KeyVaultName' is empty." + exit 1 + } + return [string] $response.value +} + +Write-Host "Reading GitHub App credentials from vault '$KeyVaultName'..." +$appId = Get-KeyVaultSecret $AppIdSecretName +$privateKey = Get-KeyVaultSecret $AppPrivateKeySecretName + # Build JWT header and payload. Use [ordered] hashtables so JSON # serialization is deterministic. $jwtHeader = [ordered]@{ @@ -59,46 +110,38 @@ $now = [System.DateTimeOffset]::UtcNow $jwtPayload = [ordered]@{ iat = $now.AddMinutes(-1).ToUnixTimeSeconds() exp = $now.AddMinutes(5).ToUnixTimeSeconds() - iss = $AppClientId + iss = $appId } $headerEncoded = ConvertTo-Base64Url ([System.Text.Encoding]::UTF8.GetBytes(($jwtHeader | ConvertTo-Json -Compress))) $payloadEncoded = ConvertTo-Base64Url ([System.Text.Encoding]::UTF8.GetBytes(($jwtPayload | ConvertTo-Json -Compress))) $signingInput = "$headerEncoded.$payloadEncoded" -# Key Vault `sign` expects the *digest* (base64), not the raw bytes. -$sha256 = [System.Security.Cryptography.SHA256]::Create() -$digestBytes = $sha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($signingInput)) -$digestBase64 = [Convert]::ToBase64String($digestBytes) +$sha256 = [System.Security.Cryptography.SHA256]::Create() +try { + $digestBytes = $sha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($signingInput)) +} +finally { + $sha256.Dispose() +} -Write-Host "Signing JWT with key '$KeyName' in vault '$KeyVaultName'..." -$previousNativeCommandErrorPreference = $PSNativeCommandUseErrorActionPreference +Write-Host 'Signing JWT with the GitHub App private key...' +$rsa = [System.Security.Cryptography.RSA]::Create() try { - # Azure CLI can emit non-fatal Python warnings to stderr even when signing succeeds. - # Use the exit code to determine success for this invocation. - $PSNativeCommandUseErrorActionPreference = $false - $signatureBase64 = az keyvault key sign ` - --vault-name $KeyVaultName ` - --name $KeyName ` - --algorithm RS256 ` - --digest $digestBase64 ` - --query signature ` - --output tsv ` - --only-show-errors - $signExitCode = $LASTEXITCODE + $rsa.ImportFromPem($privateKey) + $signatureBytes = $rsa.SignHash( + $digestBytes, + [System.Security.Cryptography.HashAlgorithmName]::SHA256, + [System.Security.Cryptography.RSASignaturePadding]::Pkcs1) + $signatureUrl = ConvertTo-Base64Url $signatureBytes } catch { - Write-PipelineTelemetryError -Category 'Build' -Message "Failed to sign the JWT via Key Vault (key '$KeyName', vault '$KeyVaultName'): $_. Verify the service connection identity has the 'Key Vault Crypto User' role (Sign action) on the key." + Write-PipelineTelemetryError -Category 'Build' -Message "Failed to sign the GitHub App JWT with the supplied private key: $_" exit 1 } finally { - $PSNativeCommandUseErrorActionPreference = $previousNativeCommandErrorPreference -} -if ($signExitCode -ne 0 -or [string]::IsNullOrWhiteSpace($signatureBase64)) { - Write-PipelineTelemetryError -Category 'Build' -Message "'az keyvault key sign' exited with code $signExitCode for key '$KeyName' in vault '$KeyVaultName'. Verify the service connection identity has the 'Key Vault Crypto User' role (Sign action) on the key." - exit 1 + $rsa.Dispose() } -$signatureUrl = $signatureBase64.Trim().TrimEnd('=').Replace('+', '-').Replace('/', '_') $jwt = "$signingInput.$signatureUrl" $headers = @{ @@ -126,7 +169,7 @@ try { } while ($pageInstallationCount -eq 100) } catch { - Write-PipelineTelemetryError -Category 'Build' -Message "Failed to list GitHub App installations: $_. The signed JWT may be invalid or the App's Client ID ('$AppClientId') may be incorrect." + Write-PipelineTelemetryError -Category 'Build' -Message "Failed to list GitHub App installations: $_. The signed JWT may be invalid or the App ID may be incorrect." exit 1 } $matchingInstallations = @($installations | Where-Object { $_.account.login -ieq $InstallationOwner }) diff --git a/eng/common/build.sh b/eng/common/build.sh index 109d83ff73f..f65b048aa87 100755 --- a/eng/common/build.sh +++ b/eng/common/build.sh @@ -254,7 +254,7 @@ function Build { properties+=("/p:Projects=$projects") fi - local bl="" + local bl=() if [[ "$binary_log" == true ]]; then local binary_log_path="" if [[ -z "$binary_log_name" ]]; then @@ -266,7 +266,7 @@ function Build { fi mkdir -p "$(dirname "$binary_log_path")" - bl="/bl:\"$binary_log_path\"" + bl=("/bl:$binary_log_path") fi local check="" @@ -274,8 +274,8 @@ function Build { check="/check" fi - MSBuild $_InitializeToolset \ - $bl \ + MSBuild "$_InitializeToolset" \ + ${bl[@]+"${bl[@]}"} \ $check \ /p:Configuration=$configuration \ /p:RepoRoot="$repo_root" \ @@ -299,7 +299,7 @@ function Build { if [[ "$clean" == true ]]; then if [ -d "$artifacts_dir" ]; then - rm -rf $artifacts_dir + rm -rf "$artifacts_dir" echo "Artifacts directory deleted." fi exit 0 diff --git a/eng/common/core-templates/job/job.yml b/eng/common/core-templates/job/job.yml index cb60f529784..2716ecd18fb 100644 --- a/eng/common/core-templates/job/job.yml +++ b/eng/common/core-templates/job/job.yml @@ -28,6 +28,7 @@ parameters: enablePublishTestResults: false enablePublishing: false enableBuildRetry: false + enableAstred: false mergeTestResults: false testRunTitle: '' testResultsFormat: '' @@ -119,6 +120,12 @@ jobs: - name: ${{ pair.key }} value: ${{ pair.value }} + - ${{ if and(eq(parameters.enableAstred, true), eq(parameters.runAsPublic, 'false'), eq(variables['System.TeamProject'], 'internal'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - name: MSBUILDDEBUGENGINE + value: 1 + - name: MSBUILDDEBUGPATH + value: $(Build.ArtifactStagingDirectory)/AstredCapture/binlogs + # DotNet-HelixApi-Access provides 'HelixApiAccessToken' for internal builds - ${{ if and(eq(parameters.enableTelemetry, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - group: DotNet-HelixApi-Access @@ -236,3 +243,8 @@ jobs: condition: always() - ${{ each step in parameters.artifactPublishSteps }}: - ${{ step }} + + - ${{ if and(eq(parameters.enableAstred, true), eq(parameters.runAsPublic, 'false'), eq(variables['System.TeamProject'], 'internal'), notin(variables['Build.Reason'], 'PullRequest')) }}: + - template: /eng/common/core-templates/steps/astred-artifacts.yml + parameters: + binlogDir: $(MSBUILDDEBUGPATH) diff --git a/eng/common/core-templates/job/onelocbuild.yml b/eng/common/core-templates/job/onelocbuild.yml index e4e6b77fc36..b772dc57880 100644 --- a/eng/common/core-templates/job/onelocbuild.yml +++ b/eng/common/core-templates/job/onelocbuild.yml @@ -5,23 +5,14 @@ parameters: # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool pool: '' - CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex - GithubPat: $(BotAccount-dotnet-bot-repo-PAT) - - # Service connection for WIF-based Entra authentication to ceapex feeds (replaces CeapexPat). - # dnceng/internal and DevDiv/DevDiv have same-named, project-scoped connections. Other projects, - # and any pipeline that sets this to '', fall back to PAT-based auth via the CeapexPat parameter. + # Project-scoped WIF service connection for Ceapex feed authentication. CeapexServiceConnection: 'dnceng-onelocbuild-ceapex' # GitHub App authentication for the OneLoc check-in PR. - # dnceng/internal and DevDiv/DevDiv are enabled by default with their project-scoped service - # connections. Other projects must explicitly opt in after provisioning equivalent infrastructure. - UseGitHubAppAuthentication: true - UseGitHubAppAuthenticationInOtherProjects: false GitHubAppServiceConnection: 'dnceng-oneloc-githubapp' - GitHubAppClientId: 'Iv23lijBU8x3gc9lDOc9' GitHubAppKeyVaultName: 'EngKeyVault' - GitHubAppKeyName: 'oneloc-localization-app-key' + GitHubAppIdSecretName: 'oneloc-localization-app-app-id' + GitHubAppPrivateKeySecretName: 'oneloc-localization-app-app-private-key' SourcesDirectory: $(System.DefaultWorkingDirectory) CreatePr: true @@ -49,7 +40,6 @@ jobs: displayName: OneLocBuild${{ parameters.JobNameSuffix }} variables: - - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat - name: _GenerateLocProjectArguments value: -SourcesDirectory ${{ parameters.SourcesDirectory }} -LanguageSet "${{ parameters.LanguageSet }}" @@ -80,6 +70,10 @@ jobs: steps: - ${{ if eq(parameters.is1ESPipeline, '') }}: - 'Illegal entry point, is1ESPipeline is not defined. Repository yaml should not directly reference templates in core-templates folder.': error + - ${{ if notIn(variables['System.TeamProject'], 'internal', 'DevDiv') }}: + - 'OneLocBuild is supported only in dnceng/internal and DevDiv/DevDiv.': error + - ${{ if eq(parameters.CeapexServiceConnection, '') }}: + - 'CeapexServiceConnection must identify a WIF service connection.': error - ${{ if ne(parameters.SkipLocProjectJsonGeneration, 'true') }}: - task: Powershell@2 @@ -89,17 +83,15 @@ jobs: displayName: Generate LocProject.json condition: ${{ parameters.condition }} - # Acquire an Entra token for ceapex feed access in the supported internal and DevDiv projects. - - ${{ if and(ne(parameters.CeapexServiceConnection, ''), or(eq(variables['System.TeamProject'], 'internal'), eq(variables['System.TeamProject'], 'DevDiv'))) }}: - - template: /eng/common/templates/steps/get-federated-access-token.yml - parameters: - federatedServiceConnection: ${{ parameters.CeapexServiceConnection }} - outputVariableName: 'CeapexEntraToken' - condition: ${{ parameters.condition }} + # Acquire a short-lived Entra token for Ceapex feed access. + - template: /eng/common/templates/steps/get-federated-access-token.yml + parameters: + federatedServiceConnection: ${{ parameters.CeapexServiceConnection }} + outputVariableName: 'CeapexEntraToken' + condition: ${{ parameters.condition }} - # Mint a short-lived GitHub App installation token for the loc check-in PR. Use the connection - # provisioned in each supported project; other projects must explicitly opt in and override it. - - ${{ if and(eq(parameters.RepoType, 'gitHub'), eq(parameters.UseGitHubAppAuthentication, true), or(eq(variables['System.TeamProject'], 'internal'), eq(variables['System.TeamProject'], 'DevDiv'), eq(parameters.UseGitHubAppAuthenticationInOtherProjects, true))) }}: + # Mint a short-lived GitHub App installation token for the loc check-in PR. + - ${{ if eq(parameters.RepoType, 'gitHub') }}: - template: /eng/common/core-templates/steps/get-github-app-token.yml parameters: is1ESPipeline: ${{ parameters.is1ESPipeline }} @@ -108,8 +100,8 @@ jobs: ${{ else }}: azureSubscription: ${{ parameters.GitHubAppServiceConnection }} keyVaultName: ${{ parameters.GitHubAppKeyVaultName }} - keyName: ${{ parameters.GitHubAppKeyName }} - appClientId: ${{ parameters.GitHubAppClientId }} + appIdSecretName: ${{ parameters.GitHubAppIdSecretName }} + appPrivateKeySecretName: ${{ parameters.GitHubAppPrivateKeySecretName }} installationOwner: ${{ parameters.GitHubOrg }} outputVariableName: 'GitHubAppInstallationToken' condition: ${{ parameters.condition }} @@ -129,16 +121,10 @@ jobs: isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }} isShouldReusePrSelected: ${{ parameters.ReusePr }} packageSourceAuth: patAuth - ${{ if and(ne(parameters.CeapexServiceConnection, ''), or(eq(variables['System.TeamProject'], 'internal'), eq(variables['System.TeamProject'], 'DevDiv'))) }}: - patVariable: $(CeapexEntraToken) - ${{ if or(eq(parameters.CeapexServiceConnection, ''), and(ne(variables['System.TeamProject'], 'internal'), ne(variables['System.TeamProject'], 'DevDiv'))) }}: - patVariable: ${{ parameters.CeapexPat }} + patVariable: $(CeapexEntraToken) ${{ if eq(parameters.RepoType, 'gitHub') }}: repoType: ${{ parameters.RepoType }} - ${{ if and(eq(parameters.UseGitHubAppAuthentication, true), or(eq(variables['System.TeamProject'], 'internal'), eq(variables['System.TeamProject'], 'DevDiv'), eq(parameters.UseGitHubAppAuthenticationInOtherProjects, true))) }}: - gitHubPatVariable: "$(GitHubAppInstallationToken)" - ${{ else }}: - gitHubPatVariable: "${{ parameters.GithubPat }}" + gitHubPatVariable: "$(GitHubAppInstallationToken)" ${{ if ne(parameters.MirrorRepo, '') }}: isMirrorRepoSelected: true gitHubOrganization: ${{ parameters.GitHubOrg }} diff --git a/eng/common/core-templates/steps/astred-artifacts.yml b/eng/common/core-templates/steps/astred-artifacts.yml new file mode 100644 index 00000000000..b914082f58b --- /dev/null +++ b/eng/common/core-templates/steps/astred-artifacts.yml @@ -0,0 +1,103 @@ +# Astred footer for producing and uploading a portable digest. +# The calling job must configure its header before any build steps run: +# MSBUILDDEBUGENGINE=1 +# MSBUILDDEBUGPATH= +parameters: +- name: sourcesPath + type: string + default: $(Build.SourcesDirectory) +- name: binlogDir + type: string + default: $(Build.ArtifactStagingDirectory)/AstredCapture/binlogs +- name: capturePath + type: string + default: $(Build.ArtifactStagingDirectory)/AstredCapture + +steps: +- task: AstredInstaller@0 + displayName: Install Astred CLI + inputs: + Version: '2.14.1' + FeedUrl: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet-internal-FoSSE/nuget/v3/index.json' + +- pwsh: | + $ErrorActionPreference = 'Continue' + $apjOut = Join-Path $env:ASTRED_CAPTURE_PATH 'apj' + New-Item -ItemType Directory -Force -Path $apjOut | Out-Null + + $binlogs = Get-ChildItem -Path $env:ASTRED_BINLOG_DIR -Recurse -Force -Filter *.binlog ` + -ErrorAction SilentlyContinue + if (-not $binlogs) { + Write-Host "##vso[task.logissue type=warning]No binlogs found in $env:ASTRED_BINLOG_DIR. Check the calling job's Astred header configuration for MSBUILDDEBUGENGINE / MSBuildDebugEngine and MSBUILDDEBUGPATH." + exit 0 + } + + $project = Join-Path $apjOut '.astred.project.json' + $binlogPaths = @($binlogs.FullName) + Write-Host "astproj: processing $($binlogPaths.Count) binlog(s)" + astred astproj -nofolders @binlogPaths "-o:$project" + if ($LASTEXITCODE -ne 0) { + Write-Host "##vso[task.logissue type=warning]astproj failed (exit $LASTEXITCODE)" + } + displayName: Generate Astred Project Files + workingDirectory: ${{ parameters.sourcesPath }} + env: + ASTRED_BINLOG_DIR: ${{ parameters.binlogDir }} + ASTRED_CAPTURE_PATH: ${{ parameters.capturePath }} + condition: succeededOrFailed() + continueOnError: true + +- pwsh: | + $ErrorActionPreference = 'Continue' + $apjDir = Join-Path $env:ASTRED_CAPTURE_PATH 'apj' + $uploadRoot = Join-Path $env:ASTRED_CAPTURE_PATH 'upload' + $project = Join-Path $apjDir '.astred.project.json' + + if (-not (Test-Path $project)) { + Write-Host "##vso[task.logissue type=warning]No Astred project file was produced." + exit 0 + } + + $digest = Join-Path $apjDir '.astred.digest.zip' + Remove-Item $digest -ErrorAction SilentlyContinue + astred "-repo:$env:ASTRED_SOURCES_PATH" "-project:$project" -digest + if ($LASTEXITCODE -eq 0 -and (Test-Path $digest)) { + $commitTimeText = & git -C $env:ASTRED_SOURCES_PATH show -s --format=%cI $env:BUILD_SOURCEVERSION + if ($LASTEXITCODE -ne 0) { + throw "Could not read the commit timestamp for $env:BUILD_SOURCEVERSION." + } + + $commitTime = [DateTimeOffset]::Parse( + $commitTimeText.Trim(), + [Globalization.CultureInfo]::InvariantCulture) + $eventFolder = '{0}_{1}' -f ` + $commitTime.UtcDateTime.ToString('yyyy-MM-ddTHH-mm-ssZ'), ` + $env:BUILD_SOURCEVERSION + $targetDir = Join-Path (Join-Path $uploadRoot 'AST') $eventFolder + $target = Join-Path $targetDir '.astred.digest.zip' + New-Item -ItemType Directory -Force -Path $targetDir | Out-Null + Move-Item $digest $target -Force + Write-Host "Prepared Astred digest: $target" + Write-Host "##vso[task.setvariable variable=ASTRED_DIGEST_READY]true" + } + elseif ($LASTEXITCODE -ne 0) { + Write-Host "##vso[task.logissue type=warning]Digest generation failed for $project (exit $LASTEXITCODE)" + Remove-Item $digest -ErrorAction SilentlyContinue + } + else { + Write-Host "##vso[task.logissue type=warning]Digest not produced for $project" + } + displayName: Package Portable Astred Digests + env: + ASTRED_SOURCES_PATH: ${{ parameters.sourcesPath }} + ASTRED_CAPTURE_PATH: ${{ parameters.capturePath }} + condition: succeededOrFailed() + continueOnError: true + +- task: UploadAstred@0 + displayName: Upload Digest to Astred + condition: and(succeededOrFailed(), eq(variables['ASTRED_DIGEST_READY'], 'true')) + inputs: + SourcePath: ${{ parameters.capturePath }}/upload + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) diff --git a/eng/common/core-templates/steps/get-github-app-token.yml b/eng/common/core-templates/steps/get-github-app-token.yml index 6d42a48d3c3..3eeb5a4c1bc 100644 --- a/eng/common/core-templates/steps/get-github-app-token.yml +++ b/eng/common/core-templates/steps/get-github-app-token.yml @@ -1,13 +1,11 @@ # Mints a short-lived GitHub App installation access token by signing a JWT -# with a private key stored in Azure Key Vault (RSA, RS256). The JWT is -# exchanged with the GitHub API for a token scoped to a single installation. +# with an RSA private key (RS256). The JWT is exchanged with the GitHub API +# for a token scoped to a single installation. # # Requirements (per GitHub App you want to authenticate as): -# - A GitHub App with its private key uploaded into Key Vault as an RSA key -# (PEM converted to a key, NOT stored as a secret). -# - The Azure service connection passed via `azureSubscription` must be -# granted the `Key Vault Crypto User` role (or at minimum `Sign` action) -# on that key. +# - A GitHub App ID and PEM private key stored as Azure Key Vault secrets. +# - The Azure service connection passed via `azureSubscription` must have +# `Get` access to those two secrets. # - The App must be installed on the target organization/account # (`installationOwner`) with the permissions/repositories you need. # @@ -17,23 +15,18 @@ # enterprise classic-PAT lifetime policy. parameters: -# Azure DevOps service connection (federated) that can call -# `az keyvault key sign` on the App's signing key. +# Azure DevOps service connection (federated) that can read the App credentials. - name: azureSubscription type: string -# Name of the Key Vault that holds the GitHub App's RSA signing key. +# Name of the Key Vault holding Secret Manager's github-app-secret projections. - name: keyVaultName type: string -# Name of the RSA key inside the Key Vault (the App's private key). -- name: keyName +- name: appIdSecretName type: string -# The GitHub App's Client ID (the value to put in the `iss` JWT claim). -# Prefer this over the numeric App ID; GitHub accepts either, but Client ID -# is the documented form going forward. -- name: appClientId +- name: appPrivateKeySecretName type: string # Login of the organization or user account whose installation we should @@ -73,7 +66,7 @@ steps: inlineScript: | & "$(System.DefaultWorkingDirectory)/eng/common/Get-GitHubAppToken.ps1" ` -KeyVaultName '${{ parameters.keyVaultName }}' ` - -KeyName '${{ parameters.keyName }}' ` - -AppClientId '${{ parameters.appClientId }}' ` + -AppIdSecretName '${{ parameters.appIdSecretName }}' ` + -AppPrivateKeySecretName '${{ parameters.appPrivateKeySecretName }}' ` -InstallationOwner '${{ parameters.installationOwner }}' ` -OutputVariableName '${{ parameters.outputVariableName }}' diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh index f58abbd2d10..3fea306bc2a 100755 --- a/eng/common/cross/build-rootfs.sh +++ b/eng/common/cross/build-rootfs.sh @@ -532,27 +532,33 @@ ensureDownloadTool() } if [[ "$__CodeName" == "alpine" ]]; then - __ApkToolsVersion=2.12.11 + __ApkToolsVersion=2.14.4-r1 __ApkToolsDir="$(mktemp -d)" __ApkKeysDir="$(mktemp -d)" arch="$(uname -m)" __AlpineRepo="${__AlpineRepoOverride:-https://dl-cdn.alpinelinux.org/alpine}" ensureDownloadTool + __ApkToolsPackage="$__ApkToolsDir/apk-tools-static.apk" + __ApkToolsUrl="$__AlpineRepo/v3.20/main/$arch/apk-tools-static-$__ApkToolsVersion.apk" if [[ "$__hasWget" == 1 ]]; then - wget -P "$__ApkToolsDir" "https://gitlab.alpinelinux.org/api/v4/projects/5/packages/generic/v$__ApkToolsVersion/$arch/apk.static" + wget -O "$__ApkToolsPackage" "$__ApkToolsUrl" else - curl -SLO --create-dirs --output-dir "$__ApkToolsDir" "https://gitlab.alpinelinux.org/api/v4/projects/5/packages/generic/v$__ApkToolsVersion/$arch/apk.static" + curl -fSL -o "$__ApkToolsPackage" "$__ApkToolsUrl" fi + if [[ "$arch" == "x86_64" ]]; then - __ApkToolsSHA512SUM="53e57b49230da07ef44ee0765b9592580308c407a8d4da7125550957bb72cb59638e04f8892a18b584451c8d841d1c7cb0f0ab680cc323a3015776affaa3be33" + __ApkToolsSHA512SUM="b1b3cc382aa0ec26a2c24b742701a1f9885d0678365f9aea15d3d005926b06ecc802659cec8a7deba2717af99c19c708a17c23e1f0f07742268ee5be5400eb9e" elif [[ "$arch" == "aarch64" ]]; then - __ApkToolsSHA512SUM="9e2b37ecb2b56c05dad23d379be84fd494c14bd730b620d0d576bda760588e1f2f59a7fcb2f2080577e0085f23a0ca8eadd993b4e61c2ab29549fdb71969afd0" + __ApkToolsSHA512SUM="61f9a636c5ac4e96e7a3f69fd65e60fc57b3ec8b23619c4df86f59b89e71d1309b3e406388945bdf0dd9168dac22df376943a70ff3efa179e5687e586f825fb0" else - echo "WARNING: add missing hash for your host architecture. To find the value, use: 'find /tmp -name apk.static -exec sha512sum {} \;'" + >&2 echo "ERROR: Unsupported apk-tools-static host architecture '$arch'." + exit 1 fi - echo "$__ApkToolsSHA512SUM $__ApkToolsDir/apk.static" | sha512sum -c + echo "$__ApkToolsSHA512SUM $__ApkToolsPackage" | sha512sum -c + tar -xzf "$__ApkToolsPackage" -C "$__ApkToolsDir" --strip-components=1 sbin/apk.static + rm "$__ApkToolsPackage" chmod +x "$__ApkToolsDir/apk.static" if [[ "$__AlpineVersion" == "edge" ]]; then diff --git a/global.json b/global.json index 95aa20484c2..bb95498950f 100644 --- a/global.json +++ b/global.json @@ -23,7 +23,7 @@ "xcopy-msbuild": "18.0.0" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "11.0.0-beta.26456.1", + "Microsoft.DotNet.Arcade.Sdk": "11.0.0-beta.26461.5", "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23255.2" } } diff --git a/src/Compiler/Checking/ConstraintSolver.fs b/src/Compiler/Checking/ConstraintSolver.fs index c90e64e0c94..a24f8a9e636 100644 --- a/src/Compiler/Checking/ConstraintSolver.fs +++ b/src/Compiler/Checking/ConstraintSolver.fs @@ -3286,7 +3286,13 @@ and CanMemberSigsMatchUpToCheck if minst.Length <> uminst.Length then return! ErrorD(Error(FSComp.SR.csTypeInstantiationLengthMismatch(), m)) else - let! usesTDC1 = MapCombineTDC2D unifyTypes minst uminst + let! usesTDC1 = + let tyargPairs = + let pairs = List.zip minst uminst + if g.langVersion.SupportsFeature LanguageFeature.TypeArgumentDependencyOrdering then + reorderTyArgsByConstraintDependencies g pairs + else pairs + tyargPairs |> MapCombineTDCD (fun (formalTy, callerTy) -> unifyTypes formalTy callerTy) let! usesTDC2 = if not (permitOptArgs || isNil unnamedCalledOptArgs) then ErrorD(Error(FSComp.SR.csOptionalArgumentNotPermittedHere(), m)) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index fb2ddc9b18d..47b5164d5bf 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -2882,7 +2882,12 @@ let TcVal (cenv: cenv) env (tpenv: UnscopedTyparEnv) (vref: ValRef) instantiatio if tpTys.Length <> tinst.Length then error(Error(FSComp.SR.tcTypeParameterArityMismatch(tps.Length, tinst.Length), m)) - List.iter2 (UnifyTypes cenv env m) tpTys tinst + let tyargPairs = + let pairs = List.zip tpTys tinst + if g.langVersion.SupportsFeature LanguageFeature.TypeArgumentDependencyOrdering then + reorderTyArgsByConstraintDependencies g pairs + else pairs + tyargPairs |> List.iter (fun (formalTy, actualTy) -> UnifyTypes cenv env m formalTy actualTy) TcValEarlyGeneralizationConsistencyCheck cenv env (v, valRecInfo, tinst, vTy, vTauTy, m) @@ -6706,7 +6711,10 @@ and TcIteratedLambdas (cenv: cenv) isFirst (env: TcEnv) overallTy takenNames tpe v.SetArgReprInfoForDisplay (Some argInfo) let inlineIfLambda = ArgReprInfoHasWellKnownAttribute g WellKnownValAttributes.InlineIfLambdaAttribute argInfo if inlineIfLambda then - v.SetInlineIfLambda()) + v.SetInlineIfLambda() + let optimizeClosureIfNotInlined = ArgReprInfoHasWellKnownAttribute g WellKnownValAttributes.OptimizeClosureIfNotInlinedAttribute argInfo + if optimizeClosureIfNotInlined then + v.SetOptimizeClosureIfNotInlined()) { envinner with eLambdaArgInfos = rest } | [] -> envinner diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index d74aa8ff998..06753589470 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -2181,9 +2181,29 @@ and CheckValInfo cenv env (ValReprInfo(_, args, ret)) = and CheckArgInfo cenv env (argInfo : ArgReprInfo) = CheckAttribs cenv env (argInfo.Attribs.AsList()) +// Reject the attribute where the optimizer cannot act on it (see AdaptOpaqueOptimizedClosureArgs). +and CheckOptimizeClosureIfNotInlinedAttribute cenv (v: Val) = + let g = cenv.g + let hasOptimizeClosureIfNotInlined = ArgReprInfoHasWellKnownAttribute g WellKnownValAttributes.OptimizeClosureIfNotInlinedAttribute + match v.ValReprInfo with + | Some (ValReprInfo(_, argInfos, _) as valReprInfo) when List.existsSquared hasOptimizeClosureIfNotInlined argInfos -> + let _, curriedArgInfos, _, _ = GetValReprTypeInFSharpForm g valReprInfo v.Type v.Range + for argGroup in curriedArgInfos do + for argTy, argInfo in argGroup do + if hasOptimizeClosureIfNotInlined argInfo then + let m = match argInfo.Name with Some id -> id.idRange | None -> v.Range + checkLanguageFeatureError g.langVersion LanguageFeature.OptimizeClosureIfNotInlined m + let hasInlineIfLambda = ArgReprInfoHasWellKnownAttribute g WellKnownValAttributes.InlineIfLambdaAttribute argInfo + let arity = List.length (fst (stripFunTyN g 6 argTy)) + let valid = v.ShouldInline && hasInlineIfLambda && List.isSingleton argGroup && arity >= 2 && arity <= 5 + if not valid then + errorR(Error(FSComp.SR.tcOptimizeClosureIfNotInlinedRequiresInlineIfLambdaAndMultiArg(), m)) + | _ -> () + and CheckValSpecAux permitByRefLike cenv env (v: Val) byrefError = v.Attribs |> CheckAttribs cenv env v.ValReprInfo |> Option.iter (CheckValInfo cenv env) + CheckOptimizeClosureIfNotInlinedAttribute cenv v CheckTypeAux permitByRefLike cenv env v.Range v.Type byrefError and CheckValSpec permitByRefLike cenv env v = @@ -2248,6 +2268,7 @@ and CheckBinding cenv env alwaysCheckNoReraise ctxt (TBind(v, bindRhs, _) as bin v.Type |> CheckTypePermitAllByrefs cenv env v.Range v.Attribs |> CheckAttribs cenv env v.ValReprInfo |> Option.iter (CheckValInfo cenv env) + CheckOptimizeClosureIfNotInlinedAttribute cenv v // Check accessibility if (v.IsMemberOrModuleBinding || v.IsMember) && not v.IsIncrClassGeneratedMember then @@ -2732,6 +2753,7 @@ let CheckEntityDefn cenv env (tycon: Entity) = // Abstract slots can have byref arguments and returns for vref in abstractSlotValsOfTycons [tycon] do + CheckOptimizeClosureIfNotInlinedAttribute cenv vref match vref.ValReprInfo with | Some valReprInfo -> let tps, argTysl, retTy, _ = GetValReprTypeInFSharpForm g valReprInfo vref.Type m diff --git a/src/Compiler/Checking/SignatureConformance.fs b/src/Compiler/Checking/SignatureConformance.fs index a56699861ba..8199ab60e51 100644 --- a/src/Compiler/Checking/SignatureConformance.fs +++ b/src/Compiler/Checking/SignatureConformance.fs @@ -464,14 +464,17 @@ type Checker(g, amap, denv, remapInfo: SignatureRepackageInfo, checkingSig) = warning(ArgumentsInSigAndImplMismatch(sname, iname)) | _ -> () - let sigHasInlineIfLambda = ArgReprInfoHasWellKnownAttribute g WellKnownValAttributes.InlineIfLambdaAttribute sigArgInfo - let implHasInlineIfLambda = ArgReprInfoHasWellKnownAttribute g WellKnownValAttributes.InlineIfLambdaAttribute implArgInfo - let m = - match implArgInfo.Name with + let m = + match implArgInfo.Name with | Some iname-> iname.idRange | None -> implVal.Range - if sigHasInlineIfLambda && not implHasInlineIfLambda then - errorR(Error (FSComp.SR.implMissingInlineIfLambda(), m)) + + let requireImplAttribute flag diagnostic = + if ArgReprInfoHasWellKnownAttribute g flag sigArgInfo && not (ArgReprInfoHasWellKnownAttribute g flag implArgInfo) then + errorR(Error (diagnostic (), m)) + + requireImplAttribute WellKnownValAttributes.InlineIfLambdaAttribute FSComp.SR.implMissingInlineIfLambda + requireImplAttribute WellKnownValAttributes.OptimizeClosureIfNotInlinedAttribute FSComp.SR.implMissingOptimizeClosureIfNotInlined implArgInfo.OtherRange <- sigArgInfo.Name |> Option.map (fun ident -> ident.idRange) sigArgInfo.OtherRange <- implArgInfo.Name |> Option.map (fun ident -> ident.idRange) diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 2f62c5d1803..0b2642bfabc 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -453,6 +453,12 @@ let TypeNameForInitClass cloc = let TypeNameForImplicitMainMethod cloc = TypeNameForInitClass cloc + "$Main" +let TypeNameForTopLevelFunctions cloc = + ".$" + + cloc.TopImplQualifiedName + let TypeNameForPrivateImplementationDetails cloc = ". + // TLR lifts avoid generic enclosing scopes (#17607). Namespace-root lifts need per-file + // storage without triggering the file's initialization when a lifted method is called. let effectiveCloc = if v.IsCompiledAsTopLevel && not v.IsMemberOrModuleBinding then if eenv.moduleCloc.Enclosing.IsEmpty then - CompLocForInitClass eenv.moduleCloc + if IsFSharpValCompiledAsMethod cenv.g v then + CompLocForTopLevelFunctions eenv.moduleCloc + else + CompLocForInitClass eenv.moduleCloc else eenv.moduleCloc else @@ -11046,6 +11061,7 @@ and GenTypeDefForCompLoc [ TypeNameForImplicitMainMethod cloc TypeNameForInitClass cloc + TypeNameForTopLevelFunctions cloc TypeNameForPrivateImplementationDetails cloc ] then @@ -11340,6 +11356,19 @@ and GenImplFile cenv (mgbuf: AssemblyBuilder) mainInfoOpt eenv (implFile: Checke // Put it at the end since that gives an approximation of dependency order (to aid FSI.EXE's code generator - see FSharp 1.0 5548) GenTypeDefForCompLoc(cenv, eenv, mgbuf, initClassCompLoc, useHiddenInitCode, taccessInternal, [], initClassTrigger, false, true) + GenTypeDefForCompLoc( + cenv, + eenv, + mgbuf, + CompLocForTopLevelFunctions eenv.cloc, + true, + taccessInternal, + [], + ILTypeInit.BeforeField, + true, + true + ) + // lazyInitInfo is an accumulator of functions which add the forced initialization of the storage module to // - mutable fields in public modules // - static "let" bindings in types diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 3b94ec61472..7f420d59c0e 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1772,6 +1772,7 @@ featureImplicitDIMCoverage,"Implicit dispatch slot coverage for default interfac featurePreprocessorElif,"#elif preprocessor directive" featureExtensionConstraintSolutions,"Allow extension members to participate in SRTP constraint resolution" featureErrorOnBitwiseOpsOnNonIntegralEnums,"Error when bitwise operators are used on enums whose underlying type is not an integer type (e.g. char)." +featureOptimizeClosureIfNotInlined,"optimize a curried closure argument when its inlining fails" 3880,optsLangVersionOutOfSupport,"Language version '%s' is out of support. The last .NET SDK supporting it is available at https://dotnet.microsoft.com/en-us/download/dotnet/%s" 3881,optsUnrecognizedLanguageFeature,"Unrecognized language feature name: '%s'. Use a valid feature name such as 'StringInterpolation' or 'FromEndSlicing'." 3882,lexHashElifMustBeFirst,"#elif directive must appear as the first non-whitespace character on a line" @@ -1808,6 +1809,7 @@ featureImprovedImpliedArgumentNamesPartTwo,"Improved implied argument names with 3906,tcRecordExplicitFieldShadowsSpreadField,"Explicit field '%s' shadows a field with the same name from an earlier spread." 3907,tcRecordExprSpreadFieldShadowsSpreadField,"Spread field '%s' shadows a field with the same name from an earlier spread." featureRecordSpreads,"record type and expression spreads" +featureTypeArgumentDependencyOrdering,"ordering explicit type arguments by their constraint dependencies" 3908,xmlDocIncludeError,"XML documentation include error: %s" 3908,xmlDocIncludeError2,"XML documentation include error: Unable to include XML fragment '%s' of file '%s' -- %s" 3909,lexColonDirectiveMustBeFirst,"#: directives must start at the beginning of a line" @@ -1817,4 +1819,6 @@ featureRecordSpreads,"record type and expression spreads" 3913,tcExtendedLayoutCannotBeUsedOnUnions,"The 'ExtendedLayoutAttribute' cannot be applied to discriminated unions" 3914,tcExtendedLayoutStructMustHaveInstanceField,"A struct with the 'ExtendedLayoutAttribute' must have at least one instance field" 3915,tcTupleTypeExtensionTooManyElements,"Tuple type extensions are supported only for tuples of up to 7 elements, but this tuple type has %d elements. Extensions of larger tuples are not supported." -3916,chkNativePtrStackallocInHandler,"'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded." +3916,tcOptimizeClosureIfNotInlinedRequiresInlineIfLambdaAndMultiArg,"The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5." +3917,implMissingOptimizeClosureIfNotInlined,"The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation." +3918,chkNativePtrStackallocInHandler,"'NativePtr.stackalloc' cannot be used inside the 'with' handler, filter or 'finally' block of a 'try' expression. The 'localloc' IL instruction this emits is rejected inside an exception-handling region, producing a 'System.InvalidProgramException' when the method is loaded." diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index e03b60f7031..5cdd3844cea 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -82,7 +82,9 @@ type LanguageFeature = | AccessProtectedBaseFieldFromClosure | ImprovedImpliedArgumentNamesPartTwo | RecordSpreads + | TypeArgumentDependencyOrdering | ErrorOnBitwiseOpsOnNonIntegralEnums + | OptimizeClosureIfNotInlined /// LanguageVersion management type LanguageVersion(versionText, ?disabledFeaturesArray: LanguageFeature array) = @@ -199,6 +201,7 @@ type LanguageVersion(versionText, ?disabledFeaturesArray: LanguageFeature array) LanguageFeature.DirectDelegateConstruction, languageVersion110 LanguageFeature.AccessProtectedBaseFieldFromClosure, languageVersion110 // #5302: read a protected base field from a closure LanguageFeature.RecordSpreads, languageVersion110 + LanguageFeature.TypeArgumentDependencyOrdering, languageVersion110 // Difference between languageVersion110 and preview - 11.0 gets turned on automatically by picking a preview .NET 11 SDK // previewVersion is only when "preview" is specified explicitly in project files and users also need a preview SDK @@ -209,6 +212,7 @@ type LanguageVersion(versionText, ?disabledFeaturesArray: LanguageFeature array) // Unfinished features that still need work before they can be assigned a release language version. LanguageFeature.FromEndSlicing, previewVersion // Unfinished features --- needs work LanguageFeature.ExtensionConstraintSolutions, previewVersion + LanguageFeature.OptimizeClosureIfNotInlined, previewVersion ] static let defaultLanguageVersion = LanguageVersion("default") @@ -370,7 +374,9 @@ type LanguageVersion(versionText, ?disabledFeaturesArray: LanguageFeature array) | LanguageFeature.AccessProtectedBaseFieldFromClosure -> FSComp.SR.featureAccessProtectedBaseFieldFromClosure () | LanguageFeature.ImprovedImpliedArgumentNamesPartTwo -> FSComp.SR.featureImprovedImpliedArgumentNamesPartTwo () | LanguageFeature.RecordSpreads -> FSComp.SR.featureRecordSpreads () + | LanguageFeature.TypeArgumentDependencyOrdering -> FSComp.SR.featureTypeArgumentDependencyOrdering () | LanguageFeature.ErrorOnBitwiseOpsOnNonIntegralEnums -> FSComp.SR.featureErrorOnBitwiseOpsOnNonIntegralEnums () + | LanguageFeature.OptimizeClosureIfNotInlined -> FSComp.SR.featureOptimizeClosureIfNotInlined () /// 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 36e1336e6ea..db17c116a63 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -73,7 +73,9 @@ type LanguageFeature = | AccessProtectedBaseFieldFromClosure | ImprovedImpliedArgumentNamesPartTwo | RecordSpreads + | TypeArgumentDependencyOrdering | ErrorOnBitwiseOpsOnNonIntegralEnums + | OptimizeClosureIfNotInlined /// LanguageVersion management type LanguageVersion = diff --git a/src/Compiler/Optimize/Optimizer.fs b/src/Compiler/Optimize/Optimizer.fs index 8ed18f61121..cee5c0713bf 100644 --- a/src/Compiler/Optimize/Optimizer.fs +++ b/src/Compiler/Optimize/Optimizer.fs @@ -441,8 +441,7 @@ type cenv = specializedInlineVals: HashMultiMap - /// Cache for 'HasFrameLocalBody' - frameLocalVals: Dictionary + forcedInlineVals: Dictionary signatureHidingInfo: SignatureHidingInfo } @@ -1903,6 +1902,68 @@ let rec (|KnownValApp|_|) expr = | Expr.App (KnownValApp(vref, typeArgs1, otherArgs1), _, typeArgs2, otherArgs2, _) -> ValueSome(vref, typeArgs1@typeArgs2, otherArgs1@otherArgs2) | _ -> ValueNone +let AdaptOpaqueOptimizedClosureArgs g (lambdaExpr: Expr) f0ty (arginfos: Summary list) m = + // Hot path: probe the flag before stripping the spine. + let rec hasFlaggedFormal expr = + match expr with + | Expr.TyLambda(_, _, body, _, _) -> hasFlaggedFormal body + | Expr.Lambda(_, _, _, vs, body, _, _) -> List.exists (fun (v: Val) -> v.OptimizeClosureIfNotInlined) vs || hasFlaggedFormal body + | _ -> false + + if not (hasFlaggedFormal lambdaExpr) then + lambdaExpr + else + + let tps, vsl, body, bodyTy = stripTopLambda (lambdaExpr, f0ty) + + let tryFlag (group, info: Summary) = + match group, info.Info with + | [ (v: Val) ], _ when not v.OptimizeClosureIfNotInlined -> None + | [ _ ], StripLambdaValue _ -> None + | [ v ], _ -> + match stripFunTy g v.Type with + | argTys, retTy when argTys.Length >= 2 && argTys.Length <= 5 -> Some(v, argTys, retTy) + | _ -> None + | _ -> None + + let flagged = + if List.length vsl = List.length arginfos then + List.choose tryFlag (List.zip vsl arginfos) + else + [] + + if List.isEmpty flagged then + lambdaExpr + else + + let adaptFormal body (folderVal: Val, argTys, retTy) = + let adaptCall, adaptTy = mkCallOptimizedClosuresAdapt g m argTys retTy (exprForVal m folderVal) + let adaptedVal, adaptedExpr = mkCompGenLocal m "adaptedClosure" adaptTy + let folderVref = mkLocalValRef folderVal + let arity = List.length argTys + let mutable rewrote = false + + // Reroute one saturated application node. A staged chain keeps its effect order. + let env = + { PreIntercept = None + PostTransform = + (fun e -> + match e with + | ValApp g folderVref (_, args, _) when List.length args = arity -> + rewrote <- true + Some(mkCallOptimizedClosuresInvoke g m argTys retTy adaptedExpr args) + | _ -> None) + PreInterceptBinding = None + RewriteQuotations = false + StackGuard = StackGuard("OptimizeClosureIfNotInlinedStackGuard") } + + let rewrittenBody = RewriteExpr env body + if rewrote then mkCompGenLet m adaptedVal adaptCall rewrittenBody else body + + let rewrittenBody = List.fold adaptFormal body flagged + if body === rewrittenBody then lambdaExpr + else mkMultiLambdas g m tps vsl (rewrittenBody, bodyTy) + /// Matches boolean decision tree: /// check single case with bool const. [] @@ -2469,28 +2530,25 @@ let instrIsFrameLocal instr = | I_localloc -> true | _ -> false -/// The FSharp.Core values expanding to frame-local IL are marked [] and so are -/// always inlined. A user 'inline' function wrapping one inherits the property but not the -/// attribute - the callee is already inlined into the recorded body, leaving only its IL - so -/// recover it from the body and propagate it through further wrappers. -/// See https://github.com/dotnet/fsharp/issues/20063. -let rec HasFrameLocalBody cenv env (vref: ValRef) = +/// Frame-local IL and resumable templates must remain in the caller's method. +/// Inline wrappers inherit this requirement even when they do not inherit the callee's attributes. +let rec HasForcedInlineBody cenv env (vref: ValRef) = let stamp = vref.Stamp - match cenv.frameLocalVals.TryGetValue stamp with + match cenv.forcedInlineVals.TryGetValue stamp with | true, res -> res | _ -> // Values bound within the body being walked have no info yet, but the walk covers them anyway. match TryGetInfoForVal cenv env vref |> Option.map (fun info -> stripValue info.ValExprInfo) with | Some(CurriedLambdaValue (_, _, _, body, _)) -> - cenv.frameLocalVals[stamp] <- false // Break cycles while the body is inspected - let res = ExprIsFrameLocal cenv env body - cenv.frameLocalVals[stamp] <- res + cenv.forcedInlineVals[stamp] <- false // Break cycles while the body is inspected + let res = ExprNeedsForcedInlining cenv env body + cenv.forcedInlineVals[stamp] <- res res | _ -> false -and ExprIsFrameLocal cenv env expr = +and ExprNeedsForcedInlining cenv env expr = let folder = { ExprFolder0 with exprIntercept = @@ -2499,7 +2557,9 @@ and ExprIsFrameLocal cenv env expr = match expr with | Expr.Op (TOp.ILAsm (instrs, _), _, _, _) when List.exists instrIsFrameLocal instrs -> true - | Expr.Val (vref, _, _) when vref.ShouldInline -> HasFrameLocalBody cenv env vref + // Lowering must see the template and its resumable-code arguments in the same method. + | StructStateMachineExpr cenv.g _ -> true + | Expr.Val (vref, _, _) when vref.ShouldInline -> HasForcedInlineBody cenv env vref | _ -> noInterceptF acc expr } FoldExpr folder false expr @@ -2512,7 +2572,9 @@ let shouldForceInlineInDebug cenv env (vref: ValRef) : bool = (vref.HasDeclaringEntity && shouldForceInlineMembersInDebug g vref.DeclaringEntity) || - HasFrameLocalBody cenv env vref + isReturnsResumableCodeTy g vref.TauType || + + HasForcedInlineBody cenv env vref /// `let p = f a b`, p an [] parameter binding whose right-hand side is an under-applied /// call to a known-arity value. @@ -3727,6 +3789,18 @@ and TryInlineApplication cenv env finfo (valExpr: Expr) (tyargs: TType list, arg let specLambda = MakeApplicationAndBetaReduce g (f2R, origLambdaTy, [tyargs], [], m) let specLambdaTy = tyOfExpr g specLambda + let hasStateMachineTemplate = + (false, specLambdaTy) + ||> SimplifyTypes.foldTypeButNotConstraints (stripTyEqns g) (fun found ty -> + found || + (tryTcrefOfAppTy g ty |> ValueOption.exists (tyconRefEq g g.ResumableStateMachine_tcr))) + + // A separate helper loses type parameters of the struct that replaces this template during lowering. + if hasStateMachineTemplate then + let cenv = { cenv with settings = { cenv.settings with alwaysInline = true } } + Some(OptimizeApplication cenv { env with debugInlineCallSite = Some m } (valExpr, vref.Type, tyargs, argsR, m)) + else + // Typars that flow in from the enclosing scope when tyargs are non-concrete. A tyarg can reach // only the body, and typars left unabstracted below are erased to 'object'. let freeTypars = @@ -4085,6 +4159,8 @@ and OptimizeApplication cenv env (f0, f0ty, tyargs, args, m) = | _ -> args |> List.map (fun arg -> UnknownValue, arg) let newArgs, arginfos = OptimizeExprsThenReshapeAndConsiderSplits cenv env shapes + // Run before beta reduction removes the flagged formals. + let newf0 = AdaptOpaqueOptimizedClosureArgs g newf0 f0ty arginfos m // beta reducing let reducedExpr = MakeApplicationAndBetaReduce g (newf0, f0ty, [tyargs], newArgs, m) let newExpr = reducedExpr |> remake @@ -4875,7 +4951,7 @@ let OptimizeImplFile (settings, ccu, tcGlobals: TcGlobals, tcVal, importMap, opt stackGuard = StackGuard("OptimizerStackGuardDepth") realsig = tcGlobals.realsig specializedInlineVals = HashMultiMap(HashIdentity.Structural, true) - frameLocalVals = Dictionary() + forcedInlineVals = Dictionary() signatureHidingInfo = SignatureHidingInfo.Empty } diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index 24b2e645bfb..4711544b314 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -280,6 +280,11 @@ type TcGlobals( let v_voidptr_tcr = mk_MFCore_tcref fslibCcu "voidptr" let v_ilsigptr_tcr = mk_MFCore_tcref fslibCcu "ilsigptr`1" let v_fastFunc_tcr = mk_MFCore_tcref fslibCcu "FSharpFunc`2" + let v_optimizedClosures_nleref = mkNonLocalEntityRef fslibCcu (Array.append CorePathArray [| "OptimizedClosures" |]) + let v_optimizedClosures_FSharpFunc3_tcr = mkNonLocalTyconRef v_optimizedClosures_nleref "FSharpFunc`3" + let v_optimizedClosures_FSharpFunc4_tcr = mkNonLocalTyconRef v_optimizedClosures_nleref "FSharpFunc`4" + let v_optimizedClosures_FSharpFunc5_tcr = mkNonLocalTyconRef v_optimizedClosures_nleref "FSharpFunc`5" + let v_optimizedClosures_FSharpFunc6_tcr = mkNonLocalTyconRef v_optimizedClosures_nleref "FSharpFunc`6" let v_refcell_tcr_canon = mk_MFCore_tcref fslibCcu "Ref`1" let v_refcell_tcr_nice = mk_MFCore_tcref fslibCcu "ref`1" let v_mfe_tcr = mk_MFCore_tcref fslibCcu "MatchFailureException" @@ -1290,6 +1295,14 @@ type TcGlobals( member _.fastFunc_tcr = v_fastFunc_tcr + member _.optimizedClosures_FSharpFunc_tcref arity = + match arity with + | 2 -> v_optimizedClosures_FSharpFunc3_tcr + | 3 -> v_optimizedClosures_FSharpFunc4_tcr + | 4 -> v_optimizedClosures_FSharpFunc5_tcr + | 5 -> v_optimizedClosures_FSharpFunc6_tcr + | _ -> failwith "optimizedClosures_FSharpFunc_tcref: arity out of range 2..5" + member _.MatchFailureException_tcr = v_mfe_tcr diff --git a/src/Compiler/TypedTree/TcGlobals.fsi b/src/Compiler/TypedTree/TcGlobals.fsi index 8356b16ccfc..b0dcdc37df7 100644 --- a/src/Compiler/TypedTree/TcGlobals.fsi +++ b/src/Compiler/TypedTree/TcGlobals.fsi @@ -288,6 +288,8 @@ type internal TcGlobals = member ResumableCode_tcr: TypedTree.EntityRef + member ResumableStateMachine_tcr: TypedTree.EntityRef + member System_Runtime_CompilerServices_RuntimeFeature_ty: TypedTree.TType option member addrof2_vref: TypedTree.ValRef @@ -544,6 +546,8 @@ type internal TcGlobals = member fastFunc_tcr: TypedTree.EntityRef + member optimizedClosures_FSharpFunc_tcref: int -> TypedTree.EntityRef + member float32_operator_info: IntrinsicValRef member float32_tcr: TypedTree.EntityRef diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index 052e046242a..2b05548dabd 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -252,6 +252,10 @@ type ValFlags(flags: int64) = member x.WithIsParameter = ValFlags(flags ||| 0b10000000000000000000000L) + member x.OptimizeClosureIfNotInlined = (flags &&& 0b100000000000000000000000L) <> 0L + + member x.WithOptimizeClosureIfNotInlined = ValFlags(flags ||| 0b100000000000000000000000L) + /// Get the flags as included in the F# binary metadata member x.PickledBits = // Clear the RecursiveValInfo, only used during inference and irrelevant across assembly boundaries @@ -3173,6 +3177,8 @@ type Val = /// Get the inline declaration on a parameter or other non-function-declaration value, used for optimization member x.InlineIfLambda = x.val_flags.InlineIfLambda + member x.OptimizeClosureIfNotInlined = x.val_flags.OptimizeClosureIfNotInlined + /// Determines if the values is implied by another construct, e.g. a `IsA` property is implied by the union case for A member x.IsImplied = x.val_flags.IsImplied @@ -3426,6 +3432,8 @@ type Val = member x.SetInlineIfLambda() = x.val_flags <- x.val_flags.WithInlineIfLambda + member x.SetOptimizeClosureIfNotInlined() = x.val_flags <- x.val_flags.WithOptimizeClosureIfNotInlined + member x.SetInlineInfo (inlineInfo: ValInline) = x.val_flags <- x.val_flags.WithInlineInfo inlineInfo member x.SetIsImplied() = x.val_flags <- x.val_flags.WithIsImplied @@ -4355,6 +4363,8 @@ type ValRef = /// Get the inline declaration on a parameter or other non-function-declaration value, used for optimization member x.InlineIfLambda = x.Deref.InlineIfLambda + member x.OptimizeClosureIfNotInlined = x.Deref.OptimizeClosureIfNotInlined + /// Indicates whether the inline declaration for the value indicate that the value must be inlined? member x.ShouldInline = x.Deref.ShouldInline diff --git a/src/Compiler/TypedTree/TypedTree.fsi b/src/Compiler/TypedTree/TypedTree.fsi index c067bf4ffb7..cd28910d1d4 100644 --- a/src/Compiler/TypedTree/TypedTree.fsi +++ b/src/Compiler/TypedTree/TypedTree.fsi @@ -123,6 +123,7 @@ type ValFlags = member IgnoresByrefScope: bool member InlineIfLambda: bool + member OptimizeClosureIfNotInlined: bool member InlineInfo: ValInline @@ -162,6 +163,7 @@ type ValFlags = member WithIgnoresByrefScope: ValFlags member WithInlineIfLambda: ValFlags + member WithOptimizeClosureIfNotInlined: ValFlags member WithInlineInfo: inlineInfo: ValInline -> ValFlags @@ -2053,6 +2055,7 @@ type Val = member SetIgnoresByrefScope: unit -> unit member SetInlineIfLambda: unit -> unit + member SetOptimizeClosureIfNotInlined: unit -> unit /// Sets the inline information for this value. Used by the type checker /// to downgrade an erroneously-recursive inline binding to non-inline @@ -2174,6 +2177,7 @@ type Val = /// Get the inline declaration on a parameter or other non-function-declaration value, used for optimization member InlineIfLambda: bool + member OptimizeClosureIfNotInlined: bool /// Get the inline declaration on the value member InlineInfo: ValInline @@ -2916,6 +2920,7 @@ type ValRef = /// Get the inline declaration on a parameter or other non-function-declaration value, used for optimization member InlineIfLambda: bool + member OptimizeClosureIfNotInlined: bool /// Determines if the values is implied by another construct, e.g. a `IsA` property is implied by the union case for A member IsImplied: bool diff --git a/src/Compiler/TypedTree/TypedTreeOps.Attributes.fs b/src/Compiler/TypedTree/TypedTreeOps.Attributes.fs index 79ed63f2043..63f686d610a 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.Attributes.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.Attributes.fs @@ -657,6 +657,7 @@ module internal AttributeHelpers = | "OptionalArgumentAttribute" -> WellKnownValAttributes.OptionalArgumentAttribute | "ProjectionParameterAttribute" -> WellKnownValAttributes.ProjectionParameterAttribute | "InlineIfLambdaAttribute" -> WellKnownValAttributes.InlineIfLambdaAttribute + | "OptimizeClosureIfNotInlinedAttribute" -> WellKnownValAttributes.OptimizeClosureIfNotInlinedAttribute | "StructAttribute" -> WellKnownValAttributes.StructAttribute | "NoCompilerInliningAttribute" -> WellKnownValAttributes.NoCompilerInliningAttribute | "GeneralizableValueAttribute" -> WellKnownValAttributes.GeneralizableValueAttribute diff --git a/src/Compiler/TypedTree/TypedTreeOps.ExprOps.fs b/src/Compiler/TypedTree/TypedTreeOps.ExprOps.fs index 01259383c7a..48f5fcfac59 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.ExprOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.ExprOps.fs @@ -1578,6 +1578,56 @@ module internal Makers = m ) + let private optimizedClosureILShape (g: TcGlobals) (argTys: TType list) retTy = + let arity = List.length argTys + let formalArgTys = List.init arity (fun i -> ILType.TypeVar(uint16 i)) + let formalRetTy = ILType.TypeVar(uint16 arity) + + let optClosILTy = + mkILBoxedTy (g.optimizedClosures_FSharpFunc_tcref arity).CompiledRepresentationForNamedType (formalArgTys @ [ formalRetTy ]) + + formalArgTys, formalRetTy, optClosILTy, argTys @ [ retTy ] + + let mkCallOptimizedClosuresAdapt (g: TcGlobals) m (argTys: TType list) (retTy: TType) folderExpr = + let formalArgTys, formalRetTy, optClosILTy, tinst = + optimizedClosureILShape g argTys retTy + + let formalFolderTy = + (formalArgTys, formalRetTy) + ||> List.foldBack (fun dty rty -> mkILBoxedTy g.fastFunc_tcr.CompiledRepresentationForNamedType [ dty; rty ]) + + let mspec = + mkILNonGenericStaticMethSpecInTy (optClosILTy, "Adapt", [ formalFolderTy ], optClosILTy) + + let resultTy = + mkWoNullAppTy (g.optimizedClosures_FSharpFunc_tcref argTys.Length) tinst + + let call = + Expr.Op( + TOp.ILCall(false, false, false, false, ValUseFlag.NormalValUse, false, false, mspec.MethodRef, tinst, [], [ resultTy ]), + [], + [ folderExpr ], + m + ) + + call, resultTy + + let mkCallOptimizedClosuresInvoke (g: TcGlobals) m (argTys: TType list) (retTy: TType) fExpr argExprs = + assert (List.length argExprs = argTys.Length) + + let formalArgTys, formalRetTy, optClosILTy, tinst = + optimizedClosureILShape g argTys retTy + + let mspec = + mkILNonGenericInstanceMethSpecInTy (optClosILTy, "Invoke", formalArgTys, formalRetTy) + + Expr.Op( + TOp.ILCall(true, false, false, false, ValUseFlag.NormalValUse, false, false, mspec.MethodRef, tinst, [], [ retTy ]), + [], + fExpr :: argExprs, + m + ) + /// Concatenate string-valued expressions, choosing the cheapest String.Concat overload by arity. /// An empty list yields "" and a singleton yields itself. let mkStringConcat (g: TcGlobals, m: range, exprs: Expr list) = diff --git a/src/Compiler/TypedTree/TypedTreeOps.ExprOps.fsi b/src/Compiler/TypedTree/TypedTreeOps.ExprOps.fsi index fe854b83c85..20af8e9f3c0 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.ExprOps.fsi +++ b/src/Compiler/TypedTree/TypedTreeOps.ExprOps.fsi @@ -438,6 +438,12 @@ module internal Makers = val mkGetStringLength: TcGlobals -> range -> Expr -> Expr + /// `OptimizedClosures.FSharpFunc.Adapt(folderExpr)`. Returns the call and its result type. + val mkCallOptimizedClosuresAdapt: TcGlobals -> range -> TType list -> TType -> Expr -> Expr * TType + + /// `fExpr.Invoke(argExprs)` on an `OptimizedClosures.FSharpFunc`. + val mkCallOptimizedClosuresInvoke: TcGlobals -> range -> TType list -> TType -> Expr -> Expr list -> Expr + val mkStaticCall_String_Concat2: TcGlobals -> range -> Expr -> Expr -> Expr val mkStaticCall_String_Concat3: TcGlobals -> range -> Expr -> Expr -> Expr -> Expr diff --git a/src/Compiler/TypedTree/TypedTreeOps.FreeVars.fs b/src/Compiler/TypedTree/TypedTreeOps.FreeVars.fs index f8793c59aab..bb3a732deec 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.FreeVars.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.FreeVars.fs @@ -492,6 +492,46 @@ module internal FreeTypeVars = let freeInTypesLeftToRightSkippingConstraints g ty = accFreeInTypesLeftToRight g false true emptyFreeTyparsLeftToRight ty |> List.rev + /// The stamps of the sibling type parameters referenced by a type parameter's subtype (:>) + /// constraints — i.e. the parameters it must be unified after (the #20103 dependency). + let constraintDependencyStamps (g: TcGlobals) (tp: Typar) = + tp.Constraints + |> List.choose (function + | TyparConstraint.CoercesTo(ty, _) -> Some ty + | _ -> None) + |> freeInTypesLeftToRight g true + |> List.choose (fun ftp -> if ftp.Stamp = tp.Stamp then None else Some ftp.Stamp) + |> Set.ofList + + /// Stable-sort the (formalTypar, actualType) unification pairs of an explicit generic + /// instantiation so a type parameter used in another's subtype constraint (the 'b in 'a :> I<'b>) + /// is unified first. Returns the pairs unchanged when no such cross-reference exists. + /// See https://github.com/dotnet/fsharp/issues/20103 + let reorderTyArgsByConstraintDependencies (g: TcGlobals) (pairs: (TType * TType) list) = + match pairs with + | [] + | [ _ ] -> pairs + | _ -> + let node pair = + match stripTyEqns g (fst pair) with + | TType_var(tp, _) -> pair, ValueSome tp.Stamp, constraintDependencyStamps g tp + | _ -> pair, ValueNone, Set.empty + + let nodes = pairs |> List.map node + + if nodes |> List.forall (fun (_, _, deps) -> Set.isEmpty deps) then + pairs + else + // 'a' must precede 'b' when b's subtype constraint references a's parameter. + let mustPrecede (_, stamp, _) (_, _, deps) = + match stamp with + | ValueSome s -> Set.contains s deps + | ValueNone -> false + + nodes + |> List.stableTopologicalSort mustPrecede + |> List.map (fun (pair, _, _) -> pair) + [] module internal MemberRepresentation = @@ -1082,19 +1122,20 @@ module internal MemberRepresentation = module SimplifyTypes = // CAREFUL! This function does NOT walk constraints - let rec foldTypeButNotConstraints f z ty = - let ty = stripTyparEqns ty + let rec foldTypeButNotConstraints normalizeType f z ty = + let ty = normalizeType ty let z = f z ty match ty with - | TType_forall(_, bodyTy) -> foldTypeButNotConstraints f z bodyTy + | TType_forall(_, bodyTy) -> foldTypeButNotConstraints normalizeType f z bodyTy | TType_app(_, tys, _) | TType_ucase(_, tys) | TType_anon(_, tys) - | TType_tuple(_, tys) -> List.fold (foldTypeButNotConstraints f) z tys + | TType_tuple(_, tys) -> List.fold (foldTypeButNotConstraints normalizeType f) z tys - | TType_fun(domainTy, rangeTy, _) -> foldTypeButNotConstraints f (foldTypeButNotConstraints f z domainTy) rangeTy + | TType_fun(domainTy, rangeTy, _) -> + foldTypeButNotConstraints normalizeType f (foldTypeButNotConstraints normalizeType f z domainTy) rangeTy | TType_var _ -> z @@ -1109,7 +1150,7 @@ module internal MemberRepresentation = let accTyparCounts z ty = // Walk type to determine typars and their counts (for pprinting decisions) (z, ty) - ||> foldTypeButNotConstraints (fun z ty -> + ||> foldTypeButNotConstraints stripTyparEqns (fun z ty -> match ty with | TType_var(tp, _) when tp.Rigidity = TyparRigidity.Rigid -> incM tp z | _ -> z) diff --git a/src/Compiler/TypedTree/TypedTreeOps.FreeVars.fsi b/src/Compiler/TypedTree/TypedTreeOps.FreeVars.fsi index 0e9761fe5ea..674317bdac8 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.FreeVars.fsi +++ b/src/Compiler/TypedTree/TypedTreeOps.FreeVars.fsi @@ -114,6 +114,10 @@ module internal FreeTypeVars = val freeInTypesLeftToRightSkippingConstraints: TcGlobals -> TType list -> Typars + /// Stable-sort explicit generic unification pairs so a type parameter used in another parameter's + /// subtype constraint (the 'b in 'a :> I<'b>) is solved first. See https://github.com/dotnet/fsharp/issues/20103 + val reorderTyArgsByConstraintDependencies: g: TcGlobals -> pairs: (TType * TType) list -> (TType * TType) list + val freeInModuleTy: ModuleOrNamespaceType -> FreeTyvars [] @@ -378,9 +382,12 @@ module internal MemberRepresentation = val prefixOfInferenceTypar: Typar -> string - /// Utilities used in simplifying types for visual presentation + /// Utilities for traversing and simplifying types module SimplifyTypes = + /// Fold normalized type structure without following type-parameter constraints. + val foldTypeButNotConstraints: (TType -> TType) -> ('State -> TType -> 'State) -> 'State -> TType -> 'State + type TypeSimplificationInfo = { singletons: Typar Zset inplaceConstraints: Zmap diff --git a/src/Compiler/TypedTree/WellKnownAttribs.fs b/src/Compiler/TypedTree/WellKnownAttribs.fs index e4959ec43fb..c0a6a5e5d41 100644 --- a/src/Compiler/TypedTree/WellKnownAttribs.fs +++ b/src/Compiler/TypedTree/WellKnownAttribs.fs @@ -119,6 +119,7 @@ type internal WellKnownValAttributes = | TailCallAttribute = (1uL <<< 40) | NotNullIfNotNullAttribute = (1uL <<< 41) | OverloadResolutionPriorityAttribute = (1uL <<< 42) + | OptimizeClosureIfNotInlinedAttribute = (1uL <<< 43) | NotComputed = (1uL <<< 63) module internal Flags = diff --git a/src/Compiler/TypedTree/WellKnownAttribs.fsi b/src/Compiler/TypedTree/WellKnownAttribs.fsi index c8945a1d912..a3d2154cef3 100644 --- a/src/Compiler/TypedTree/WellKnownAttribs.fsi +++ b/src/Compiler/TypedTree/WellKnownAttribs.fsi @@ -117,6 +117,7 @@ type internal WellKnownValAttributes = | TailCallAttribute = (1uL <<< 40) | NotNullIfNotNullAttribute = (1uL <<< 41) | OverloadResolutionPriorityAttribute = (1uL <<< 42) + | OptimizeClosureIfNotInlinedAttribute = (1uL <<< 43) | NotComputed = (1uL <<< 63) module internal Flags = diff --git a/src/Compiler/Utilities/illib.fs b/src/Compiler/Utilities/illib.fs index 244158619d2..d6302776cb7 100644 --- a/src/Compiler/Utilities/illib.fs +++ b/src/Compiler/Utilities/illib.fs @@ -778,6 +778,22 @@ module List = go state list [] + let stableTopologicalSort (mustPrecede: 'T -> 'T -> bool) (xs: 'T list) = + let rec emit remaining = + match remaining with + | [] -> [] + | _ -> + // A node is ready once nothing still remaining must precede it. List.partition is stable, + // so ready nodes keep their original order; a leftover cycle is emitted in original order. + match + remaining + |> List.partition (fun x -> remaining |> List.forall (fun y -> not (mustPrecede y x))) + with + | [], cycle -> cycle + | ready, rest -> ready @ emit rest + + emit xs + module ResizeArray = /// Split a ResizeArray into an array of smaller chunks. diff --git a/src/Compiler/Utilities/illib.fsi b/src/Compiler/Utilities/illib.fsi index 0ee41f441b5..bc04c2ca1ac 100644 --- a/src/Compiler/Utilities/illib.fsi +++ b/src/Compiler/Utilities/illib.fsi @@ -261,6 +261,11 @@ module internal List = list: 'T list -> struct ('Result list * 'State) + /// Stable topological sort by a 'mustPrecede' relation ('mustPrecede x y' means x must come before y). + /// Independent elements keep their original order; any leftover dependency cycle is emitted in original + /// order. O(n²) per emitted layer, so intended for small inputs. + val stableTopologicalSort: mustPrecede: ('T -> 'T -> bool) -> xs: 'T list -> 'T list + module internal ResizeArray = /// Split a ResizeArray into an array of smaller chunks. diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index e776d0f485d..b39c2004790 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -482,6 +482,11 @@ nullness checking + + optimize a curried closure argument when its inlining fails + optimize a curried closure argument when its inlining fails + + Support for OverloadResolutionPriorityAttribute to prioritize method overloads. Support for OverloadResolutionPriorityAttribute to prioritize method overloads. @@ -592,6 +597,11 @@ Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`. + + ordering explicit type arguments by their constraint dependencies + ordering explicit type arguments by their constraint dependencies + + Union case test properties Vlastnosti testu případu sjednocení @@ -707,6 +717,11 @@ Atribut InlineIfLambda se nachází v signatuře, ale ne v implementaci. + + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + + XML comment is not placed on a valid language element. Komentář XML není umístěn v platném prvku jazyka. @@ -1607,6 +1622,11 @@ Only structs may be given the 'ExtendedLayoutAttribute' + + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + + The syntax 'expr1[expr2]' is ambiguous when used as an argument. See https://aka.ms/fsharp-index-notation. If you intend indexing or slicing then you must use 'expr1.[expr2]' in argument position. If calling a function with multiple curried arguments, add a space between them, e.g. 'someFunction expr1 [expr2]'. Syntaxe expr1[expr2] je při použití jako argument nejednoznačná. Více informací: https://aka.ms/fsharp-index-notation. Pokud plánujete indexování nebo vytváření řezů, musíte použít expr1.[expr2] na pozici argumentu. Pokud voláte funkci s vícenásobnými curryfikovanými argumenty, přidejte mezi ně mezeru, třeba someFunction expr1 [expr2]. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 96200e44108..2d13e3d720e 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -482,6 +482,11 @@ nullness checking + + optimize a curried closure argument when its inlining fails + optimize a curried closure argument when its inlining fails + + Support for OverloadResolutionPriorityAttribute to prioritize method overloads. Support for OverloadResolutionPriorityAttribute to prioritize method overloads. @@ -592,6 +597,11 @@ Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`. + + ordering explicit type arguments by their constraint dependencies + ordering explicit type arguments by their constraint dependencies + + Union case test properties Eigenschaften von Union-Falltests @@ -707,6 +717,11 @@ Das Attribut "InlineIfLambda" ist in der Signatur vorhanden, jedoch nicht in der Implementierung. + + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + + XML comment is not placed on a valid language element. Der XML-Kommentar wird nicht in einem gültigen Sprachelement platziert. @@ -1607,6 +1622,11 @@ Only structs may be given the 'ExtendedLayoutAttribute' + + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + + The syntax 'expr1[expr2]' is ambiguous when used as an argument. See https://aka.ms/fsharp-index-notation. If you intend indexing or slicing then you must use 'expr1.[expr2]' in argument position. If calling a function with multiple curried arguments, add a space between them, e.g. 'someFunction expr1 [expr2]'. Die Syntax "expr1[expr2]" ist mehrdeutig, wenn sie als Argument verwendet wird. Siehe https://aka.ms/fsharp-index-notation. Wenn Sie indizieren oder aufteilen möchten, müssen Sie "expr1.[expr2]' in Argumentposition verwenden. Wenn Sie eine Funktion mit mehreren geschweiften Argumenten aufrufen, fügen Sie ein Leerzeichen dazwischen hinzu, z. B. "someFunction expr1 [expr2]". diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index cb0ede0ad34..53657aa853d 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -482,6 +482,11 @@ nullness checking + + optimize a curried closure argument when its inlining fails + optimize a curried closure argument when its inlining fails + + Support for OverloadResolutionPriorityAttribute to prioritize method overloads. Support for OverloadResolutionPriorityAttribute to prioritize method overloads. @@ -592,6 +597,11 @@ Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`. + + ordering explicit type arguments by their constraint dependencies + ordering explicit type arguments by their constraint dependencies + + Union case test properties Propiedades de prueba de caso de unión @@ -707,6 +717,11 @@ El atributo "InlineIfLambda" está presente en la firma, pero no en la implementación. + + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + + XML comment is not placed on a valid language element. El comentario XML no está situado en un elemento válido del lenguaje. @@ -1607,6 +1622,11 @@ Only structs may be given the 'ExtendedLayoutAttribute' + + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + + The syntax 'expr1[expr2]' is ambiguous when used as an argument. See https://aka.ms/fsharp-index-notation. If you intend indexing or slicing then you must use 'expr1.[expr2]' in argument position. If calling a function with multiple curried arguments, add a space between them, e.g. 'someFunction expr1 [expr2]'. La sintaxis "expr1[expr2]" es ambigua cuando se usa como argumento. Vea https://aka.ms/fsharp-index-notation. Si piensa indexar o segmentar, debe usar "expr1.[expr2]" en la posición del argumento. Si se llama a una función con varios argumentos currificados, se agregará un espacio entre ellos, por ejemplo, "unaFunción expr1 [expr2]". diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index fdcb65fc805..52a99f3ae2d 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -482,6 +482,11 @@ nullness checking + + optimize a curried closure argument when its inlining fails + optimize a curried closure argument when its inlining fails + + Support for OverloadResolutionPriorityAttribute to prioritize method overloads. Support for OverloadResolutionPriorityAttribute to prioritize method overloads. @@ -592,6 +597,11 @@ Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`. + + ordering explicit type arguments by their constraint dependencies + ordering explicit type arguments by their constraint dependencies + + Union case test properties Propriétés du test de cas d’union @@ -707,6 +717,11 @@ L’attribut « InlineIfLambda » est présent dans la signature, mais pas dans l’implémentation. + + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + + XML comment is not placed on a valid language element. Le commentaire XML n'est pas placé dans un élément valide du langage. @@ -1607,6 +1622,11 @@ Only structs may be given the 'ExtendedLayoutAttribute' + + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + + The syntax 'expr1[expr2]' is ambiguous when used as an argument. See https://aka.ms/fsharp-index-notation. If you intend indexing or slicing then you must use 'expr1.[expr2]' in argument position. If calling a function with multiple curried arguments, add a space between them, e.g. 'someFunction expr1 [expr2]'. La syntaxe « expr1[expr2] » est ambiguë lorsqu’elle est utilisée comme argument. Voir https://aka.ms/fsharp-index-notation. Si vous avez l’intention d’indexer ou de découper, vous devez utiliser « expr1.[expr2] » en position d’argument. Si vous appelez une fonction avec plusieurs arguments codés, ajoutez un espace entre eux, par exemple « someFunction expr1 [expr2] ». diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index c5d2450ab76..11b84cf937a 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -482,6 +482,11 @@ nullness checking + + optimize a curried closure argument when its inlining fails + optimize a curried closure argument when its inlining fails + + Support for OverloadResolutionPriorityAttribute to prioritize method overloads. Support for OverloadResolutionPriorityAttribute to prioritize method overloads. @@ -592,6 +597,11 @@ Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`. + + ordering explicit type arguments by their constraint dependencies + ordering explicit type arguments by their constraint dependencies + + Union case test properties Proprietà test case di unione @@ -707,6 +717,11 @@ L'attributo 'InlineIfLambda' è presente nella firma, ma non nell'implementazione. + + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + + XML comment is not placed on a valid language element. Il commento XML non si trova in un elemento di linguaggio valido. @@ -1607,6 +1622,11 @@ Only structs may be given the 'ExtendedLayoutAttribute' + + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + + The syntax 'expr1[expr2]' is ambiguous when used as an argument. See https://aka.ms/fsharp-index-notation. If you intend indexing or slicing then you must use 'expr1.[expr2]' in argument position. If calling a function with multiple curried arguments, add a space between them, e.g. 'someFunction expr1 [expr2]'. La sintassi 'expr1[expr2]' è ambigua se usata come argomento. Vedere https://aka.ms/fsharp-index-notation. Se si intende eseguire l'indicizzazione o il sezionamento, è necessario usare 'expr1.[expr2]' nella posizione dell'argomento. Se si chiama una funzione con più argomenti sottoposti a corsi, aggiungere uno spazio tra di essi, ad esempio 'someFunction expr1 [expr2]'. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 22e7f90f155..3188d6ca4c6 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -482,6 +482,11 @@ nullness checking + + optimize a curried closure argument when its inlining fails + optimize a curried closure argument when its inlining fails + + Support for OverloadResolutionPriorityAttribute to prioritize method overloads. Support for OverloadResolutionPriorityAttribute to prioritize method overloads. @@ -592,6 +597,11 @@ Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`. + + ordering explicit type arguments by their constraint dependencies + ordering explicit type arguments by their constraint dependencies + + Union case test properties ユニオン ケースのテスト プロパティ @@ -707,6 +717,11 @@ 'InlineIfLambda' 属性はシグネチャに存在しますが、実装はありません。 + + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + + XML comment is not placed on a valid language element. XML コメントは有効な言語要素上にありません。 @@ -1607,6 +1622,11 @@ Only structs may be given the 'ExtendedLayoutAttribute' + + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + + The syntax 'expr1[expr2]' is ambiguous when used as an argument. See https://aka.ms/fsharp-index-notation. If you intend indexing or slicing then you must use 'expr1.[expr2]' in argument position. If calling a function with multiple curried arguments, add a space between them, e.g. 'someFunction expr1 [expr2]'. 構文 'expr1[expr2]' は引数として使用されている場合、あいまいです。https://aka.ms/fsharp-index-notation を参照してください。インデックス作成またはスライスを行う場合は、'expr1.[expr2]' を引数の位置に使用する必要があります。複数のカリー化された引数を持つ関数を呼び出す場合は、'expr1 [expr2]' のように間にスペースを追加します。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index b857d14c3a0..832a37caf5f 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -482,6 +482,11 @@ nullness checking + + optimize a curried closure argument when its inlining fails + optimize a curried closure argument when its inlining fails + + Support for OverloadResolutionPriorityAttribute to prioritize method overloads. Support for OverloadResolutionPriorityAttribute to prioritize method overloads. @@ -592,6 +597,11 @@ Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`. + + ordering explicit type arguments by their constraint dependencies + ordering explicit type arguments by their constraint dependencies + + Union case test properties 공용 구조체 사례 테스트 속성 @@ -707,6 +717,11 @@ 'InlineIfLambda' 특성이 서명에 있지만 구현에는 없습니다. + + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + + XML comment is not placed on a valid language element. XML 주석이 유효한 언어 요소에 배치되어 있지 않습니다. @@ -1607,6 +1622,11 @@ Only structs may be given the 'ExtendedLayoutAttribute' + + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + + The syntax 'expr1[expr2]' is ambiguous when used as an argument. See https://aka.ms/fsharp-index-notation. If you intend indexing or slicing then you must use 'expr1.[expr2]' in argument position. If calling a function with multiple curried arguments, add a space between them, e.g. 'someFunction expr1 [expr2]'. 'expr1[expr2]' 구문은 인수로 사용될 때 모호합니다. https://aka.ms/fsharp-index-notation을 참조하세요. 인덱싱이나 슬라이싱을 하려면 인수 위치에 'expr1.[expr2]'를 사용해야 합니다. 여러 개의 커리된 인수로 함수를 호출하는 경우 그 사이에 공백을 추가하세요(예: 'someFunction expr1 [expr2]'). diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 4017c9a1a9f..09e622cfc9a 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -482,6 +482,11 @@ nullness checking + + optimize a curried closure argument when its inlining fails + optimize a curried closure argument when its inlining fails + + Support for OverloadResolutionPriorityAttribute to prioritize method overloads. Support for OverloadResolutionPriorityAttribute to prioritize method overloads. @@ -592,6 +597,11 @@ Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`. + + ordering explicit type arguments by their constraint dependencies + ordering explicit type arguments by their constraint dependencies + + Union case test properties Właściwości testowe przypadku unii @@ -707,6 +717,11 @@ Atrybut "InlineIfLambda" jest obecny w sygnaturze, ale nie w implementacji. + + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + + XML comment is not placed on a valid language element. Komentarz XML nie został umieszczony w prawidłowym elemencie języka. @@ -1607,6 +1622,11 @@ Only structs may be given the 'ExtendedLayoutAttribute' + + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + + The syntax 'expr1[expr2]' is ambiguous when used as an argument. See https://aka.ms/fsharp-index-notation. If you intend indexing or slicing then you must use 'expr1.[expr2]' in argument position. If calling a function with multiple curried arguments, add a space between them, e.g. 'someFunction expr1 [expr2]'. Składnia wyrażenia „expr1[expr2]” jest niejednoznaczna, gdy jest używana jako argument. Zobacz https://aka.ms/fsharp-index-notation. Jeśli zamierzasz indeksować lub fragmentować, to w pozycji argumentu musi być użyte wyrażenie „expr1.[expr2]”. Jeśli wywołujesz funkcję z wieloma argumentami typu curried, dodaj spację między nimi, np. „someFunction expr1 [expr2]”. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 142eb6c05fb..0dad23e2c85 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -482,6 +482,11 @@ nullness checking + + optimize a curried closure argument when its inlining fails + optimize a curried closure argument when its inlining fails + + Support for OverloadResolutionPriorityAttribute to prioritize method overloads. Support for OverloadResolutionPriorityAttribute to prioritize method overloads. @@ -592,6 +597,11 @@ Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`. + + ordering explicit type arguments by their constraint dependencies + ordering explicit type arguments by their constraint dependencies + + Union case test properties Propriedades de teste de caso de união @@ -707,6 +717,11 @@ O atributo 'InlineIfLambda' está presente na assinatura, mas não na implementação. + + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + + XML comment is not placed on a valid language element. O comentário XML não está inserido em um elemento de linguagem válido. @@ -1607,6 +1622,11 @@ Only structs may be given the 'ExtendedLayoutAttribute' + + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + + The syntax 'expr1[expr2]' is ambiguous when used as an argument. See https://aka.ms/fsharp-index-notation. If you intend indexing or slicing then you must use 'expr1.[expr2]' in argument position. If calling a function with multiple curried arguments, add a space between them, e.g. 'someFunction expr1 [expr2]'. A sintaxe '[expr1][expr2]' é ambígua quando usada como um argumento. Consulte https://aka.ms/fsharp-index-notation. Se você pretende indexar ou colocar em fatias, deve usar '(expr1).[expr2]' na posição do argumento. Se chamar uma função com vários argumentos na forma curried, adicione um espaço entre eles, por exemplo, 'someFunction [expr1] [expr2]'. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 0a13387efec..41880f7c7b7 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -482,6 +482,11 @@ nullness checking + + optimize a curried closure argument when its inlining fails + optimize a curried closure argument when its inlining fails + + Support for OverloadResolutionPriorityAttribute to prioritize method overloads. Support for OverloadResolutionPriorityAttribute to prioritize method overloads. @@ -592,6 +597,11 @@ Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`. + + ordering explicit type arguments by their constraint dependencies + ordering explicit type arguments by their constraint dependencies + + Union case test properties Свойства теста союзного случая @@ -707,6 +717,11 @@ Атрибут "InlineIfLambda" присутствует в сигнатуре, но отсутствует в реализации. + + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + + XML comment is not placed on a valid language element. За XML-комментарием не следует допустимый элемент языка. @@ -1607,6 +1622,11 @@ Only structs may be given the 'ExtendedLayoutAttribute' + + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + + The syntax 'expr1[expr2]' is ambiguous when used as an argument. See https://aka.ms/fsharp-index-notation. If you intend indexing or slicing then you must use 'expr1.[expr2]' in argument position. If calling a function with multiple curried arguments, add a space between them, e.g. 'someFunction expr1 [expr2]'. Синтаксис "expr1[expr2]" неоднозначен при использовании в качестве аргумента. См. https://aka.ms/fsharp-index-notation. Если вы намереваетесь индексировать или разрезать, необходимо использовать "expr1.[expr2]" в позиции аргумента. При вызове функции с несколькими каррированными аргументами добавьте пробел между ними, например "someFunction expr1 [expr2]". diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 151f641cef5..4830fb04d89 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -482,6 +482,11 @@ nullness checking + + optimize a curried closure argument when its inlining fails + optimize a curried closure argument when its inlining fails + + Support for OverloadResolutionPriorityAttribute to prioritize method overloads. Support for OverloadResolutionPriorityAttribute to prioritize method overloads. @@ -592,6 +597,11 @@ Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`. + + ordering explicit type arguments by their constraint dependencies + ordering explicit type arguments by their constraint dependencies + + Union case test properties Birleşim durumu test özellikleri @@ -707,6 +717,11 @@ 'InlineIfLambda' özniteliği imzada var ama uygulamada yok. + + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + + XML comment is not placed on a valid language element. XML açıklaması geçerli bir dil öğesine yerleştirilmemiş. @@ -1607,6 +1622,11 @@ Only structs may be given the 'ExtendedLayoutAttribute' + + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + + The syntax 'expr1[expr2]' is ambiguous when used as an argument. See https://aka.ms/fsharp-index-notation. If you intend indexing or slicing then you must use 'expr1.[expr2]' in argument position. If calling a function with multiple curried arguments, add a space between them, e.g. 'someFunction expr1 [expr2]'. Söz dizimi “expr1[expr2]” artık dizin oluşturma için ayrılmıştır ve bağımsız değişken olarak kullanıldığında belirsizdir. https://aka.ms/fsharp-index-notation'a bakın. Dizin oluşturmayı veya dilimlemeyi düşünüyorsanız, bağımsız değişken konumunda “expr1.[expr2]” kullanmalısınız. Birden çok curry bağımsız değişkenli bir işlev çağırıyorsanız, aralarına bir boşluk ekleyin, örn. “someFunction expr1 [expr2]”. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index f25f008f0ef..4896d310e8c 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -482,6 +482,11 @@ nullness checking + + optimize a curried closure argument when its inlining fails + optimize a curried closure argument when its inlining fails + + Support for OverloadResolutionPriorityAttribute to prioritize method overloads. Support for OverloadResolutionPriorityAttribute to prioritize method overloads. @@ -592,6 +597,11 @@ Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`. + + ordering explicit type arguments by their constraint dependencies + ordering explicit type arguments by their constraint dependencies + + Union case test properties 联合用例测试属性 @@ -707,6 +717,11 @@ "InlineIfLambda" 属性存在于签名中,但实现中不存在。 + + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + + XML comment is not placed on a valid language element. 未将 XML 注释放在有效语言元素上。 @@ -1607,6 +1622,11 @@ Only structs may be given the 'ExtendedLayoutAttribute' + + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + + The syntax 'expr1[expr2]' is ambiguous when used as an argument. See https://aka.ms/fsharp-index-notation. If you intend indexing or slicing then you must use 'expr1.[expr2]' in argument position. If calling a function with multiple curried arguments, add a space between them, e.g. 'someFunction expr1 [expr2]'. 语法“expr1[expr2]”用作参数时不明确。请参阅 https://aka.ms/fsharp-index-notation。如果要索引或切片,则必须在参数位置使用“expr1.[expr2]”。如果使用多个扩充参数调用函数,请在它们之间添加空格,例如“someFunction expr1 [expr2]”。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 71cd73b20c1..d73e869c017 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -482,6 +482,11 @@ nullness checking + + optimize a curried closure argument when its inlining fails + optimize a curried closure argument when its inlining fails + + Support for OverloadResolutionPriorityAttribute to prioritize method overloads. Support for OverloadResolutionPriorityAttribute to prioritize method overloads. @@ -592,6 +597,11 @@ Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`. + + ordering explicit type arguments by their constraint dependencies + ordering explicit type arguments by their constraint dependencies + + Union case test properties 聯集案例測試屬性 @@ -707,6 +717,11 @@ 'InlineIfLambda' 屬性存在於簽章中,但不存在於實作中。 + + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + The 'OptimizeClosureIfNotInlined' attribute is present in the signature but not the implementation. + + XML comment is not placed on a valid language element. XML 註解沒有放置在有效的語言元素上。 @@ -1607,6 +1622,11 @@ Only structs may be given the 'ExtendedLayoutAttribute' + + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + The 'OptimizeClosureIfNotInlined' attribute requires 'InlineIfLambda' on a separately curried parameter of an inline function or method whose type is a curried F# function of arity 2 to 5. + + The syntax 'expr1[expr2]' is ambiguous when used as an argument. See https://aka.ms/fsharp-index-notation. If you intend indexing or slicing then you must use 'expr1.[expr2]' in argument position. If calling a function with multiple curried arguments, add a space between them, e.g. 'someFunction expr1 [expr2]'. 語法 'expr1[expr2]' 用作引數時不明確。請參閱 https://aka.ms/fsharp-index-notation。如果您要編製索引或切割,則必須在引數位置使用 'expr1.[expr2]'。如果要呼叫具有多個調用引數的函式,請在它們之間新增空格,例如 'someFunction expr1 [expr2]'。 diff --git a/src/FSharp.Core/array.fs b/src/FSharp.Core/array.fs index b57fda0538a..b7fd6a49af6 100644 --- a/src/FSharp.Core/array.fs +++ b/src/FSharp.Core/array.fs @@ -20,9 +20,18 @@ module Array = if isNull arg then nullArg argName - let inline indexNotFound () = + [] + let indexNotFound () = raise (KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) + [] + let differentLengthArrays (arg1: string) (len1: int) (arg2: string) (len2: int) = + invalidArgDifferentArrayLength arg1 len1 arg2 len2 + [] let length (array: _ array) = checkNonNull "array" array @@ -350,16 +359,15 @@ module Array = res [] - let iter2 action (array1: 'T array) (array2: 'U array) = + let inline iter2 ([] action) (array1: 'T array) (array2: 'U array) = checkNonNull "array1" array1 checkNonNull "array2" array2 - let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(action) if array1.Length <> array2.Length then - invalidArgDifferentArrayLength "array1" array1.Length "array2" array2.Length + differentLengthArrays "array1" array1.Length "array2" array2.Length for i = 0 to array1.Length - 1 do - f.Invoke(array1.[i], array2.[i]) + action array1.[i] array2.[i] [] let distinctBy projection (array: 'T array) = @@ -432,24 +440,22 @@ module Array = res [] - let iteri action (array: 'T array) = + let inline iteri ([] action) (array: 'T array) = checkNonNull "array" array - let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(action) for i = 0 to array.Length - 1 do - f.Invoke(i, array.[i]) + action i array.[i] [] - let iteri2 action (array1: 'T array) (array2: 'U array) = + let inline iteri2 ([] action) (array1: 'T array) (array2: 'U array) = checkNonNull "array1" array1 checkNonNull "array2" array2 - let f = OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt(action) if array1.Length <> array2.Length then - invalidArgDifferentArrayLength "array1" array1.Length "array2" array2.Length + differentLengthArrays "array1" array1.Length "array2" array2.Length for i = 0 to array1.Length - 1 do - f.Invoke(i, array1.[i], array2.[i]) + action i array1.[i] array2.[i] [] let mapi (mapping: int -> 'T -> 'U) (array: 'T array) = @@ -497,22 +503,21 @@ module Array = state [] - let exists2 predicate (array1: _ array) (array2: _ array) = + let inline exists2 ([] predicate) (array1: _ array) (array2: _ array) = checkNonNull "array1" array1 checkNonNull "array2" array2 - let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(predicate) let len1 = array1.Length if len1 <> array2.Length then - invalidArgDifferentArrayLength "array1" array1.Length "array2" array2.Length + differentLengthArrays "array1" array1.Length "array2" array2.Length let rec loop i = - i < len1 && (f.Invoke(array1.[i], array2.[i]) || loop (i + 1)) + i < len1 && (predicate array1.[i] array2.[i] || loop (i + 1)) loop 0 [] - let forall (predicate: 'T -> bool) (array: 'T array) = + let inline forall ([] predicate: 'T -> bool) (array: 'T array) = checkNonNull "array" array let len = array.Length @@ -522,17 +527,16 @@ module Array = loop 0 [] - let forall2 predicate (array1: _ array) (array2: _ array) = + let inline forall2 ([] predicate) (array1: _ array) (array2: _ array) = checkNonNull "array1" array1 checkNonNull "array2" array2 - let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(predicate) let len1 = array1.Length if len1 <> array2.Length then - invalidArgDifferentArrayLength "array1" array1.Length "array2" array2.Length + differentLengthArrays "array1" array1.Length "array2" array2.Length let rec loop i = - i >= len1 || (f.Invoke(array1.[i], array2.[i]) && loop (i + 1)) + i >= len1 || (predicate array1.[i] array2.[i] && loop (i + 1)) loop 0 @@ -594,7 +598,7 @@ module Array = groupByRefType projection array [] - let pick chooser (array: _ array) = + let inline pick ([] chooser) (array: _ array) = checkNonNull "array" array let rec loop i = @@ -608,7 +612,7 @@ module Array = loop 0 [] - let tryPick chooser (array: _ array) = + let inline tryPick ([] chooser) (array: _ array) = checkNonNull "array" array let rec loop i = @@ -1159,7 +1163,7 @@ module Array = scatterPartitioned isChoice1 results1 results2 count1 [] - let find predicate (array: _ array) = + let inline find ([] predicate) (array: _ array) = checkNonNull "array" array let rec loop i = @@ -1212,9 +1216,15 @@ module Array = | resLen -> Microsoft.FSharp.Primitives.Basics.Array.subUnchecked i resLen array [] - let findBack predicate (array: _ array) = + let inline findBack ([] predicate) (array: _ array) = checkNonNull "array" array - Microsoft.FSharp.Primitives.Basics.Array.findBack predicate array + + let rec loop i = + if i < 0 then indexNotFound () + elif predicate array.[i] then array.[i] + else loop (i - 1) + + loop (array.Length - 1) [] let tryFindBack predicate (array: _ array) = @@ -1222,9 +1232,15 @@ module Array = Microsoft.FSharp.Primitives.Basics.Array.tryFindBack predicate array [] - let findIndexBack predicate (array: _ array) = + let inline findIndexBack ([] predicate) (array: _ array) = checkNonNull "array" array - Microsoft.FSharp.Primitives.Basics.Array.findIndexBack predicate array + + let rec loop i = + if i < 0 then indexNotFound () + elif predicate array.[i] then i + else loop (i - 1) + + loop (array.Length - 1) [] let tryFindIndexBack predicate (array: _ array) = @@ -1395,68 +1411,72 @@ module Array = res [] - let fold<'T, 'State> (folder: 'State -> 'T -> 'State) (state: 'State) (array: 'T array) = + let inline fold<'T, 'State> + ([] folder: 'State -> 'T -> 'State) + (state: 'State) + (array: 'T array) + = checkNonNull "array" array - let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(folder) let mutable state = state for i = 0 to array.Length - 1 do - state <- f.Invoke(state, array.[i]) + state <- folder state array.[i] state [] - let foldBack<'T, 'State> (folder: 'T -> 'State -> 'State) (array: 'T array) (state: 'State) = + let inline foldBack<'T, 'State> + ([] folder: 'T -> 'State -> 'State) + (array: 'T array) + (state: 'State) + = checkNonNull "array" array - let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(folder) let mutable res = state for i = array.Length - 1 downto 0 do - res <- f.Invoke(array.[i], res) + res <- folder array.[i] res res [] - let foldBack2<'T1, 'T2, 'State> folder (array1: 'T1 array) (array2: 'T2 array) (state: 'State) = + let inline foldBack2<'T1, 'T2, 'State> + ([] folder: 'T1 -> 'T2 -> 'State -> 'State) + (array1: 'T1 array) + (array2: 'T2 array) + (state: 'State) + = checkNonNull "array1" array1 checkNonNull "array2" array2 - let f = OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt(folder) let mutable res = state let len = array1.Length if len <> array2.Length then - invalidArgDifferentArrayLength "array1" len "array2" array2.Length + differentLengthArrays "array1" len "array2" array2.Length for i = len - 1 downto 0 do - res <- f.Invoke(array1.[i], array2.[i], res) + res <- folder array1.[i] array2.[i] res res [] - let fold2<'T1, 'T2, 'State> folder (state: 'State) (array1: 'T1 array) (array2: 'T2 array) = + let inline fold2<'T1, 'T2, 'State> + ([] folder: 'State -> 'T1 -> 'T2 -> 'State) + (state: 'State) + (array1: 'T1 array) + (array2: 'T2 array) + = checkNonNull "array1" array1 checkNonNull "array2" array2 - let f = OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt(folder) let mutable state = state if array1.Length <> array2.Length then - invalidArgDifferentArrayLength "array1" array1.Length "array2" array2.Length + differentLengthArrays "array1" array1.Length "array2" array2.Length for i = 0 to array1.Length - 1 do - state <- f.Invoke(state, array1.[i], array2.[i]) + state <- folder state array1.[i] array2.[i] state - let foldSubRight f (array: _ array) start fin acc = - checkNonNull "array" array - let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(f) - let mutable res = acc - - for i = fin downto start do - res <- f.Invoke(array.[i], res) - - res - let scanSubLeft f initState (array: _ array) start fin = checkNonNull "array" array let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(f) @@ -1494,30 +1514,34 @@ module Array = init (array.Length - 1) (fun i -> array.[i], array.[i + 1]) [] - let reduce reduction (array: _ array) = + let inline reduce ([] reduction) (array: _ array) = checkNonNull "array" array let len = array.Length if len = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString else - let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(reduction) let mutable res = array.[0] for i = 1 to array.Length - 1 do - res <- f.Invoke(res, array.[i]) + res <- reduction res array.[i] res [] - let reduceBack reduction (array: _ array) = + let inline reduceBack ([] reduction) (array: _ array) = checkNonNull "array" array let len = array.Length if len = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString else - foldSubRight reduction array 0 (len - 2) array.[len - 1] + let mutable res = array.[len - 1] + + for i = len - 2 downto 0 do + res <- reduction array.[i] res + + res [] let sortInPlaceWith comparer (array: 'T array) = @@ -1596,7 +1620,7 @@ module Array = Seq.toArray source [] - let findIndex predicate (array: _ array) = + let inline findIndex ([] predicate) (array: _ array) = checkNonNull "array" array let len = array.Length diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index 397df39d7cb..9af0d3e18bb 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -15,6 +15,18 @@ open Microsoft.FSharp.Collections [] module Array = + /// This function is for use by compiled F# code and should not be used directly. + [] + val indexNotFound: unit -> 'T + + /// This function is for use by compiled F# code and should not be used directly. + [] + val differentLengthArrays: arg1: string -> len1: int -> arg2: string -> len2: int -> 'T + /// Returns a new array that contains all pairings of elements from the first and second arrays. /// /// The first input array. @@ -464,7 +476,7 @@ module Array = /// /// This is an O(n) operation in the worst case, where n is the length of the array. [] - val tryPick: chooser: ('T -> 'U option) -> array: 'T array -> 'U option + val inline tryPick: chooser: ('T -> 'U option) -> array: 'T array -> 'U option /// Fills a range of elements of the array with the given value. /// @@ -523,7 +535,7 @@ module Array = /// /// This is an O(n) operation in the worst case, where n is the length of the array. [] - val pick: chooser: ('T -> 'U option) -> array: 'T array -> 'U + val inline pick: chooser: ('T -> 'U option) -> array: 'T array -> 'U /// Applies the given function to each element of the array. Returns /// the array comprised of the results x for each element where @@ -857,7 +869,7 @@ module Array = /// Evaluates to true /// [] - val exists2: predicate: ('T1 -> 'T2 -> bool) -> array1: 'T1 array -> array2: 'T2 array -> bool + val inline exists2: predicate: ('T1 -> 'T2 -> bool) -> array1: 'T1 array -> array2: 'T2 array -> bool /// Returns a new collection containing only the elements of the collection /// for which the given predicate returns "true". @@ -914,7 +926,7 @@ module Array = /// /// This is an O(n) operation in the worst case, where n is the length of the array. [] - val find: predicate: ('T -> bool) -> array: 'T array -> 'T + val inline find: predicate: ('T -> bool) -> array: 'T array -> 'T /// Returns the last element for which the given function returns 'true'. /// Raise if no such element exists. @@ -948,7 +960,7 @@ module Array = /// /// This is an O(n) operation in the worst case, where n is the length of the array. [] - val findBack: predicate: ('T -> bool) -> array: 'T array -> 'T + val inline findBack: predicate: ('T -> bool) -> array: 'T array -> 'T /// Returns the index of the first element in the array /// that satisfies the given predicate. Raise if @@ -982,7 +994,7 @@ module Array = /// /// This is an O(n) operation in the worst case, where n is the length of the array. [] - val findIndex: predicate: ('T -> bool) -> array: 'T array -> int + val inline findIndex: predicate: ('T -> bool) -> array: 'T array -> int /// Returns the index of the last element in the array /// that satisfies the given predicate. Raise if @@ -1017,7 +1029,7 @@ module Array = /// /// This is an O(n) operation in the worst case, where n is the length of the array. [] - val findIndexBack: predicate: ('T -> bool) -> array: 'T array -> int + val inline findIndexBack: predicate: ('T -> bool) -> array: 'T array -> int /// Tests if all elements of the array satisfy the given predicate. /// @@ -1042,7 +1054,7 @@ module Array = /// /// [] - val forall: predicate: ('T -> bool) -> array: 'T array -> bool + val inline forall: predicate: ('T -> bool) -> array: 'T array -> bool /// Tests if all corresponding elements of the array satisfy the given predicate pairwise. /// @@ -1091,7 +1103,7 @@ module Array = /// Throws ArgumentException. /// [] - val forall2: predicate: ('T1 -> 'T2 -> bool) -> array1: 'T1 array -> array2: 'T2 array -> bool + val inline forall2: predicate: ('T1 -> 'T2 -> bool) -> array1: 'T1 array -> array2: 'T2 array -> bool /// Applies a function to each element of the collection, threading an accumulator argument /// through the computation. If the input function is f and the elements are i0...iN then computes @@ -1123,7 +1135,7 @@ module Array = /// /// This is an O(n) operation, where n is the length of the array. [] - val fold<'T, 'State> : folder: ('State -> 'T -> 'State) -> state: 'State -> array: 'T array -> 'State + val inline fold<'T, 'State> : folder: ('State -> 'T -> 'State) -> state: 'State -> array: 'T array -> 'State /// Applies a function to each element of the array, starting from the end, threading an accumulator argument /// through the computation. If the input function is f and the elements are i0...iN then computes @@ -1168,7 +1180,7 @@ module Array = /// /// This is an O(n) operation, where n is the length of the array. [] - val foldBack<'T, 'State> : folder: ('T -> 'State -> 'State) -> array: 'T array -> state: 'State -> 'State + val inline foldBack<'T, 'State> : folder: ('T -> 'State -> 'State) -> array: 'T array -> state: 'State -> 'State /// Applies a function to pairs of elements drawn from the two collections, /// left-to-right, threading an accumulator argument @@ -1204,7 +1216,7 @@ module Array = /// /// This is an O(n) operation, where n is the length of the arrays. [] - val fold2<'T1, 'T2, 'State> : + val inline fold2<'T1, 'T2, 'State> : folder: ('State -> 'T1 -> 'T2 -> 'State) -> state: 'State -> array1: 'T1 array -> array2: 'T2 array -> 'State /// Apply a function to pairs of elements drawn from the two collections, right-to-left, @@ -1255,7 +1267,7 @@ module Array = /// /// This is an O(n) operation, where n is the length of the arrays. [] - val foldBack2<'T1, 'T2, 'State> : + val inline foldBack2<'T1, 'T2, 'State> : folder: ('T1 -> 'T2 -> 'State -> 'State) -> array1: 'T1 array -> array2: 'T2 array -> state: 'State -> 'State /// Gets an element from an array. @@ -1492,7 +1504,7 @@ module Array = /// /// This is an O(n) operation, where n is the length of the arrays. [] - val iter2: action: ('T1 -> 'T2 -> unit) -> array1: 'T1 array -> array2: 'T2 array -> unit + val inline iter2: action: ('T1 -> 'T2 -> unit) -> array1: 'T1 array -> array2: 'T2 array -> unit /// Applies the given function to each element of the array. The integer passed to the /// function indicates the index of element. @@ -1519,7 +1531,7 @@ module Array = /// /// This is an O(n) operation, where n is the length of the array. [] - val iteri: action: (int -> 'T -> unit) -> array: 'T array -> unit + val inline iteri: action: (int -> 'T -> unit) -> array: 'T array -> unit /// Applies the given function to pair of elements drawn from matching indices in two arrays, /// also passing the index of the elements. The two arrays must have the same lengths, @@ -1550,7 +1562,7 @@ module Array = /// /// This is an O(n) operation, where n is the length of the arrays. [] - val iteri2: action: (int -> 'T1 -> 'T2 -> unit) -> array1: 'T1 array -> array2: 'T2 array -> unit + val inline iteri2: action: (int -> 'T1 -> 'T2 -> unit) -> array1: 'T1 array -> array2: 'T2 array -> unit /// Returns the last element of the array. /// @@ -2154,7 +2166,7 @@ module Array = /// /// This is an O(n) operation, where n is the length of the array. [] - val reduce: reduction: ('T -> 'T -> 'T) -> array: 'T array -> 'T + val inline reduce: reduction: ('T -> 'T -> 'T) -> array: 'T array -> 'T /// Applies a function to each element of the array, starting from the end, threading an accumulator argument /// through the computation. If the input function is f and the elements are i0...iN @@ -2180,7 +2192,7 @@ module Array = /// /// This is an O(n) operation, where n is the length of the array. [] - val reduceBack: reduction: ('T -> 'T -> 'T) -> array: 'T array -> 'T + val inline reduceBack: reduction: ('T -> 'T -> 'T) -> array: 'T array -> 'T /// Creates an array by replicating the given initial value. /// diff --git a/src/FSharp.Core/list.fs b/src/FSharp.Core/list.fs index fde53cb80ff..f02c8853233 100644 --- a/src/FSharp.Core/list.fs +++ b/src/FSharp.Core/list.fs @@ -18,9 +18,30 @@ module List = if isNull arg then nullArg argName - let inline indexNotFound () = + [] + let indexNotFound () = raise (KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) + [] + let emptyListError () = + invalidArg "list" (SR.GetString(SR.inputListWasEmpty)) + + [] + let differentLengthLists (arg1: string) (arg2: string) (diff: int) = + invalidArgDifferentListLength arg1 arg2 diff + + [] + let listsDifferentLengths () = + invalidArg "list2" (SR.GetString(SR.listsHadDifferentLengths)) + [] let length (list: 'T list) = list.Length @@ -218,7 +239,7 @@ module List = Microsoft.FSharp.Primitives.Basics.List.takeWhile predicate list [] - let inline iteri ([] action) (list: 'T list) = + let inline iteri ([] action) (list: 'T list) = let mutable n = 0 for x in list do @@ -242,32 +263,28 @@ module List = result [] - let iter2 action list1 list2 = - let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(action) - + let inline iter2 ([] action) list1 list2 = let rec loop list1 list2 = match list1, list2 with | [], [] -> () | h1 :: t1, h2 :: t2 -> - f.Invoke(h1, h2) + action h1 h2 loop t1 t2 - | [], xs2 -> invalidArgDifferentListLength "list1" "list2" xs2.Length - | xs1, [] -> invalidArgDifferentListLength "list2" "list1" xs1.Length + | [], xs2 -> differentLengthLists "list1" "list2" xs2.Length + | xs1, [] -> differentLengthLists "list2" "list1" xs1.Length loop list1 list2 [] - let iteri2 action list1 list2 = - let f = OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt(action) - + let inline iteri2 ([] action) list1 list2 = let rec loop n list1 list2 = match list1, list2 with | [], [] -> () | h1 :: t1, h2 :: t2 -> - f.Invoke(n, h1, h2) + action n h1 h2 loop (n + 1) t1 t2 - | [], xs2 -> invalidArgDifferentListLength "list1" "list2" xs2.Length - | xs1, [] -> invalidArgDifferentListLength "list2" "list1" xs1.Length + | [], xs2 -> differentLengthLists "list1" "list2" xs2.Length + | xs1, [] -> differentLengthLists "list2" "list1" xs1.Length loop 0 list1 list2 @@ -284,26 +301,26 @@ module List = Microsoft.FSharp.Primitives.Basics.List.map2 mapping list1 list2 [] - let fold<'T, 'State> folder (state: 'State) (list: 'T list) = - match list with - | [] -> state - | _ -> - let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(folder) - let mutable acc = state + let inline fold<'T, 'State> + ([] folder: 'State -> 'T -> 'State) + (state: 'State) + (list: 'T list) + = + let mutable acc = state - for x in list do - acc <- f.Invoke(acc, x) + for x in list do + acc <- folder acc x - acc + acc [] let pairwise (list: 'T list) = Microsoft.FSharp.Primitives.Basics.List.pairwise list [] - let reduce reduction list = + let inline reduce ([] reduction) list = match list with - | [] -> invalidArg "list" (SR.GetString(SR.inputListWasEmpty)) + | [] -> emptyListError () | h :: t -> fold reduction h t [] @@ -315,15 +332,18 @@ module List = [ value ] [] - let fold2<'T1, 'T2, 'State> folder (state: 'State) (list1: 'T1 list) (list2: 'T2 list) = - let f = OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt(folder) - + let inline fold2<'T1, 'T2, 'State> + ([] folder: 'State -> 'T1 -> 'T2 -> 'State) + (state: 'State) + (list1: 'T1 list) + (list2: 'T2 list) + = let rec loop acc list1 list2 = match list1, list2 with | [], [] -> acc - | h1 :: t1, h2 :: t2 -> loop (f.Invoke(acc, h1, h2)) t1 t2 - | [], xs2 -> invalidArgDifferentListLength "list1" "list2" xs2.Length - | xs1, [] -> invalidArgDifferentListLength "list2" "list1" xs1.Length + | h1 :: t1, h2 :: t2 -> loop (folder acc h1 h2) t1 t2 + | [], xs2 -> differentLengthLists "list1" "list2" xs2.Length + | xs1, [] -> differentLengthLists "list2" "list1" xs1.Length loop state list1 list2 @@ -428,28 +448,34 @@ module List = | [], xs2 -> invalidArgDifferentListLength "list1" "list2" xs2.Length | xs1, [] -> invalidArgDifferentListLength "list2" "list1" xs1.Length - let rec forall2aux (f: OptimizedClosures.FSharpFunc<_, _, _>) list1 list2 = - match list1, list2 with - | [], [] -> true - | h1 :: t1, h2 :: t2 -> f.Invoke(h1, h2) && forall2aux f t1 t2 - | [], xs2 -> invalidArgDifferentListLength "list1" "list2" xs2.Length - | xs1, [] -> invalidArgDifferentListLength "list2" "list1" xs1.Length - [] - let forall2 predicate list1 list2 = - match list1, list2 with - | [], [] -> true - | _ -> - let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(predicate) - forall2aux f list1 list2 + let inline forall2 ([] predicate) list1 list2 = + let rec loop list1 list2 = + match list1, list2 with + | [], [] -> true + | h1 :: t1, h2 :: t2 -> predicate h1 h2 && loop t1 t2 + | [], xs2 -> differentLengthLists "list1" "list2" xs2.Length + | xs1, [] -> differentLengthLists "list2" "list1" xs1.Length + + loop list1 list2 [] - let forall predicate list = - Microsoft.FSharp.Primitives.Basics.List.forall predicate list + let inline forall ([] predicate) list = + let rec loop list = + match list with + | [] -> true + | h :: t -> predicate h && loop t + + loop list [] - let exists predicate list = - Microsoft.FSharp.Primitives.Basics.List.exists predicate list + let inline exists ([] predicate) list = + let rec loop list = + match list with + | [] -> false + | h :: t -> predicate h || loop t + + loop list [] let inline contains value source = @@ -463,29 +489,24 @@ module List = contains value source - let rec exists2aux (f: OptimizedClosures.FSharpFunc<_, _, _>) list1 list2 = - match list1, list2 with - | [], [] -> false - | h1 :: t1, h2 :: t2 -> f.Invoke(h1, h2) || exists2aux f t1 t2 - | _ -> invalidArg "list2" (SR.GetString(SR.listsHadDifferentLengths)) - [] - let rec exists2 predicate list1 list2 = - match list1, list2 with - | [], [] -> false - | _ -> - let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(predicate) - exists2aux f list1 list2 + let inline exists2 ([] predicate) list1 list2 = + let rec loop list1 list2 = + match list1, list2 with + | [], [] -> false + | h1 :: t1, h2 :: t2 -> predicate h1 h2 || loop t1 t2 + | _ -> listsDifferentLengths () + + loop list1 list2 [] - let rec find predicate list = - match list with - | [] -> indexNotFound () - | h :: t -> - if predicate h then - h - else - find predicate t + let inline find ([] predicate) list = + let rec loop list = + match list with + | [] -> indexNotFound () + | h :: t -> if predicate h then h else loop t + + loop list [] let rec tryFind predicate list = @@ -508,22 +529,28 @@ module List = |> Microsoft.FSharp.Primitives.Basics.Array.tryFindBack predicate [] - let rec tryPick chooser list = - match list with - | [] -> None - | h :: t -> - match chooser h with - | None -> tryPick chooser t - | r -> r + let inline tryPick ([] chooser) list = + let rec loop list = + match list with + | [] -> None + | h :: t -> + match chooser h with + | None -> loop t + | r -> r + + loop list [] - let rec pick chooser list = - match list with - | [] -> indexNotFound () - | h :: t -> - match chooser h with - | None -> pick chooser t - | Some r -> r + let inline pick ([] chooser) list = + let rec loop list = + match list with + | [] -> indexNotFound () + | h :: t -> + match chooser h with + | None -> loop t + | Some r -> r + + loop list [] let filter predicate list = @@ -627,10 +654,13 @@ module List = loop count list [] - let rec skipWhile predicate list = - match list with - | head :: tail when predicate head -> skipWhile predicate tail - | _ -> list + let inline skipWhile ([] predicate) list = + let rec loop list = + match list with + | head :: tail when predicate head -> loop tail + | _ -> list + + loop list [] let sortWith comparer list = @@ -685,7 +715,7 @@ module List = Seq.ofList list [] - let findIndex predicate list = + let inline findIndex ([] predicate) list = let rec loop n list = match list with | [] -> indexNotFound () diff --git a/src/FSharp.Core/list.fsi b/src/FSharp.Core/list.fsi index 82d7c6f5573..9c63416b285 100644 --- a/src/FSharp.Core/list.fsi +++ b/src/FSharp.Core/list.fsi @@ -15,6 +15,22 @@ open Microsoft.FSharp.Collections [] module List = + /// This function is for use by compiled F# code and should not be used directly. + [] + val indexNotFound: unit -> 'T + + /// This function is for use by compiled F# code and should not be used directly. + [] + val emptyListError: unit -> 'T + + /// This function is for use by compiled F# code and should not be used directly. + [] + val differentLengthLists: arg1: string -> arg2: string -> diff: int -> 'T + + /// This function is for use by compiled F# code and should not be used directly. + [] + val listsDifferentLengths: unit -> 'T + /// Returns a new list that contains all pairings of elements from two lists. /// /// The first input list. @@ -624,7 +640,7 @@ module List = /// /// [] - val exists: predicate:('T -> bool) -> list:'T list -> bool + val inline exists: predicate:('T -> bool) -> list:'T list -> bool /// Tests if any pair of corresponding elements of the lists satisfies the given predicate. /// @@ -654,7 +670,7 @@ module List = /// /// [] - val exists2: predicate:('T1 -> 'T2 -> bool) -> list1:'T1 list -> list2:'T2 list -> bool + val inline exists2: predicate:('T1 -> 'T2 -> bool) -> list1:'T1 list -> list2:'T2 list -> bool /// Returns the first element for which the given function returns True. /// Raises KeyNotFoundException if no such element exists. @@ -682,7 +698,7 @@ module List = /// /// This is an O(n) operation in the worst case, where n is the length of the list. [] - val find: predicate:('T -> bool) -> list:'T list -> 'T + val inline find: predicate:('T -> bool) -> list:'T list -> 'T /// Returns the last element for which the given function returns True. /// Raises KeyNotFoundException if no such element exists. @@ -739,7 +755,7 @@ module List = /// /// This is an O(n) operation in the worst case, where n is the length of the list. [] - val findIndex: predicate:('T -> bool) -> list:'T list -> int + val inline findIndex: predicate:('T -> bool) -> list:'T list -> int /// Returns the index of the last element in the list /// that satisfies the given predicate. @@ -841,7 +857,7 @@ module List = /// /// This is an O(n) operation, where n is the length of the list. [] - val fold<'T,'State> : folder:('State -> 'T -> 'State) -> state:'State -> list:'T list -> 'State + val inline fold<'T,'State> : folder:('State -> 'T -> 'State) -> state:'State -> list:'T list -> 'State /// Applies a function to corresponding elements of two collections, threading an accumulator argument /// through the computation. The collections must have identical sizes. @@ -873,7 +889,7 @@ module List = /// /// This is an O(n) operation, where n is the length of the lists. [] - val fold2<'T1,'T2,'State> : folder:('State -> 'T1 -> 'T2 -> 'State) -> state:'State -> list1:'T1 list -> list2:'T2 list -> 'State + val inline fold2<'T1,'T2,'State> : folder:('State -> 'T1 -> 'T2 -> 'State) -> state:'State -> list1:'T1 list -> list2:'T2 list -> 'State /// Applies a function to each element of the collection, starting from the end, threading an accumulator argument /// through the computation. If the input function is f and the elements are i0...iN then @@ -989,7 +1005,7 @@ module List = /// /// [] - val forall: predicate:('T -> bool) -> list:'T list -> bool + val inline forall: predicate:('T -> bool) -> list:'T list -> bool /// Tests if all corresponding elements of the collection satisfy the given predicate pairwise. /// @@ -1036,7 +1052,7 @@ module List = /// Throws ArgumentException. /// [] - val forall2: predicate:('T1 -> 'T2 -> bool) -> list1:'T1 list -> list2:'T2 list -> bool + val inline forall2: predicate:('T1 -> 'T2 -> bool) -> list1:'T1 list -> list2:'T2 list -> bool /// Applies a key-generating function to each element of a list and yields a list of /// unique keys. Each unique key contains a list of all elements that match @@ -1239,7 +1255,7 @@ module List = /// /// This is an O(n) operation, where n is the length of the lists. [] - val iter2: action:('T1 -> 'T2 -> unit) -> list1:'T1 list -> list2:'T2 list -> unit + val inline iter2: action:('T1 -> 'T2 -> unit) -> list1:'T1 list -> list2:'T2 list -> unit /// Applies the given function to each element of the collection. The integer passed to the /// function indicates the index of the element. @@ -1292,7 +1308,7 @@ module List = /// /// This is an O(n) operation, where n is the length of the lists. [] - val iteri2: action:(int -> 'T1 -> 'T2 -> unit) -> list1:'T1 list -> list2:'T2 list -> unit + val inline iteri2: action:(int -> 'T1 -> 'T2 -> unit) -> list1:'T1 list -> list2:'T2 list -> unit /// Returns the last element of the list. /// @@ -1816,7 +1832,7 @@ module List = /// /// This is an O(n) operation in the worst case, where n is the length of the list. [] - val pick: chooser:('T -> 'U option) -> list:'T list -> 'U + val inline pick: chooser:('T -> 'U option) -> list:'T list -> 'U /// Returns a list with all elements permuted according to the /// specified permutation. @@ -1865,7 +1881,7 @@ module List = /// Evaluates to 1342, by computing ((1 * 10 + 3) * 10 + 4) * 10 + 2 /// [] - val reduce: reduction:('T -> 'T -> 'T) -> list:'T list -> 'T + val inline reduce: reduction:('T -> 'T -> 'T) -> list:'T list -> 'T /// Applies a function to each element of the collection, starting from the end, threading an accumulator argument /// through the computation. If the input function is f and the elements are i0...iN then computes @@ -2071,7 +2087,7 @@ module List = /// /// This is an O(n) operation in the worst case, where n is the length of the list. [] - val skipWhile: predicate:('T -> bool) -> list:'T list -> 'T list + val inline skipWhile: predicate:('T -> bool) -> list:'T list -> 'T list /// Sorts the given list using the given comparison function. /// @@ -2482,7 +2498,7 @@ module List = /// /// This is an O(n) operation in the worst case, where n is the length of the list. [] - val tryPick: chooser:('T -> 'U option) -> list:'T list -> 'U option + val inline tryPick: chooser:('T -> 'U option) -> list:'T list -> 'U option /// Returns the first element for which the given function returns True. /// Return None if no such element exists. diff --git a/src/FSharp.Core/prim-types.fs b/src/FSharp.Core/prim-types.fs index 11e3ff1cb6a..9a6d0cf85fe 100644 --- a/src/FSharp.Core/prim-types.fs +++ b/src/FSharp.Core/prim-types.fs @@ -272,6 +272,11 @@ namespace Microsoft.FSharp.Core type InlineIfLambdaAttribute() = inherit Attribute() + [] + [] + type OptimizeClosureIfNotInlinedAttribute() = + inherit Attribute() + [] [] type CompilationArgumentCountsAttribute(counts:int array) = diff --git a/src/FSharp.Core/prim-types.fsi b/src/FSharp.Core/prim-types.fsi index 201013fb97f..2947c5999c7 100644 --- a/src/FSharp.Core/prim-types.fsi +++ b/src/FSharp.Core/prim-types.fsi @@ -807,6 +807,18 @@ namespace Microsoft.FSharp.Core /// InlineIfLambdaAttribute new: unit -> InlineIfLambdaAttribute + /// Used with InlineIfLambda on a separately curried parameter whose type is a curried F# function of arity 2 to 5. When the enclosing function or method is inlined but the argument is not a known lambda, the compiler adapts the closure once via OptimizedClosures.FSharpFunc instead of dispatching its arity on every fully applied call. + /// + /// Attributes + [] + [] + type OptimizeClosureIfNotInlinedAttribute = + inherit Attribute + + /// Creates an instance of the attribute + /// OptimizeClosureIfNotInlinedAttribute + new: unit -> OptimizeClosureIfNotInlinedAttribute + /// This attribute is generated automatically by the F# compiler to tag functions and members /// that accept a partial application of some of their arguments and return a residual function. /// diff --git a/tests/AheadOfTime/Trimming/check.ps1 b/tests/AheadOfTime/Trimming/check.ps1 index 240ff643de3..49a3af46ca7 100644 --- a/tests/AheadOfTime/Trimming/check.ps1 +++ b/tests/AheadOfTime/Trimming/check.ps1 @@ -63,12 +63,12 @@ function CheckTrim($root, $tfm, $outputfile, $expected_len, $callerLineNumber) { $allErrors = @() # Check net9.0 trimmed assemblies. -$allErrors += CheckTrim -root "SelfContained_Trimming_Test" -tfm "net9.0" -outputfile "FSharp.Core.dll" -expected_len 311296 -callerLineNumber 66 +$allErrors += CheckTrim -root "SelfContained_Trimming_Test" -tfm "net9.0" -outputfile "FSharp.Core.dll" -expected_len 310272 -callerLineNumber 66 # Check net9.0 trimmed assemblies with static linked FSharpCore. # Statically links FSharp.Compiler.Service; the size is stable now that its codegen is # deterministic (#19928/#19929). Update if compiler/trimming output intentionally changes. -$allErrors += CheckTrim -root "StaticLinkedFSharpCore_Trimming_Test" -tfm "net9.0" -outputfile "StaticLinkedFSharpCore_Trimming_Test.dll" -expected_len 9174528 -callerLineNumber 71 +$allErrors += CheckTrim -root "StaticLinkedFSharpCore_Trimming_Test" -tfm "net9.0" -outputfile "StaticLinkedFSharpCore_Trimming_Test.dll" -expected_len 9173504 -callerLineNumber 71 # Check net9.0 trimmed assemblies with F# metadata resources removed $allErrors += CheckTrim -root "FSharpMetadataResource_Trimming_Test" -tfm "net9.0" -outputfile "FSharpMetadataResource_Trimming_Test.dll" -expected_len 7613440 -callerLineNumber 74 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Signatures/SignatureEnforcedAttributes.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Signatures/SignatureEnforcedAttributes.fs index eae5eca01a1..1a65d537a4a 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Signatures/SignatureEnforcedAttributes.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Signatures/SignatureEnforcedAttributes.fs @@ -482,3 +482,22 @@ module Inner = |> shouldSucceed |> withWarningCode 3888 |> withDiagnosticMessageMatches "RequireQualifiedAccess" + + [] + let ``OptimizeClosureIfNotInlined in sig but not impl raises`` () = + let sigSrc = """ +module M +val inline run: [] f: (int -> int -> int) -> x: int -> int +""" + let implSrc = """ +module M +let inline run ([] f: int -> int -> int) (x: int) = f x x +""" + fsFromString (fsi sigSrc) + |> FS + |> withAdditionalSourceFile (fs implSrc) + |> asLibrary + |> withLangVersionPreview + |> compile + |> shouldFail + |> withErrorCode 3917 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/TypesAndTypeConstraints/TypesAndTypeConstraints.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/TypesAndTypeConstraints/TypesAndTypeConstraints.fs index 60e27d37c70..35daf29478b 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/TypesAndTypeConstraints/TypesAndTypeConstraints.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/TypesAndTypeConstraints/TypesAndTypeConstraints.fs @@ -684,3 +684,160 @@ module TypeParameterDefinitions = [] let ``UnitSpecialization_fs`` compilation = compilation |> asExe |> typecheck |> shouldSucceed |> ignore + +// https://github.com/dotnet/fsharp/issues/20103 +module GenericInterfaceConstraintDependencyOrdering = + + let private source = """ +module Repro + +type I<'a> = interface end + +type IServices = + abstract member Register<'a, 'b when 'a :> I<'b>> : ctor: (IServices -> 'a) -> unit + +type Foo(services: IServices) = + interface I + interface I + +let register (services: IServices) = + services.Register Foo + services.Register Foo +""" + + [] + [] + [] + let ``Explicit type args are ordered by constraint dependencies only from langversion 11`` (langVersion: string) (succeeds: bool) = + let result = FSharp source |> asLibrary |> withLangVersion langVersion |> typecheck + if succeeds then result |> shouldSucceed |> ignore + else result |> shouldFail |> withErrorCode 1 |> ignore + + // Overloaded generic method: reordering must not disturb overload resolution (CanMemberSigsMatchUpToCheck). + [] + let ``Overloaded generic method with a dependent constraint resolves under langversion 11`` () = + FSharp """ +module ReproOverload + +type I<'a> = interface end + +type Foo() = + interface I + interface I + +type C = + static member M<'a, 'b when 'a :> I<'b>>(x: 'a, y: 'b) = 1 + static member M<'a, 'b when 'a :> I<'b>>(x: 'a, y: 'b, z: int) = 2 + +let test (f: Foo) = C.M(f, 0) +""" + |> asLibrary + |> withLangVersion11 + |> typecheck + |> shouldSucceed + |> ignore + + [] + [] + [] + [] + [] + let ``Same arity overload resolution rolls back failed candidate constraints`` (typeArguments: string) = + FSharp $""" +module ReproCompetingOverloads + +type I<'a> = interface end + +type Foo() = + interface I + interface I + +type C = + static member M<'a, 'b when 'a :> I<'b> and 'a : struct>(x: 'a, y: obj) = 1 + static member M<'a, 'b when 'a :> I<'b>>(x: obj, y: 'a) = 2 + +[] +let main _ = + let f = Foo() + let selected = C.M<{typeArguments}>(f, f) + if selected <> 2 then failwithf "Expected overload 2, got %%d" selected + 0 +""" + |> asExe + |> withLangVersion11 + |> compileExeAndRun + |> shouldSucceed + |> ignore + + [] + let ``Workaround ordering keeps compiling under langversion 10`` () = + FSharp """ +module ReproWA + +type I<'a> = interface end + +type IServices = + abstract member Register<'a, 'b when 'b :> I<'a>> : ctor: (IServices -> 'b) -> unit + +type Foo(services: IServices) = + interface I + interface I + +let register (services: IServices) = + services.Register Foo + services.Register Foo +""" + |> asLibrary + |> withLangVersion10 + |> typecheck + |> shouldSucceed + |> ignore + + [] + let ``A genuinely unsatisfiable interface argument is still rejected`` () = + FSharp """ +module ReproNeg + +type I<'a> = interface end + +type IServices = + abstract member Register<'a, 'b when 'a :> I<'b>> : ctor: (IServices -> 'a) -> unit + +type Foo(services: IServices) = + interface I + interface I + +let register (services: IServices) = + services.Register Foo +""" + |> asLibrary + |> withLangVersion11 + |> typecheck + |> shouldFail + |> withErrorCode 1 + |> ignore + + // Mutually-referential constraints ('a :> I<'b> and 'b :> J<'a>) form a dependency cycle; the + // reordering must degrade to the original order rather than loop forever (topological-sort cycle path). + [] + let ``Cyclic constraint dependencies degrade gracefully without hanging`` () = + FSharp """ +module ReproCycle + +type I<'a> = interface end +type J<'a> = interface end + +type C = + static member M<'a, 'b when 'a :> I<'b> and 'b :> J<'a>>() = () + +type Foo() = + interface I + interface J + +let test () = C.M() +""" + |> asLibrary + |> withLangVersion11 + |> typecheck + |> shouldSucceed + |> ignore diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall.fs index 976b1c5f68f..854d0726bcb 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall.fs @@ -1759,6 +1759,41 @@ let main _ = |> compileAndRun |> verifySequencePoints + [] + let ``Resumable 04 - Builder Run is inlined`` () = + FSharp """ +open Microsoft.FSharp.Core.CompilerServices +open Microsoft.FSharp.Core.CompilerServices.StateMachineHelpers + +#nowarn "3501" +#nowarn "3513" + +type Builder() = + member inline _.Run(code: ResumableCode) = + if __useResumableCode then + __stateMachine + (MoveNextMethodImpl<_>(fun sm -> code.Invoke(&sm) |> ignore)) + (SetStateMachineMethodImpl<_>(fun _ _ -> ())) + (AfterCode<_, _>(fun _ -> 42)) + else + 0 + +let builder = Builder() + +[] +let main _ = + let code = ResumableCode(fun _ -> true) + let result = builder.Run code + if result = 42 then 0 else 1 +""" + |> withDebug + |> withNoOptimize + |> asExe + |> compileAndRun + |> shouldSucceed + |> withExitCode 0 + |> verifySequencePoints + [] let ``InlineIfLambda 01 - Debug`` () = FSharp """ @@ -1896,4 +1931,3 @@ let main _ = |> asExe |> compileAndRun |> verifySequencePoints - diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 01.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 01.bsl index 538420ab647..b087cd275f7 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 01.bsl +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 01.bsl @@ -8,35 +8,88 @@ let main _ = Test::main (6,13-6,17) task - IL_0000: call TaskBuilderModule::get_task - IL_0005: stloc.1 - IL_0006: ldloc.1 - IL_0007: ldloc.1 - IL_0008: ldloc.1 - IL_0009: newobj t@6::.ctor - IL_000e: callvirt TaskBuilderBase::Delay - IL_0013: callvirt TaskBuilder::Run - IL_0018: stloc.0 + IL_0000: ldloca.s 1 + IL_0002: initobj t@6 + IL_0008: ldloca.s 1 + IL_000a: stloc.2 + IL_000b: ldloc.2 + IL_000c: ldflda t@6::Data + IL_0011: call Create + IL_0016: stfld MethodBuilder + IL_001b: ldloc.2 + IL_001c: ldflda t@6::Data + IL_0021: ldflda MethodBuilder + IL_0026: ldloc.2 + IL_0027: call Start + IL_002c: ldloc.2 + IL_002d: ldflda t@6::Data + IL_0032: ldflda MethodBuilder + IL_0037: call get_Task + IL_003c: stloc.0 (7,5-7,25) if t.Result = 1 then - IL_0019: ldloc.0 - IL_001a: callvirt get_Result - IL_001f: ldc.i4.1 - IL_0020: bne.un.s IL_0024 + IL_003d: ldloc.0 + IL_003e: callvirt get_Result + IL_0043: ldc.i4.1 + IL_0044: bne.un.s IL_0048 (7,26-7,27) 0 - IL_0022: ldc.i4.0 - IL_0023: ret + IL_0046: ldc.i4.0 + IL_0047: ret (7,33-7,34) 1 - IL_0024: ldc.i4.1 - IL_0025: ret + IL_0048: ldc.i4.1 + IL_0049: ret -t@6::Invoke - (6,20-6,28) return 1 +t@6::MoveNext + IL_0000: ldarg.0 - IL_0001: ldfld t@6::builder@ - IL_0006: ldc.i4.1 - IL_0007: tail. - IL_0009: callvirt TaskBuilderBase::Return - IL_000e: ret + IL_0001: ldfld t@6::ResumptionPoint + IL_0006: stloc.0 + + (6,20-6,28) return 1 + IL_0007: ldc.i4.1 + IL_0008: stloc.3 + IL_0009: ldarg.0 + IL_000a: ldflda t@6::Data + IL_000f: ldloc.3 + IL_0010: stfld Result + IL_0015: ldc.i4.1 + IL_0016: stloc.2 + IL_0017: ldloc.2 + IL_0018: brfalse.s IL_0037 + + + IL_001a: ldarg.0 + IL_001b: ldflda t@6::Data + IL_0020: ldflda MethodBuilder + IL_0025: ldarg.0 + IL_0026: ldflda t@6::Data + IL_002b: ldfld Result + IL_0030: call SetResult + IL_0035: leave.s IL_0045 + + + IL_0037: leave.s IL_0045 + IL_0039: castclass Exception + IL_003e: stloc.s 4 + IL_0040: ldloc.s 4 + IL_0042: stloc.1 + IL_0043: leave.s IL_0045 + + + IL_0045: ldloc.1 + IL_0046: stloc.s 5 + IL_0048: ldloc.s 5 + IL_004a: brtrue.s IL_004d + + + IL_004c: ret + + + IL_004d: ldarg.0 + IL_004e: ldflda t@6::Data + IL_0053: ldflda MethodBuilder + IL_0058: ldloc.s 5 + IL_005a: call SetException + IL_005f: ret diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 02.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 02.bsl index 420647d81d1..34a8deffeda 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 02.bsl +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 02.bsl @@ -12,73 +12,322 @@ let main _ = Test::main (6,13-6,17) task - IL_0000: call TaskBuilderModule::get_task - IL_0005: stloc.1 - IL_0006: ldloc.1 - IL_0007: ldloc.1 - IL_0008: ldloc.1 - IL_0009: newobj t@9::.ctor - IL_000e: callvirt TaskBuilderBase::Delay - IL_0013: callvirt TaskBuilder::Run - IL_0018: stloc.0 + IL_0000: ldloca.s 1 + IL_0002: initobj t@6 + IL_0008: ldloca.s 1 + IL_000a: stloc.2 + IL_000b: ldloc.2 + IL_000c: ldflda t@6::Data + IL_0011: call Create + IL_0016: stfld MethodBuilder + IL_001b: ldloc.2 + IL_001c: ldflda t@6::Data + IL_0021: ldflda MethodBuilder + IL_0026: ldloc.2 + IL_0027: call Start + IL_002c: ldloc.2 + IL_002d: ldflda t@6::Data + IL_0032: ldflda MethodBuilder + IL_0037: call get_Task + IL_003c: stloc.0 (11,5-11,25) if t.Result = 3 then - IL_0019: ldloc.0 - IL_001a: callvirt get_Result - IL_001f: ldc.i4.3 - IL_0020: bne.un.s IL_0024 + IL_003d: ldloc.0 + IL_003e: callvirt get_Result + IL_0043: ldc.i4.3 + IL_0044: bne.un.s IL_0048 (11,26-11,27) 0 - IL_0022: ldc.i4.0 - IL_0023: ret + IL_0046: ldc.i4.0 + IL_0047: ret (11,33-11,34) 1 - IL_0024: ldc.i4.1 - IL_0025: ret + IL_0048: ldc.i4.1 + IL_0049: ret -t@8-1::Invoke +t@6::MoveNext - IL_0000: ldarg.1 - IL_0001: stloc.0 + IL_0000: ldarg.0 + IL_0001: ldfld t@6::ResumptionPoint + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: sub + IL_000a: switch (2 targets) + IL_0017: br.s IL_001f + + + IL_0019: nop + IL_001a: br.s IL_0020 + + + IL_001c: nop + IL_001d: br.s IL_0020 + + + IL_001f: nop + IL_0020: ldloc.0 + IL_0021: ldc.i4.1 + IL_0022: sub + IL_0023: switch (2 targets) + IL_0030: br.s IL_003b + + + IL_0032: nop + IL_0033: br.s IL_0064 + + + IL_0035: nop + IL_0036: br IL_00c5 + + + IL_003b: nop + + (7,9-7,36) let! x = Task.FromResult(1) + IL_003c: ldc.i4.1 + IL_003d: call Task::FromResult + IL_0042: stloc.3 + IL_0043: ldarg.0 + IL_0044: ldloc.3 + IL_0045: callvirt GetAwaiter + IL_004a: stfld t@6::awaiter0 + IL_004f: ldc.i4.1 + IL_0050: stloc.s 4 + IL_0052: ldarg.0 + IL_0053: ldflda t@6::awaiter0 + IL_0058: call get_IsCompleted + IL_005d: brfalse.s IL_0061 + IL_005f: br.s IL_007a + + + IL_0061: ldc.i4.0 + IL_0062: brfalse.s IL_0068 + + + IL_0064: ldc.i4.1 + + + IL_0065: nop + IL_0066: br.s IL_0071 + + + IL_0068: ldarg.0 + IL_0069: ldc.i4.1 + IL_006a: stfld t@6::ResumptionPoint + IL_006f: ldc.i4.0 + + + IL_0070: nop + IL_0071: stloc.s 5 + IL_0073: ldloc.s 5 + IL_0075: stloc.s 4 + + + IL_0077: nop + IL_0078: br.s IL_007b + + + IL_007a: nop + IL_007b: ldloc.s 4 + IL_007d: brfalse IL_014b + + + IL_0082: ldarg.0 + IL_0083: ldflda t@6::awaiter0 + IL_0088: call GetResult + IL_008d: stloc.s 6 + IL_008f: ldloc.s 6 + IL_0091: stloc.s 7 + IL_0093: ldarg.0 + IL_0094: ldloc.s 7 + IL_0096: stfld t@6::x (8,9-8,36) let! y = Task.FromResult(2) - IL_0002: ldarg.0 - IL_0003: ldfld t@8-1::builder@ - IL_0008: ldc.i4.2 - IL_0009: call Task::FromResult - IL_000e: ldarg.0 - IL_000f: ldfld t@8-1::builder@ - IL_0014: ldloc.0 - IL_0015: newobj t@9-2::.ctor - IL_001a: tail. - IL_001c: call HighPriority::TaskBuilderBase.Bind - IL_0021: ret - -t@9-2::Invoke - - IL_0000: ldarg.1 - IL_0001: stloc.0 + IL_009b: ldc.i4.2 + IL_009c: call Task::FromResult + IL_00a1: stloc.s 8 + IL_00a3: ldarg.0 + IL_00a4: ldloc.s 8 + IL_00a6: callvirt GetAwaiter + IL_00ab: stfld t@6::awaiter + IL_00b0: ldc.i4.1 + IL_00b1: stloc.s 9 + IL_00b3: ldarg.0 + IL_00b4: ldflda t@6::awaiter + IL_00b9: call get_IsCompleted + IL_00be: brfalse.s IL_00c2 + IL_00c0: br.s IL_00db + + + IL_00c2: ldc.i4.0 + IL_00c3: brfalse.s IL_00c9 + + + IL_00c5: ldc.i4.1 + + + IL_00c6: nop + IL_00c7: br.s IL_00d2 + + + IL_00c9: ldarg.0 + IL_00ca: ldc.i4.2 + IL_00cb: stfld t@6::ResumptionPoint + IL_00d0: ldc.i4.0 + + + IL_00d1: nop + IL_00d2: stloc.s 10 + IL_00d4: ldloc.s 10 + IL_00d6: stloc.s 9 + + + IL_00d8: nop + IL_00d9: br.s IL_00dc + + + IL_00db: nop + IL_00dc: ldloc.s 9 + IL_00de: brfalse.s IL_0111 + + + IL_00e0: ldarg.0 + IL_00e1: ldflda t@6::awaiter + IL_00e6: call GetResult + IL_00eb: stloc.s 11 + IL_00ed: ldloc.s 11 + IL_00ef: stloc.s 12 + IL_00f1: ldloc.s 12 + IL_00f3: stloc.s 13 (9,9-9,21) return x + y - IL_0002: ldarg.0 - IL_0003: ldfld t@9-2::builder@ - IL_0008: ldarg.0 - IL_0009: ldfld t@9-2::x - IL_000e: ldloc.0 - IL_000f: add - IL_0010: tail. - IL_0012: callvirt TaskBuilderBase::Return - IL_0017: ret - -t@9::Invoke - (7,9-7,36) let! x = Task.FromResult(1) - IL_0000: ldarg.0 - IL_0001: ldfld t@9::builder@ - IL_0006: ldc.i4.1 - IL_0007: call Task::FromResult - IL_000c: ldarg.0 - IL_000d: ldfld t@9::builder@ - IL_0012: newobj t@8-1::.ctor - IL_0017: tail. - IL_0019: call HighPriority::TaskBuilderBase.Bind - IL_001e: ret + IL_00f5: ldarg.0 + IL_00f6: ldfld t@6::x + IL_00fb: ldloc.s 13 + IL_00fd: add + IL_00fe: stloc.s 14 + IL_0100: ldarg.0 + IL_0101: ldflda t@6::Data + IL_0106: ldloc.s 14 + IL_0108: stfld Result + IL_010d: ldc.i4.1 + + + IL_010e: nop + IL_010f: br.s IL_012a + + + IL_0111: ldarg.0 + IL_0112: ldflda t@6::Data + IL_0117: ldflda MethodBuilder + IL_011c: ldarg.0 + IL_011d: ldflda t@6::awaiter + IL_0122: ldarg.0 + IL_0123: call AwaitUnsafeOnCompleted + IL_0128: ldc.i4.0 + + + IL_0129: nop + IL_012a: brfalse.s IL_0138 + + + IL_012c: ldarg.0 + IL_012d: ldloc.s 15 + IL_012f: stfld t@6::awaiter + IL_0134: ldc.i4.1 + + + IL_0135: nop + IL_0136: br.s IL_013a + + + IL_0138: ldc.i4.0 + + + IL_0139: nop + IL_013a: brfalse.s IL_0147 + + + IL_013c: ldarg.0 + IL_013d: ldc.i4.0 + IL_013e: stfld t@6::x + IL_0143: ldc.i4.1 + + + IL_0144: nop + IL_0145: br.s IL_0164 + + + IL_0147: ldc.i4.0 + + + IL_0148: nop + IL_0149: br.s IL_0164 + + + IL_014b: ldarg.0 + IL_014c: ldflda t@6::Data + IL_0151: ldflda MethodBuilder + IL_0156: ldarg.0 + IL_0157: ldflda t@6::awaiter0 + IL_015c: ldarg.0 + IL_015d: call AwaitUnsafeOnCompleted + IL_0162: ldc.i4.0 + + + IL_0163: nop + IL_0164: brfalse.s IL_0172 + + + IL_0166: ldarg.0 + IL_0167: ldloc.s 16 + IL_0169: stfld t@6::awaiter0 + IL_016e: ldc.i4.1 + + + IL_016f: nop + IL_0170: br.s IL_0174 + + + IL_0172: ldc.i4.0 + + + IL_0173: nop + IL_0174: stloc.2 + IL_0175: ldloc.2 + IL_0176: brfalse.s IL_0195 + + + IL_0178: ldarg.0 + IL_0179: ldflda t@6::Data + IL_017e: ldflda MethodBuilder + IL_0183: ldarg.0 + IL_0184: ldflda t@6::Data + IL_0189: ldfld Result + IL_018e: call SetResult + IL_0193: leave.s IL_01a3 + + + IL_0195: leave.s IL_01a3 + IL_0197: castclass Exception + IL_019c: stloc.s 17 + IL_019e: ldloc.s 17 + IL_01a0: stloc.1 + IL_01a1: leave.s IL_01a3 + + + IL_01a3: ldloc.1 + IL_01a4: stloc.s 18 + IL_01a6: ldloc.s 18 + IL_01a8: brtrue.s IL_01ab + + + IL_01aa: ret + + + IL_01ab: ldarg.0 + IL_01ac: ldflda t@6::Data + IL_01b1: ldflda MethodBuilder + IL_01b6: ldloc.s 18 + IL_01b8: call SetException + IL_01bd: ret diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 03.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 03.bsl index d2ae10311bc..b00a66ad8a1 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 03.bsl +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 03.bsl @@ -26,36 +26,39 @@ Test::g Test::main (19,5-19,25) let r = g (S()) - IL_0000: ldloc.1 - IL_0001: call Test::g - IL_0006: stloc.0 + IL_0000: ldloca.s 2 + IL_0002: initobj r@19 + IL_0008: ldloca.s 2 + IL_000a: stloc.3 + IL_000b: ldc.i4.s 42 + IL_000d: stloc.0 (20,5-20,19) if r = 42 then - IL_0007: ldloc.0 - IL_0008: ldc.i4.s 42 - IL_000a: bne.un.s IL_000e + IL_000e: ldloc.0 + IL_000f: ldc.i4.s 42 + IL_0011: bne.un.s IL_0015 (20,20-20,21) 0 - IL_000c: ldc.i4.0 - IL_000d: ret + IL_0013: ldc.i4.0 + IL_0014: ret (20,27-20,28) 1 - IL_000e: ldc.i4.1 - IL_000f: ret + IL_0015: ldc.i4.1 + IL_0016: ret S`1::Equals IL_0000: ldarg.1 IL_0001: stloc.0 IL_0002: ldloc.0 - IL_0003: isinst 0x1b000003 + IL_0003: isinst 0x1b000004 IL_0008: ldnull IL_0009: cgt.un IL_000b: brfalse.s IL_001d IL_000d: ldarg.1 - IL_000e: unbox.any 0x1b000003 + IL_000e: unbox.any 0x1b000004 IL_0013: stloc.1 IL_0014: ldarg.0 IL_0015: ldloc.1 @@ -76,14 +79,14 @@ S`1::Equals IL_0000: ldarg.1 IL_0001: stloc.0 IL_0002: ldloc.0 - IL_0003: isinst 0x1b000003 + IL_0003: isinst 0x1b000004 IL_0008: ldnull IL_0009: cgt.un IL_000b: brfalse.s IL_001c IL_000d: ldarg.1 - IL_000e: unbox.any 0x1b000003 + IL_000e: unbox.any 0x1b000004 IL_0013: stloc.1 IL_0014: ldarg.0 IL_0015: ldloc.1 diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 04 - Builder Run is inlined.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 04 - Builder Run is inlined.bsl new file mode 100644 index 00000000000..fcb69cc382b --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/Resumable 04 - Builder Run is inlined.bsl @@ -0,0 +1,100 @@ +open Microsoft.FSharp.Core.CompilerServices +open Microsoft.FSharp.Core.CompilerServices.StateMachineHelpers + +#nowarn "3501" +#nowarn "3513" + +type Builder() = + member inline _.Run(code: ResumableCode) = + if __useResumableCode then + __stateMachine + (MoveNextMethodImpl<_>(fun sm -> code.Invoke(&sm) |> ignore)) + (SetStateMachineMethodImpl<_>(fun _ _ -> ())) + (AfterCode<_, _>(fun _ -> 42)) + else + 0 + +let builder = Builder() + +[] +let main _ = + let code = ResumableCode(fun _ -> true) + let result = builder.Run code + if result = 42 then 0 else 1 +-------------------------------------------------------------------------------- + +Test::main + (22,5-22,55) let code = ResumableCode(fun _ -> true) + IL_0000: ldc.i4.0 + IL_0001: stsfld $Test::init@ + IL_0006: ldsfld $Test::init@ + IL_000b: pop + IL_000c: ldnull + IL_000d: ldftn code@22::Invoke + IL_0013: newobj .ctor + IL_0018: stloc.0 + + (23,5-23,34) let result = builder.Run code + IL_0019: ldloca.s 2 + IL_001b: initobj result@23 + IL_0021: ldloca.s 2 + IL_0023: stloc.3 + IL_0024: ldc.i4.s 42 + IL_0026: stloc.1 + + (24,5-24,24) if result = 42 then + IL_0027: ldloc.1 + IL_0028: ldc.i4.s 42 + IL_002a: bne.un.s IL_002e + + (24,25-24,26) 0 + IL_002c: ldc.i4.0 + IL_002d: ret + + (24,32-24,33) 1 + IL_002e: ldc.i4.1 + IL_002f: ret + +Test::.cctor + + IL_0000: ldc.i4.0 + IL_0001: stsfld $Test::init@ + IL_0006: ldsfld $Test::init@ + IL_000b: pop + IL_000c: ret + +Test::staticInitialization@ + (18,1-18,24) let builder = Builder() + IL_0000: newobj Builder::.ctor + IL_0005: stsfld Test::builder@18 + IL_000a: ret + +Builder::.ctor + (8,6-8,13) Builder + IL_0000: ldarg.0 + IL_0001: callvirt Object::.ctor + IL_0006: ldarg.0 + IL_0007: pop + IL_0008: ret + +Builder::Run + (16,13-16,14) 0 + IL_0000: ldc.i4.0 + IL_0001: ret + +code@22::Invoke + (22,50-22,54) true + IL_0000: ldc.i4.1 + IL_0001: ret + +result@23::MoveNext + + IL_0000: ldarg.0 + IL_0001: stloc.1 + + (22,50-22,54) true + IL_0002: ldc.i4.1 + IL_0003: stloc.0 + IL_0004: ldloc.0 + IL_0005: stloc.2 + IL_0006: ret diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/SRTP 13 - Witness - Struct with ResumableCode and partially resolved type args.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/SRTP 13 - Witness - Struct with ResumableCode and partially resolved type args.bsl index 25137313f09..549a83f3c2a 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/SRTP 13 - Witness - Struct with ResumableCode and partially resolved type args.bsl +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/SRTP 13 - Witness - Struct with ResumableCode and partially resolved type args.bsl @@ -39,43 +39,32 @@ Test::f$W Test::g (15,19-15,26) f (S()) - IL_0000: ldsfld @_instance - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: ldloc.1 - IL_0008: tail. - IL_000a: callvirt Invoke - IL_000f: ret + IL_0000: ldloc.0 + IL_0001: newobj .ctor + IL_0006: ldftn Invoke + IL_000c: newobj .ctor + IL_0011: ret Test::g$W (15,19-15,26) f (S()) IL_0000: ldarg.0 - IL_0001: newobj .ctor - IL_0006: stloc.0 - IL_0007: ldloc.0 - IL_0008: ldloc.1 - IL_0009: tail. - IL_000b: callvirt Invoke - IL_0010: ret + IL_0001: ldloc.0 + IL_0002: newobj .ctor + IL_0007: ldftn Invoke + IL_000d: newobj .ctor + IL_0012: ret Test::main (19,35-19,39) g () - IL_0000: call Test::__debug@19 - IL_0005: pop + IL_0000: ldloc.0 + IL_0001: newobj main@19::.ctor + IL_0006: ldftn main@19::Invoke + IL_000c: newobj .ctor + IL_0011: pop (20,5-20,6) 0 - IL_0006: ldc.i4.0 - IL_0007: ret - -Test::__debug@19 - (15,19-15,26) f (S()) - IL_0000: ldsfld main@9::@_instance - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: ldloc.1 - IL_0008: tail. - IL_000a: callvirt Invoke - IL_000f: ret + IL_0012: ldc.i4.0 + IL_0013: ret S::Equals @@ -133,32 +122,6 @@ D::Bar IL_0000: ldc.i4.1 IL_0001: ret -g@9::Invoke - (10,26-13,6) (fun sm -> (^A: (member Foo: unit -> unit) x) (^B: (member Bar: unit -> bool) sm.Data) ) - IL_0000: ldarg.1 - IL_0001: newobj .ctor - IL_0006: ldftn Invoke - IL_000c: newobj .ctor - IL_0011: ret - -g@9-2::Invoke - (10,26-13,6) (fun sm -> (^A: (member Foo: unit -> unit) x) (^B: (member Bar: unit -> bool) sm.Data) ) - IL_0000: ldarg.0 - IL_0001: ldfld bar - IL_0006: ldarg.1 - IL_0007: newobj .ctor - IL_000c: ldftn Invoke - IL_0012: newobj .ctor - IL_0017: ret - -main@9::Invoke - (10,26-13,6) (fun sm -> (^A: (member Foo: unit -> unit) x) (^B: (member Bar: unit -> bool) sm.Data) ) - IL_0000: ldarg.1 - IL_0001: newobj main@10-1::.ctor - IL_0006: ldftn main@10-1::Invoke - IL_000c: newobj .ctor - IL_0011: ret - f@10::Invoke (11,9-11,43) (^A: (member Foo: unit -> unit) x) IL_0000: ldc.i4.0 @@ -193,44 +156,3 @@ f@10-1::Invoke IL_001e: tail. IL_0020: callvirt Invoke IL_0025: ret - -g@10-1::Invoke - (11,9-11,43) (^A: (member Foo: unit -> unit) x) - IL_0000: ldarg.0 - IL_0001: ldflda x - IL_0006: call S::Foo - IL_000b: nop - - (12,9-12,49) (^B: (member Bar: unit -> bool) sm.Data) - IL_000c: ldstr "Dynamic invocation of Bar is not supported" - IL_0011: newobj NotSupportedException::.ctor - IL_0016: throw - -g@10-3::Invoke - (11,9-11,43) (^A: (member Foo: unit -> unit) x) - IL_0000: ldarg.0 - IL_0001: ldflda x - IL_0006: call S::Foo - IL_000b: nop - - (12,9-12,49) (^B: (member Bar: unit -> bool) sm.Data) - IL_000c: ldarg.0 - IL_000d: ldfld bar - IL_0012: ldarg.1 - IL_0013: ldfld Data - IL_0018: tail. - IL_001a: callvirt Invoke - IL_001f: ret - -main@10-1::Invoke - (11,9-11,43) (^A: (member Foo: unit -> unit) x) - IL_0000: ldarg.0 - IL_0001: ldflda main@10-1::x - IL_0006: call S::Foo - IL_000b: nop - - (12,9-12,49) (^B: (member Bar: unit -> bool) sm.Data) - IL_000c: ldarg.1 - IL_000d: ldfld Data - IL_0012: callvirt D::Bar - IL_0017: ret diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/SRTP 14 - StateMachine with unresolved trait from composed inline function.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/SRTP 14 - StateMachine with unresolved trait from composed inline function.bsl index aceb51ead83..8c3aca87f16 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/SRTP 14 - StateMachine with unresolved trait from composed inline function.bsl +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/DebugInlineAsCall/SRTP 14 - StateMachine with unresolved trait from composed inline function.bsl @@ -41,60 +41,64 @@ Test::g Test::h (19,18-19,25) g (f a) IL_0000: ldsfld @_instance - IL_0005: stloc.0 - IL_0006: ldloc.0 + IL_0005: stloc.1 + IL_0006: ldloc.1 IL_0007: ldarg.0 IL_0008: callvirt Invoke - IL_000d: tail. - IL_000f: call Test::g - IL_0014: ret + IL_000d: stloc.0 + IL_000e: ldloca.s 2 + IL_0010: initobj h@19-1 + IL_0016: ldloca.s 2 + IL_0018: stloc.3 + IL_0019: ldc.i4.0 + IL_001a: ret Test::h$W (19,18-19,25) g (f a) IL_0000: ldarg.0 IL_0001: newobj .ctor - IL_0006: stloc.0 - IL_0007: ldloc.0 + IL_0006: stloc.1 + IL_0007: ldloc.1 IL_0008: ldarg.1 IL_0009: callvirt Invoke - IL_000e: tail. - IL_0010: call Test::g - IL_0015: ret + IL_000e: stloc.0 + IL_000f: ldloca.s 2 + IL_0011: initobj h@19-3 + IL_0017: ldloca.s 2 + IL_0019: stloc.3 + IL_001a: ldc.i4.0 + IL_001b: ret Test::main (23,13-23,25) h (S()) - IL_0000: ldloc.0 - IL_0001: call Test::__debug@23 - IL_0006: pop + IL_0000: ldsfld main@23::@_instance + IL_0005: stloc.2 + IL_0006: ldloc.2 + IL_0007: ldloc.0 + IL_0008: callvirt Invoke + IL_000d: stloc.1 + IL_000e: ldloca.s 3 + IL_0010: initobj main@23-1 + IL_0016: ldloca.s 3 + IL_0018: stloc.s 4 (24,5-24,6) 0 - IL_0007: ldc.i4.0 - IL_0008: ret - -Test::__debug@23 - (19,18-19,25) g (f a) - IL_0000: ldsfld main@9::@_instance - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: ldarg.0 - IL_0008: callvirt Invoke - IL_000d: tail. - IL_000f: call Test::g - IL_0014: ret + IL_001a: ldc.i4.0 + IL_001b: ret S`1::Equals IL_0000: ldarg.1 IL_0001: stloc.0 IL_0002: ldloc.0 - IL_0003: isinst 0x1b000008 + IL_0003: isinst 0x1b00000a IL_0008: ldnull IL_0009: cgt.un IL_000b: brfalse.s IL_001d IL_000d: ldarg.1 - IL_000e: unbox.any 0x1b000008 + IL_000e: unbox.any 0x1b00000a IL_0013: stloc.1 IL_0014: ldarg.0 IL_0015: ldloc.1 @@ -115,14 +119,14 @@ S`1::Equals IL_0000: ldarg.1 IL_0001: stloc.0 IL_0002: ldloc.0 - IL_0003: isinst 0x1b000008 + IL_0003: isinst 0x1b00000a IL_0008: ldnull IL_0009: cgt.un IL_000b: brfalse.s IL_001c IL_000d: ldarg.1 - IL_000e: unbox.any 0x1b000008 + IL_000e: unbox.any 0x1b00000a IL_0013: stloc.1 IL_0014: ldarg.0 IL_0015: ldloc.1 @@ -138,12 +142,7 @@ h@9::Invoke IL_0000: ldloc.0 IL_0001: ret -h@9-1::Invoke - (9,104-9,123) Unchecked.defaultof - IL_0000: ldloc.0 - IL_0001: ret - -main@9::Invoke +h@9-2::Invoke (9,104-9,123) Unchecked.defaultof IL_0000: ldloc.0 IL_0001: ret diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_StructuralAssertions.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_StructuralAssertions.fs index 81e58f02457..b12df008f3a 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_StructuralAssertions.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Inlining/Regression_TLR_MutualInnerRec_StructuralAssertions.fs @@ -168,6 +168,49 @@ type C() = |> shouldSucceed |> verifyILNotPresent [ "PrivateImplementationDetails" ] + [] + let ``Namespace-level inner-rec does not trigger file initialization`` (realsig: bool) = + let source = """ +namespace Repro + +type WrappedList<'T> = Wrap of 'T list with + static member Exists(Wrap list: WrappedList<'T>, predicate) = + let rec loop list = + match list with + | [] -> false + | h :: t -> predicate h || loop t + loop list + +module Initialization = + let value: int = failwith "Unexpected file initialization" +""" + let other = """ +namespace Repro +module OtherInitialization = + let value: int = failwith "Unexpected initialization of another file" +""" + let main = """ +module Main +open Repro + +[] +let main _ = + let visited = ResizeArray() + let _ = WrappedList.Exists(Wrap [1; 2; 3], fun x -> visited.Add x; x = 2) + if Seq.toList visited = [1; 2] then 0 else 1 +""" + FSharp source + |> withFileName "A.fs" + |> withAdditionalSourceFiles [ + FsSourceWithFileName "A$Functions.fs" other + FsSourceWithFileName "Main.fs" main + ] + |> withRealInternalSignature realsig + |> asExe + |> withOptimize + |> compileExeAndRun + |> shouldSucceed + [] let ``Value recursion is not broken by TLR`` (realsig: bool) = """module Sample @@ -180,6 +223,31 @@ let main _argv = if run() = 6 then 0 else 1 """ |> compileOptimizedAndRun realsig + [] + let ``Namespace-rec forward values are initialized`` (realsig: bool, optimize: bool) = + let source = """ +namespace rec Repro +module Values = + let x = C(42) +type C(value: int) = + member _.Value = value +module Check = + do if Values.x.Value <> 42 then failwith "Not initialized" +""" + let main = """ +module Main +[] +let main _ = Repro.Values.x.Value - 42 +""" + FSharp source + |> withAdditionalSourceFile (FsSourceWithFileName "Main.fs" main) + |> withRealInternalSignature realsig + |> withOptimization optimize + |> withOptions ["--nowarn:22,40"] + |> asExe + |> compile + |> verifyPEAndRun + [] let ``Quotation body is not affected by TLR`` (realsig: bool) = """module Sample diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/OptimizeClosureIfNotInlined.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/OptimizeClosureIfNotInlined.fs new file mode 100644 index 00000000000..26d879f31dd --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/OptimizeClosureIfNotInlined.fs @@ -0,0 +1,248 @@ +namespace EmittedIL + +open Xunit +open FSharp.Test.Compiler + +module OptimizeClosureIfNotInlined = + + let private prelude = + """ +module M +let inline fold2 ([] folder: 'State -> 'T1 -> 'T2 -> 'State) (state: 'State) (a: 'T1[]) (b: 'T2[]) = + let mutable s = state + for i in 0 .. a.Length - 1 do + s <- folder s a.[i] b.[i] + s + +[] +let mkFolder () : int -> int -> int -> int = fun s x y -> s + x * y +""" + + let private optimized source = + FSharp source + |> withLangVersionPreview + |> withOptions [ "--optimize+" ] + |> compile + |> shouldSucceed + + let private runOutput source = + FSharp source + |> withLangVersionPreview + |> withOptions [ "--optimize+" ] + |> compileExeAndRun + |> shouldSucceed + + [] + let ``opaque multi-arg callback is Adapt-ed`` () = + optimized (prelude + "let callOpaque (a: int[]) (b: int[]) = fold2 (mkFolder ()) 0 a b") + |> verifyILPresent [ "::Adapt(" ] + + [] + let ``inlinable lambda callback is not Adapt-ed`` () = + optimized (prelude + "let callLambda (a: int[]) (b: int[]) (k: int) = fold2 (fun s x y -> s + x * y + k) 0 a b") + |> verifyILNotPresent [ "Adapt" ] + + // Declared arity exceeds the applied arity, so no application is rewritten. + [] + let ``over-arrows callback emits no dead Adapt`` () = + optimized """ +module M +let inline applyOverArrows ([] f: (int -> int) -> int -> (int -> int)) (g0: int -> int) (a: int[]) = + let mutable acc = g0 + for i in 0 .. a.Length - 1 do + acc <- f acc a.[i] + acc + +[] +let mkF () : (int -> int) -> int -> (int -> int) = fun g x -> (fun z -> g z + x) + +let callOverArrows (a: int[]) = applyOverArrows (mkF ()) id a +""" + |> verifyILNotPresent [ "Adapt" ] + + [] + [] + [] + [] + [] + let ``boundary arity uses the matching OptimizedClosures type`` (arity: int) (expectedType: string) = + let tyArrows = String.concat " -> " (List.replicate (arity + 1) "int") + let formalArgs = String.concat " " [ for i in 1 .. arity -> $"x{i}" ] + let applyArgs = String.concat " " [ yield "acc"; for _ in 2 .. arity -> "xs.[i]" ] + let sumBody = String.concat " + " [ for i in 1 .. arity -> $"x{i}" ] + optimized $""" +module M +let inline foldN ([] folder: {tyArrows}) (state: int) (xs: int[]) = + let mutable acc = state + for i in 0 .. xs.Length - 1 do + acc <- folder {applyArgs} + acc + +[] +let mkFolder () : {tyArrows} = fun {formalArgs} -> {sumBody} + +let callOpaque (xs: int[]) = foldN (mkFolder ()) 0 xs +""" + |> verifyILPresent [ $"OptimizedClosures/{expectedType}"; "::Adapt("; "::Invoke(" ] + + // Distinct arg/result types catch a generic-slot mix-up a homogeneous int callback hides. + [] + let ``adapted callback with heterogeneous argument types is correct`` () = + runOutput """ +module M +let inline apply4 ([] f: int -> string -> bool -> float -> decimal) (xs: int[]) = + let mutable acc = 0M + for x in xs do acc <- acc + f x "k" true 2.0 + acc + +[] +let mkF () : int -> string -> bool -> float -> decimal = + fun i s b d -> decimal i + decimal s.Length + (if b then 10M else 0M) + decimal d + +[] +let main _ = + printfn "RESULT=%M" (apply4 (mkF ()) [| 1; 2; 3 |]) + 0 +""" + |> withStdOutContains "RESULT=45" + + [] + let ``optimized opaque callback matches un-attributed results and effect order`` () = + runOutput """ +module M +let log = ResizeArray() +let mutable factoryCalls = 0 + +let inline fold2_ocini ([] folder: 'S -> 'a -> 'b -> 'S) (state: 'S) (a: 'a[]) (b: 'b[]) = + let mutable s = state + for i in 0 .. a.Length - 1 do s <- folder s a.[i] b.[i] + s +let inline fold2_plain ([] folder: 'S -> 'a -> 'b -> 'S) (state: 'S) (a: 'a[]) (b: 'b[]) = + let mutable s = state + for i in 0 .. a.Length - 1 do s <- folder s a.[i] b.[i] + s + +[] +let mkTracingFolder () : int -> int -> int -> int = + factoryCalls <- factoryCalls + 1 + fun s x y -> log.Add((s, x, y)); s + x * y + +[] +let main _ = + let a = [| 1; 2; 3; 4 |] + let b = [| 5; 6; 7; 8 |] + let expected = [ (0, 1, 5); (5, 2, 6); (17, 3, 7); (38, 4, 8) ] + + factoryCalls <- 0 + log.Clear() + let rOcini = fold2_ocini (mkTracingFolder ()) 0 a b + let traceOcini = List.ofSeq log + let callsOcini = factoryCalls + + log.Clear() + let rPlain = fold2_plain (mkTracingFolder ()) 0 a b + let tracePlain = List.ofSeq log + + let ok = rOcini = 70 && rPlain = 70 && traceOcini = expected && tracePlain = expected && callsOcini = 1 + printfn "RESULT=%s" (if ok then "PASS" else "FAIL") + 0 +""" + |> withStdOutContains "RESULT=PASS" + + // Saturated calls are adapted and the partial application is left as-is. + [] + let ``callback used saturated and partially applied stays correct`` () = + runOutput """ +module M +let inline foldMixed ([] folder: int -> int -> int -> int) (state: int) (a: int[]) = + let mutable s = state + let partial = folder state + for i in 0 .. a.Length - 1 do s <- folder s a.[i] a.[i] + s + partial 100 200 + +[] +let mkFolder () : int -> int -> int -> int = fun s x y -> s + x * y + +[] +let main _ = + printfn "RESULT=%d" (foldMixed (mkFolder ()) 0 [| 1; 2; 3 |]) + 0 +""" + |> withStdOutContains "RESULT=20014" + + // RewriteQuotations is false, so the reflected call stays an application, not an adapted Invoke. + [] + let ``quotation inside a rewritten body is not adapted`` () = + runOutput """ +module M +open Microsoft.FSharp.Quotations +let inline applyAndQuote ([] f: int -> int -> int -> int) : int * Expr = + f 1 2 3, <@ f 1 2 3 @> + +[] +let mkFolder () : int -> int -> int -> int = fun s x y -> s + x * y + +[] +let main _ = + let result, quoted = applyAndQuote (mkFolder ()) + let s = quoted.ToString() + printfn "RESULT=%b" (result = 7 && not (s.Contains "Invoke") && not (s.Contains "Adapt")) + 0 +""" + |> withStdOutContains "RESULT=true" + + [] + let ``opaque callback is adapted across an assembly boundary at old langversion`` () = + let library = + FSharp """ +module Lib +let inline fold2 ([] folder: 'S -> 'a -> 'b -> 'S) (state: 'S) (a: 'a[]) (b: 'b[]) = + let mutable s = state + for i in 0 .. a.Length - 1 do s <- folder s a.[i] b.[i] + s +""" + |> withLangVersionPreview + |> withOptions [ "--optimize+" ] + |> asLibrary + + let consumer = + FSharp """ +module App +[] +let mkFolder () : int -> int -> int -> int = fun s x y -> s + x * y +let callOpaque (a: int[]) (b: int[]) = Lib.fold2 (mkFolder ()) 0 a b +""" + |> withLangVersion "8.0" + |> withOptions [ "--optimize+" ] + |> withReferences [ library ] + |> compile + |> shouldSucceed + + consumer |> verifyILPresent [ "OptimizedClosures/FSharpFunc`4"; "::Adapt(" ] + consumer |> verifyILNotPresent [ "InvokeFast" ] + + [] + [] g: int -> int) x = g x")>] + [] g: int -> int -> int -> int -> int -> int -> int) a b c d e h = g a b c d e h")>] + [] g: int) x = g + x")>] + [] g: (int * int) -> int) x = g x")>] + [] g: int -> int -> int) x y = g x y")>] + [] g: int -> int -> int) x y = g x y")>] + [] f: int -> int -> int, xs: int[]) =\n let mutable s = 0\n for x in xs do s <- f s x\n s")>] + [] value: int) =\n member _.Value = value")>] + [] f: (int -> int -> int) -> unit")>] + [] f: (int -> int -> int) -> unit")>] + let ``attribute is rejected where it cannot take effect`` (decl: string) = + FSharp ("module M\n" + decl) + |> withLangVersionPreview + |> compile + |> shouldFail + |> withErrorCode 3916 + + [] + let ``attribute requires the preview language feature`` () = + FSharp "module M\nlet inline f ([] g: int -> int -> int) x y = g x y" + |> withLangVersion "8.0" + |> compile + |> shouldFail + |> withErrorCode 3350 diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index c50c9a03675..2a8f90e194f 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -248,6 +248,7 @@ + diff --git a/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs index c4002767e55..07924ab9bf1 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs @@ -8,6 +8,127 @@ open FSharp.Test.Compiler module StateMachineTests = + [] + let ``SRTP await helpers preserve generic state machine captures`` optimize = + FSharp """ +open System.Runtime.CompilerServices +open System.Threading.Tasks +open Microsoft.FSharp.Control +open Microsoft.FSharp.Core.CompilerServices + +#nowarn "3513" +#nowarn "1204" + +type Helper = + static member inline Await(builder: byref< ^Builder>, awaiter: byref< ^Awaiter>, sm: byref< ^StateMachine>) = + (^Builder: (member AwaitUnsafeOnCompleted: byref< ^Awaiter> * byref< ^StateMachine> -> unit) + (builder, &awaiter, &sm)) + +[] +type CustomAwaitable = CustomAwaitable of YieldAwaitable + +type TaskBuilderBase with + member inline _.Bind(CustomAwaitable value, continuation: unit -> TaskCode<'T, 'U>) = + TaskCode<'T, 'U>(fun sm -> + if __useResumableCode then + let mutable awaiter = value.GetAwaiter() + let mutable __stack_fin = true + if not awaiter.IsCompleted then + let __stack_yield_fin = ResumableCode.Yield().Invoke(&sm) + __stack_fin <- __stack_yield_fin + if __stack_fin then + awaiter.GetResult() + (continuation ()).Invoke(&sm) + else + Helper.Await(&sm.Data.MethodBuilder, &awaiter, &sm) + false + else + failwith "unexpected dynamic fallback") + +let fakeWork value (items: ResizeArray<_>) = + task { + items.Add value + do! CustomAwaitable(Task.Yield()) + items.Add value + } + +[] +let main _ = + let items = ResizeArray() + fakeWork 1 items |> fun work -> work.GetAwaiter().GetResult() + if Seq.toList items <> [1; 1] then failwithf "Unexpected captures: %A" items + 0 +""" + |> withDebug + |> withOptimization optimize + |> withFSharpCoreShippedNet + |> compileExeAndRun + |> shouldSucceed + + [] + [] + [] + [] + [] + let ``Resumable builders and combinators inline across assemblies`` (optimizeLibrary, optimizeConsumer) = + let library = + FSharp """ +module ResumableLibrary + +open System.Runtime.CompilerServices +open Microsoft.FSharp.Core.CompilerServices +open Microsoft.FSharp.Core.CompilerServices.StateMachineHelpers + +#nowarn "3513" + +let inline finish (sm: byref<'SM> when 'SM :> IAsyncStateMachine and 'SM :> IResumableStateMachine) = + sm.MoveNext() + sm.Data + +let inline step () = + ResumableCode(fun sm -> + if __useResumableCode then + sm.Data <- sm.Data + 21 + true + else + failwith "unexpected combinator fallback") + +type Builder() = + member inline _.Run(code: ResumableCode) = + if __useResumableCode then + __stateMachine + (MoveNextMethodImpl<_>(fun sm -> + code.Invoke(&sm) |> ignore)) + (SetStateMachineMethodImpl<_>(fun _ _ -> ())) + (AfterCode<_, _>(fun sm -> finish &sm)) + else + failwith "unexpected dynamic fallback" + +let builder = Builder() + +let inline run () = + if __useResumableCode then + builder.Run(ResumableCode.Combine(step(), step())) + else + failwith "unexpected wrapper fallback" +""" + |> withName "ResumableLibrary" + |> withDebug + |> withOptimization optimizeLibrary + |> asLibrary + + FSharp """ +[] +let main _ = + if ResumableLibrary.run() = 42 then 0 else 1 +""" + |> withReferences [library] + |> withDebug + |> withOptimization optimizeConsumer + |> compileExeAndRun + |> shouldSucceed + |> withExitCode 0 + let verifyOptimizedAndRun code = Fsx code |> withOptimize diff --git a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs index 593d8ebcf08..d1a349e41ee 100644 --- a/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs +++ b/tests/FSharp.Compiler.ComponentTests/Libraries/NativeInterop.fs @@ -175,7 +175,7 @@ let call (s: Sink) = // Regression tests for https://github.com/dotnet/fsharp/issues/20295 (Case 1): 'NativePtr.stackalloc' // emits the 'localloc' IL instruction, which the JIT rejects inside an exception-handling region. // Such code used to compile and then throw InvalidProgramException at method load; it must now be - // rejected at compile time with FS3916. + // rejected at compile time with FS3918. [] [ NativePtr.stackalloc 1 |> ignore")>] [ NativePtr.stackalloc 1 |> ignore")>] @@ -194,7 +194,7 @@ let f () = {handler} |> withNoWarn 9 |> compile |> shouldFail - |> withErrorCode 3916 + |> withErrorCode 3918 // A 'let inline' wrapper around 'stackalloc' is inlined into the handler's IL region, so its // 'localloc' still lands inside the exception region and must be rejected. The pre-codegen syntactic @@ -210,7 +210,7 @@ let f () = try () with _ -> alloc () |> withNoWarn 9 |> compile |> shouldFail - |> withErrorCode 3916 + |> withErrorCode 3918 // An escaping closure defined in a handler is compiled to its own method, so its 'localloc' lives // outside the exception region and is legal. Such code must not be rejected (regression guard against diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl index 28c97aa1af8..7e34fcc2adf 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl @@ -1516,6 +1516,7 @@ Microsoft.FSharp.Core.FuncConvert: Microsoft.FSharp.Core.FSharpFunc`2[T1,Microso Microsoft.FSharp.Core.FuncConvert: Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,TResult]] FuncFromTupled[T1,T2,TResult](Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[T1,T2],TResult]) Microsoft.FSharp.Core.GeneralizableValueAttribute: Void .ctor() Microsoft.FSharp.Core.InlineIfLambdaAttribute: Void .ctor() +Microsoft.FSharp.Core.OptimizeClosureIfNotInlinedAttribute: Void .ctor() Microsoft.FSharp.Core.InterfaceAttribute: Void .ctor() Microsoft.FSharp.Core.LanguagePrimitives+ErrorStrings: System.String AddressOpNotFirstClassString Microsoft.FSharp.Core.LanguagePrimitives+ErrorStrings: System.String InputArrayEmptyString @@ -2705,3 +2706,9 @@ Microsoft.FSharp.Reflection.UnionCaseInfo: System.String ToString() Microsoft.FSharp.Reflection.UnionCaseInfo: System.String get_Name() Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type DeclaringType Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type get_DeclaringType() +Microsoft.FSharp.Collections.ListModule: T indexNotFound[T]() +Microsoft.FSharp.Collections.ListModule: T emptyListError[T]() +Microsoft.FSharp.Collections.ListModule: T differentLengthLists[T](System.String, System.String, Int32) +Microsoft.FSharp.Collections.ListModule: T listsDifferentLengths[T]() +Microsoft.FSharp.Collections.ArrayModule: T indexNotFound[T]() +Microsoft.FSharp.Collections.ArrayModule: T differentLengthArrays[T](System.String, Int32, System.String, Int32) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl index 7410f312057..888c9d4ae67 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl @@ -1516,6 +1516,7 @@ Microsoft.FSharp.Core.FuncConvert: Microsoft.FSharp.Core.FSharpFunc`2[T1,Microso Microsoft.FSharp.Core.FuncConvert: Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,TResult]] FuncFromTupled[T1,T2,TResult](Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[T1,T2],TResult]) Microsoft.FSharp.Core.GeneralizableValueAttribute: Void .ctor() Microsoft.FSharp.Core.InlineIfLambdaAttribute: Void .ctor() +Microsoft.FSharp.Core.OptimizeClosureIfNotInlinedAttribute: Void .ctor() Microsoft.FSharp.Core.InterfaceAttribute: Void .ctor() Microsoft.FSharp.Core.LanguagePrimitives+ErrorStrings: System.String AddressOpNotFirstClassString Microsoft.FSharp.Core.LanguagePrimitives+ErrorStrings: System.String InputArrayEmptyString @@ -2704,3 +2705,9 @@ Microsoft.FSharp.Reflection.UnionCaseInfo: System.String ToString() Microsoft.FSharp.Reflection.UnionCaseInfo: System.String get_Name() Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type DeclaringType Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type get_DeclaringType() +Microsoft.FSharp.Collections.ListModule: T indexNotFound[T]() +Microsoft.FSharp.Collections.ListModule: T emptyListError[T]() +Microsoft.FSharp.Collections.ListModule: T differentLengthLists[T](System.String, System.String, Int32) +Microsoft.FSharp.Collections.ListModule: T listsDifferentLengths[T]() +Microsoft.FSharp.Collections.ArrayModule: T indexNotFound[T]() +Microsoft.FSharp.Collections.ArrayModule: T differentLengthArrays[T](System.String, Int32, System.String, Int32) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl index 048d38f8ded..d6ad10ec0b1 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl @@ -1533,6 +1533,7 @@ Microsoft.FSharp.Core.FuncConvert: Microsoft.FSharp.Core.FSharpFunc`2[T1,Microso Microsoft.FSharp.Core.FuncConvert: Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,TResult]] FuncFromTupled[T1,T2,TResult](Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[T1,T2],TResult]) Microsoft.FSharp.Core.GeneralizableValueAttribute: Void .ctor() Microsoft.FSharp.Core.InlineIfLambdaAttribute: Void .ctor() +Microsoft.FSharp.Core.OptimizeClosureIfNotInlinedAttribute: Void .ctor() Microsoft.FSharp.Core.InterfaceAttribute: Void .ctor() Microsoft.FSharp.Core.LanguagePrimitives+ErrorStrings: System.String AddressOpNotFirstClassString Microsoft.FSharp.Core.LanguagePrimitives+ErrorStrings: System.String InputArrayEmptyString @@ -2721,4 +2722,10 @@ Microsoft.FSharp.Reflection.UnionCaseInfo: System.String Name Microsoft.FSharp.Reflection.UnionCaseInfo: System.String ToString() Microsoft.FSharp.Reflection.UnionCaseInfo: System.String get_Name() Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type DeclaringType -Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type get_DeclaringType() \ No newline at end of file +Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type get_DeclaringType() +Microsoft.FSharp.Collections.ListModule: T indexNotFound[T]() +Microsoft.FSharp.Collections.ListModule: T emptyListError[T]() +Microsoft.FSharp.Collections.ListModule: T differentLengthLists[T](System.String, System.String, Int32) +Microsoft.FSharp.Collections.ListModule: T listsDifferentLengths[T]() +Microsoft.FSharp.Collections.ArrayModule: T indexNotFound[T]() +Microsoft.FSharp.Collections.ArrayModule: T differentLengthArrays[T](System.String, Int32, System.String, Int32) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl index 9f52c9d2c11..1139abf6eeb 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl @@ -1533,6 +1533,7 @@ Microsoft.FSharp.Core.FuncConvert: Microsoft.FSharp.Core.FSharpFunc`2[T1,Microso Microsoft.FSharp.Core.FuncConvert: Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,TResult]] FuncFromTupled[T1,T2,TResult](Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[T1,T2],TResult]) Microsoft.FSharp.Core.GeneralizableValueAttribute: Void .ctor() Microsoft.FSharp.Core.InlineIfLambdaAttribute: Void .ctor() +Microsoft.FSharp.Core.OptimizeClosureIfNotInlinedAttribute: Void .ctor() Microsoft.FSharp.Core.InterfaceAttribute: Void .ctor() Microsoft.FSharp.Core.LanguagePrimitives+ErrorStrings: System.String AddressOpNotFirstClassString Microsoft.FSharp.Core.LanguagePrimitives+ErrorStrings: System.String InputArrayEmptyString @@ -2720,4 +2721,10 @@ Microsoft.FSharp.Reflection.UnionCaseInfo: System.String Name Microsoft.FSharp.Reflection.UnionCaseInfo: System.String ToString() Microsoft.FSharp.Reflection.UnionCaseInfo: System.String get_Name() Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type DeclaringType -Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type get_DeclaringType() \ No newline at end of file +Microsoft.FSharp.Reflection.UnionCaseInfo: System.Type get_DeclaringType() +Microsoft.FSharp.Collections.ListModule: T indexNotFound[T]() +Microsoft.FSharp.Collections.ListModule: T emptyListError[T]() +Microsoft.FSharp.Collections.ListModule: T differentLengthLists[T](System.String, System.String, Int32) +Microsoft.FSharp.Collections.ListModule: T listsDifferentLengths[T]() +Microsoft.FSharp.Collections.ArrayModule: T indexNotFound[T]() +Microsoft.FSharp.Collections.ArrayModule: T differentLengthArrays[T](System.String, Int32, System.String, Int32) diff --git a/tests/fsharp/Compiler/CodeGen/EmittedIL/TaskGeneratedCode.fs b/tests/fsharp/Compiler/CodeGen/EmittedIL/TaskGeneratedCode.fs index c821a9e3996..028e86d9141 100644 --- a/tests/fsharp/Compiler/CodeGen/EmittedIL/TaskGeneratedCode.fs +++ b/tests/fsharp/Compiler/CodeGen/EmittedIL/TaskGeneratedCode.fs @@ -39,58 +39,152 @@ let testTask() = task { return 1 } .class public abstract auto ansi sealed Test extends [runtime]System.Object { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) - .class auto ansi serializable sealed nested assembly beforefieldinit testTask@4 - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,int32>> + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .class auto autochar sealed nested assembly beforefieldinit specialname testTask@4 + extends [runtime]System.ValueType + implements [runtime]System.Runtime.CompilerServices.IAsyncStateMachine, + class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1> { - .field public class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@ - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .method assembly specialname rtspecialname instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@) cil managed + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 06 00 00 00 00 00 ) + .field public valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Data + .field public int32 ResumptionPoint + .method public strict virtual instance void MoveNext() cil managed { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext + + .maxstack 4 + .locals init (int32 V_0, + class [runtime]System.Exception V_1, + bool V_2, + int32 V_3, + class [runtime]System.Exception V_4, + class [runtime]System.Exception V_5) + IL_0000: ldarg.0 + IL_0001: ldfld int32 Test/testTask@4::ResumptionPoint + IL_0006: stloc.0 + .try + { + IL_0007: ldc.i4.1 + IL_0008: stloc.3 + IL_0009: ldarg.0 + IL_000a: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_000f: ldloc.3 + IL_0010: stfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result + IL_0015: ldc.i4.1 + IL_0016: stloc.2 + IL_0017: ldloc.2 + IL_0018: brfalse.s IL_0037 + + IL_001a: ldarg.0 + IL_001b: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0020: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0025: ldarg.0 + IL_0026: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_002b: ldfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result + IL_0030: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetResult(!0) + IL_0035: leave.s IL_0045 + + IL_0037: leave.s IL_0045 + + } + catch [runtime]System.Object + { + IL_0039: castclass [runtime]System.Exception + IL_003e: stloc.s V_4 + IL_0040: ldloc.s V_4 + IL_0042: stloc.1 + IL_0043: leave.s IL_0045 + + } + IL_0045: ldloc.1 + IL_0046: stloc.s V_5 + IL_0048: ldloc.s V_5 + IL_004a: brtrue.s IL_004d + + IL_004c: ret + + IL_004d: ldarg.0 + IL_004e: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0053: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0058: ldloc.s V_5 + IL_005a: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetException(class [netstandard]System.Exception) + IL_005f: ret + } + + .method public strict virtual instance void SetStateMachine(class [runtime]System.Runtime.CompilerServices.IAsyncStateMachine state) cil managed + { + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine + .maxstack 8 IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,int32>>::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_000d: ret - } + IL_0001: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0006: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_000b: ldarg.1 + IL_000c: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetStateMachine(class [netstandard]System.Runtime.CompilerServices.IAsyncStateMachine) + IL_0011: ret + } - .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,int32> Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed + .method public strict virtual instance int32 get_ResumptionPoint() cil managed { - + .override method instance int32 class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::get_ResumptionPoint() + .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_0006: ldc.i4.1 - IL_0007: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!0> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Return(!!0) - IL_000c: ret - } + IL_0001: ldfld int32 Test/testTask@4::ResumptionPoint + IL_0006: ret + } + + .method public strict virtual instance valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 get_Data() cil managed + { + .override method instance !0 class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::get_Data() + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0006: ret + } + + .method public strict virtual instance void set_Data(valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 'value') cil managed + { + .override method instance void class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::set_Data(!0) + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0007: ret + } - } + } .method public static class [runtime]System.Threading.Tasks.Task`1 testTask() cil managed { - - .maxstack 5 - .locals init (class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder V_0) - IL_0000: call class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderModule::get_task() - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: ldloc.0 - IL_0008: ldloc.0 - IL_0009: newobj instance void Test/testTask@4::.ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder) - IL_000e: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!1> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Delay(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!1>>) - IL_0013: callvirt instance class [runtime]System.Threading.Tasks.Task`1 [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder::Run(class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!0>) - IL_0018: ret - } -} + .maxstack 4 + .locals init (valuetype Test/testTask@4 V_0, + valuetype Test/testTask@4& V_1) + IL_0000: ldloca.s V_0 + IL_0002: initobj Test/testTask@4 + IL_0008: ldloca.s V_0 + IL_000a: stloc.1 + IL_000b: ldloc.1 + IL_000c: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0011: call valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Create() + IL_0016: stfld valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_001b: ldloc.1 + IL_001c: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0021: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0026: ldloc.1 + IL_0027: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Start(!!0&) + IL_002c: ldloc.1 + IL_002d: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0032: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0037: call instance class [netstandard]System.Threading.Tasks.Task`1 valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::get_Task() + IL_003c: ret + } + +} """ ])) @@ -193,109 +287,258 @@ let testTask(t: Task) = task { let! res = t in return res+1 } .class public abstract auto ansi sealed Test extends [runtime]System.Object { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) - .class auto ansi serializable sealed nested assembly beforefieldinit 'testTask@4-1' - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,int32>> + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .class auto autochar sealed nested assembly beforefieldinit specialname testTask@4 + extends [runtime]System.ValueType + implements [runtime]System.Runtime.CompilerServices.IAsyncStateMachine, + class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1> { - .field public class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@ - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .method assembly specialname rtspecialname instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@) cil managed + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 06 00 00 00 00 00 ) + .field public valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Data + .field public int32 ResumptionPoint + .field public class [runtime]System.Threading.Tasks.Task`1 t + .field public valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 awaiter + .method public strict virtual instance void MoveNext() cil managed { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext + + .maxstack 5 + .locals init (int32 V_0, + class [runtime]System.Exception V_1, + bool V_2, + class [runtime]System.Threading.Tasks.Task`1 V_3, + bool V_4, + bool V_5, + int32 V_6, + int32 V_7, + int32 V_8, + int32 V_9, + valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 V_10, + class [runtime]System.Exception V_11, + class [runtime]System.Exception V_12) + IL_0000: ldarg.0 + IL_0001: ldfld int32 Test/testTask@4::ResumptionPoint + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: sub + IL_000a: switch ( + IL_0015) + IL_0013: br.s IL_0018 + + IL_0015: nop + IL_0016: br.s IL_0019 + + IL_0018: nop + .try + { + IL_0019: ldloc.0 + IL_001a: ldc.i4.1 + IL_001b: sub + IL_001c: switch ( + IL_0027) + IL_0025: br.s IL_002a + + IL_0027: nop + IL_0028: br.s IL_0053 + + IL_002a: nop + IL_002b: ldarg.0 + IL_002c: ldfld class [runtime]System.Threading.Tasks.Task`1 Test/testTask@4::t + IL_0031: stloc.3 + IL_0032: ldarg.0 + IL_0033: ldloc.3 + IL_0034: callvirt instance valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1 class [netstandard]System.Threading.Tasks.Task`1::GetAwaiter() + IL_0039: stfld valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 Test/testTask@4::awaiter + IL_003e: ldc.i4.1 + IL_003f: stloc.s V_4 + IL_0041: ldarg.0 + IL_0042: ldflda valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 Test/testTask@4::awaiter + IL_0047: call instance bool valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1::get_IsCompleted() + IL_004c: brfalse.s IL_0050 + + IL_004e: br.s IL_0069 + + IL_0050: ldc.i4.0 + IL_0051: brfalse.s IL_0057 + + IL_0053: ldc.i4.1 + IL_0054: nop + IL_0055: br.s IL_0060 + + IL_0057: ldarg.0 + IL_0058: ldc.i4.1 + IL_0059: stfld int32 Test/testTask@4::ResumptionPoint + IL_005e: ldc.i4.0 + IL_005f: nop + IL_0060: stloc.s V_5 + IL_0062: ldloc.s V_5 + IL_0064: stloc.s V_4 + IL_0066: nop + IL_0067: br.s IL_006a + + IL_0069: nop + IL_006a: ldloc.s V_4 + IL_006c: brfalse.s IL_009a + + IL_006e: ldarg.0 + IL_006f: ldflda valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 Test/testTask@4::awaiter + IL_0074: call instance !0 valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1::GetResult() + IL_0079: stloc.s V_6 + IL_007b: ldloc.s V_6 + IL_007d: stloc.s V_7 + IL_007f: ldloc.s V_7 + IL_0081: stloc.s V_8 + IL_0083: ldloc.s V_8 + IL_0085: ldc.i4.1 + IL_0086: add + IL_0087: stloc.s V_9 + IL_0089: ldarg.0 + IL_008a: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_008f: ldloc.s V_9 + IL_0091: stfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result + IL_0096: ldc.i4.1 + IL_0097: nop + IL_0098: br.s IL_00b3 + + IL_009a: ldarg.0 + IL_009b: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_00a0: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_00a5: ldarg.0 + IL_00a6: ldflda valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 Test/testTask@4::awaiter + IL_00ab: ldarg.0 + IL_00ac: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::AwaitUnsafeOnCompleted,valuetype Test/testTask@4>(!!0&, + !!1&) + IL_00b1: ldc.i4.0 + IL_00b2: nop + IL_00b3: brfalse.s IL_00c1 + + IL_00b5: ldarg.0 + IL_00b6: ldloc.s V_10 + IL_00b8: stfld valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 Test/testTask@4::awaiter + IL_00bd: ldc.i4.1 + IL_00be: nop + IL_00bf: br.s IL_00c3 + + IL_00c1: ldc.i4.0 + IL_00c2: nop + IL_00c3: stloc.2 + IL_00c4: ldloc.2 + IL_00c5: brfalse.s IL_00e4 + + IL_00c7: ldarg.0 + IL_00c8: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_00cd: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_00d2: ldarg.0 + IL_00d3: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_00d8: ldfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result + IL_00dd: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetResult(!0) + IL_00e2: leave.s IL_00f2 + + IL_00e4: leave.s IL_00f2 + + } + catch [runtime]System.Object + { + IL_00e6: castclass [runtime]System.Exception + IL_00eb: stloc.s V_11 + IL_00ed: ldloc.s V_11 + IL_00ef: stloc.1 + IL_00f0: leave.s IL_00f2 + + } + IL_00f2: ldloc.1 + IL_00f3: stloc.s V_12 + IL_00f5: ldloc.s V_12 + IL_00f7: brtrue.s IL_00fa + + IL_00f9: ret + + IL_00fa: ldarg.0 + IL_00fb: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0100: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0105: ldloc.s V_12 + IL_0107: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetException(class [netstandard]System.Exception) + IL_010c: ret + } + + .method public strict virtual instance void SetStateMachine(class [runtime]System.Runtime.CompilerServices.IAsyncStateMachine state) cil managed + { + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine + .maxstack 8 IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,int32>>::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/'testTask@4-1'::builder@ - IL_000d: ret - } + IL_0001: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0006: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_000b: ldarg.1 + IL_000c: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetStateMachine(class [netstandard]System.Runtime.CompilerServices.IAsyncStateMachine) + IL_0011: ret + } - .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,int32> Invoke(int32 _arg1) cil managed + .method public strict virtual instance int32 get_ResumptionPoint() cil managed { - - .maxstack 7 - .locals init (int32 V_0) - IL_0000: ldarg.1 - IL_0001: stloc.0 - IL_0002: ldarg.0 - IL_0003: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/'testTask@4-1'::builder@ - IL_0008: ldloc.0 - IL_0009: ldc.i4.1 - IL_000a: add - IL_000b: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!0> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Return(!!0) - IL_0010: ret - } + .override method instance int32 class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::get_ResumptionPoint() - } + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld int32 Test/testTask@4::ResumptionPoint + IL_0006: ret + } - .class auto ansi serializable sealed nested assembly beforefieldinit testTask@4 - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,int32>> - { - .field public class [runtime]System.Threading.Tasks.Task`1 t - .field public class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@ - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .method assembly specialname rtspecialname instance void .ctor(class [runtime]System.Threading.Tasks.Task`1 t, class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@) cil managed + .method public strict virtual instance valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 get_Data() cil managed { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - + .override method instance !0 class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::get_Data() + .maxstack 8 IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,int32>>::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld class [runtime]System.Threading.Tasks.Task`1 Test/testTask@4::t - IL_000d: ldarg.0 - IL_000e: ldarg.2 - IL_000f: stfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_0014: ret - } + IL_0001: ldfld valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0006: ret + } - .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,int32> Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed + .method public strict virtual instance void set_Data(valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 'value') cil managed { - + .override method instance void class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::set_Data(!0) + .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_0006: ldarg.0 - IL_0007: ldfld class [runtime]System.Threading.Tasks.Task`1 Test/testTask@4::t - IL_000c: ldarg.0 - IL_000d: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_0012: newobj instance void Test/'testTask@4-1'::.ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder) - IL_0017: call class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!2> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderExtensions.HighPriority::TaskBuilderBase.Bind(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase, - class [runtime]System.Threading.Tasks.Task`1, - class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!2>>) - IL_001c: ret - } + IL_0001: ldarg.1 + IL_0002: stfld valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0007: ret + } - } + } .method public static class [runtime]System.Threading.Tasks.Task`1 testTask(class [runtime]System.Threading.Tasks.Task`1 t) cil managed { - - .maxstack 6 - .locals init (class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder V_0) - IL_0000: call class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderModule::get_task() - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: ldloc.0 - IL_0008: ldarg.0 - IL_0009: ldloc.0 - IL_000a: newobj instance void Test/testTask@4::.ctor(class [runtime]System.Threading.Tasks.Task`1, - class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder) - IL_000f: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!1> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Delay(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!1>>) - IL_0014: callvirt instance class [runtime]System.Threading.Tasks.Task`1 [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder::Run(class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!0>) - IL_0019: ret - } -} + .maxstack 4 + .locals init (valuetype Test/testTask@4 V_0, + valuetype Test/testTask@4& V_1) + IL_0000: ldloca.s V_0 + IL_0002: initobj Test/testTask@4 + IL_0008: ldloca.s V_0 + IL_000a: stloc.1 + IL_000b: ldloc.1 + IL_000c: ldarg.0 + IL_000d: stfld class [runtime]System.Threading.Tasks.Task`1 Test/testTask@4::t + IL_0012: ldloc.1 + IL_0013: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0018: call valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Create() + IL_001d: stfld valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0022: ldloc.1 + IL_0023: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0028: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_002d: ldloc.1 + IL_002e: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Start(!!0&) + IL_0033: ldloc.1 + IL_0034: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0039: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_003e: call instance class [netstandard]System.Threading.Tasks.Task`1 valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::get_Task() + IL_0043: ret + } + +} """ ])) @@ -424,136 +667,232 @@ let testTask() = task { try 1+1 finally System.Console.WriteLine("finally") } .class public abstract auto ansi sealed Test extends [runtime]System.Object { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) - .class auto ansi serializable sealed nested assembly beforefieldinit testTask@4 - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>> + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .class auto autochar sealed nested assembly beforefieldinit specialname testTask@4 + extends [runtime]System.ValueType + implements [runtime]System.Runtime.CompilerServices.IAsyncStateMachine, + class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1> { - .field public class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@ - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .method assembly specialname rtspecialname instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@) cil managed + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 06 00 00 00 00 00 ) + .field public valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Data + .field public int32 ResumptionPoint + .method public strict virtual instance void MoveNext() cil managed { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - - .maxstack 8 + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext + + .maxstack 4 + .locals init (int32 V_0, + class [runtime]System.Exception V_1, + bool V_2, + class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 V_3, + bool V_4, + bool V_5, + class [runtime]System.Exception V_6, + bool V_7, + bool V_8, + class [runtime]System.Exception V_9, + class [runtime]System.Exception V_10) IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>>::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_000d: ret - } + IL_0001: ldfld int32 Test/testTask@4::ResumptionPoint + IL_0006: stloc.0 + .try + { + IL_0007: ldsfld class Test/'testTask@4-1' Test/'testTask@4-1'::@_instance + IL_000c: stloc.3 + IL_000d: ldc.i4.0 + IL_000e: stloc.s V_4 + .try + { + IL_0010: nop + IL_0011: ldc.i4.1 + IL_0012: stloc.s V_5 + IL_0014: ldloc.s V_5 + IL_0016: stloc.s V_4 + IL_0018: leave.s IL_0037 + + } + catch [runtime]System.Object + { + IL_001a: castclass [runtime]System.Exception + IL_001f: stloc.s V_6 + IL_0021: ldloc.3 + IL_0022: ldnull + IL_0023: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) + IL_0028: pop + IL_0029: ldc.i4.1 + IL_002a: stloc.s V_7 + IL_002c: rethrow + IL_002e: ldnull + IL_002f: unbox.any [FSharp.Core]Microsoft.FSharp.Core.Unit + IL_0034: pop + IL_0035: leave.s IL_0037 - .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit> Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed + } + IL_0037: ldloc.s V_4 + IL_0039: brfalse.s IL_0049 + + IL_003b: ldloc.3 + IL_003c: ldnull + IL_003d: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) + IL_0042: pop + IL_0043: ldc.i4.1 + IL_0044: stloc.s V_8 + IL_0046: nop + IL_0047: br.s IL_004a + + IL_0049: nop + IL_004a: ldloc.s V_4 + IL_004c: stloc.2 + IL_004d: ldloc.2 + IL_004e: brfalse.s IL_006d + + IL_0050: ldarg.0 + IL_0051: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0056: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_005b: ldarg.0 + IL_005c: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0061: ldfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result + IL_0066: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetResult(!0) + IL_006b: leave.s IL_007b + + IL_006d: leave.s IL_007b + + } + catch [runtime]System.Object + { + IL_006f: castclass [runtime]System.Exception + IL_0074: stloc.s V_9 + IL_0076: ldloc.s V_9 + IL_0078: stloc.1 + IL_0079: leave.s IL_007b + + } + IL_007b: ldloc.1 + IL_007c: stloc.s V_10 + IL_007e: ldloc.s V_10 + IL_0080: brtrue.s IL_0083 + + IL_0082: ret + + IL_0083: ldarg.0 + IL_0084: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0089: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_008e: ldloc.s V_10 + IL_0090: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetException(class [netstandard]System.Exception) + IL_0095: ret + } + + .method public strict virtual instance void SetStateMachine(class [runtime]System.Runtime.CompilerServices.IAsyncStateMachine state) cil managed { - + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine + .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_0006: ldarg.0 - IL_0007: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_000c: ldarg.0 - IL_000d: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_0012: newobj instance void Test/'testTask@4-1'::.ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder) - IL_0017: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!1> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Delay(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!1>>) - IL_001c: ldsfld class Test/'testTask@4-2' Test/'testTask@4-2'::@_instance - IL_0021: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!1> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::TryFinally(class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!1>, - class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_0026: ret - } + IL_0001: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0006: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_000b: ldarg.1 + IL_000c: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetStateMachine(class [netstandard]System.Runtime.CompilerServices.IAsyncStateMachine) + IL_0011: ret + } - } + .method public strict virtual instance int32 get_ResumptionPoint() cil managed + { + .override method instance int32 class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::get_ResumptionPoint() - .class auto ansi serializable sealed nested assembly beforefieldinit 'testTask@4-1' - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>> - { - .field public class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@ - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .method assembly specialname rtspecialname instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@) cil managed + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld int32 Test/testTask@4::ResumptionPoint + IL_0006: ret + } + + .method public strict virtual instance valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 get_Data() cil managed { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - + .override method instance !0 class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::get_Data() + .maxstack 8 IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>>::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/'testTask@4-1'::builder@ - IL_000d: ret - } + IL_0001: ldfld valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0006: ret + } - .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit> Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed + .method public strict virtual instance void set_Data(valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 'value') cil managed { - + .override method instance void class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::set_Data(!0) + .maxstack 8 - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/'testTask@4-1'::builder@ - IL_0007: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Zero() - IL_000c: ret - } + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0007: ret + } - } + } - .class auto ansi serializable sealed nested assembly beforefieldinit 'testTask@4-2' + .class auto ansi serializable sealed nested assembly beforefieldinit 'testTask@4-1' extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 { - .field static assembly initonly class Test/'testTask@4-2' @_instance + .field static assembly initonly class Test/'testTask@4-1' @_instance .method assembly specialname rtspecialname instance void .ctor() cil managed { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) + .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::.ctor() IL_0006: ret - } + } .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.Unit Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed { - + .maxstack 8 IL_0000: nop IL_0001: ldstr "finally" IL_0006: call void [runtime]System.Console::WriteLine(string) IL_000b: ldnull IL_000c: ret - } + } .method private specialname rtspecialname static void .cctor() cil managed { - + .maxstack 10 - IL_0000: newobj instance void Test/'testTask@4-2'::.ctor() - IL_0005: stsfld class Test/'testTask@4-2' Test/'testTask@4-2'::@_instance + IL_0000: newobj instance void Test/'testTask@4-1'::.ctor() + IL_0005: stsfld class Test/'testTask@4-1' Test/'testTask@4-1'::@_instance IL_000a: ret - } + } - } + } .method public static class [runtime]System.Threading.Tasks.Task`1 testTask() cil managed { - - .maxstack 5 - .locals init (class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder V_0) - IL_0000: call class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderModule::get_task() - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: ldloc.0 - IL_0008: ldloc.0 - IL_0009: newobj instance void Test/testTask@4::.ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder) - IL_000e: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!1> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Delay(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!1>>) - IL_0013: callvirt instance class [runtime]System.Threading.Tasks.Task`1 [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder::Run(class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!0>) - IL_0018: ret - } -} + .maxstack 4 + .locals init (valuetype Test/testTask@4 V_0, + valuetype Test/testTask@4& V_1) + IL_0000: ldloca.s V_0 + IL_0002: initobj Test/testTask@4 + IL_0008: ldloca.s V_0 + IL_000a: stloc.1 + IL_000b: ldloc.1 + IL_000c: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0011: call valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Create() + IL_0016: stfld valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_001b: ldloc.1 + IL_001c: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0021: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0026: ldloc.1 + IL_0027: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Start(!!0&) + IL_002c: ldloc.1 + IL_002d: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0032: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0037: call instance class [netstandard]System.Threading.Tasks.Task`1 valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::get_Task() + IL_003c: ret + } + +} """ ])) @@ -686,139 +1025,193 @@ let testTask() = task { try 1 with e -> System.Console.WriteLine("with"); 2 } .class public abstract auto ansi sealed Test extends [runtime]System.Object { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) - .class auto ansi serializable sealed nested assembly beforefieldinit 'testTask@4-2' - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>> + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .class auto autochar sealed nested assembly beforefieldinit specialname testTask@4 + extends [runtime]System.ValueType + implements [runtime]System.Runtime.CompilerServices.IAsyncStateMachine, + class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1> { - .field public class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@ - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .method assembly specialname rtspecialname instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@) cil managed + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 06 00 00 00 00 00 ) + .field public valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Data + .field public int32 ResumptionPoint + .method public strict virtual instance void MoveNext() cil managed { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - - .maxstack 8 + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext + + .maxstack 4 + .locals init (int32 V_0, + class [runtime]System.Exception V_1, + bool V_2, + bool V_3, + bool V_4, + class [runtime]System.Exception V_5, + bool V_6, + class [runtime]System.Exception V_7, + class [runtime]System.Exception V_8, + class [runtime]System.Exception V_9, + class [runtime]System.Exception V_10, + class [runtime]System.Exception V_11) IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>>::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/'testTask@4-2'::builder@ - IL_000d: ret - } + IL_0001: ldfld int32 Test/testTask@4::ResumptionPoint + IL_0006: stloc.0 + .try + { + IL_0007: ldc.i4.0 + IL_0008: stloc.3 + IL_0009: ldc.i4.0 + IL_000a: stloc.s V_4 + IL_000c: ldnull + IL_000d: stloc.s V_5 + .try + { + IL_000f: nop + IL_0010: ldc.i4.1 + IL_0011: stloc.s V_6 + IL_0013: ldloc.s V_6 + IL_0015: stloc.3 + IL_0016: leave.s IL_0028 - .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit> Invoke(class [runtime]System.Exception _arg1) cil managed - { - - .maxstack 5 - .locals init (class [runtime]System.Exception V_0) - IL_0000: ldarg.1 - IL_0001: stloc.0 - IL_0002: ldstr "with" - IL_0007: call void [runtime]System.Console::WriteLine(string) - IL_000c: ldarg.0 - IL_000d: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/'testTask@4-2'::builder@ - IL_0012: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Zero() - IL_0017: ret - } + } + catch [runtime]System.Object + { + IL_0018: castclass [runtime]System.Exception + IL_001d: stloc.s V_7 + IL_001f: ldc.i4.1 + IL_0020: stloc.s V_4 + IL_0022: ldloc.s V_7 + IL_0024: stloc.s V_5 + IL_0026: leave.s IL_0028 - } + } + IL_0028: ldloc.s V_4 + IL_002a: brfalse.s IL_0042 + + IL_002c: ldloc.s V_5 + IL_002e: stloc.s V_8 + IL_0030: ldloc.s V_8 + IL_0032: stloc.s V_9 + IL_0034: ldstr "with" + IL_0039: call void [runtime]System.Console::WriteLine(string) + IL_003e: ldc.i4.1 + IL_003f: nop + IL_0040: br.s IL_0044 - .class auto ansi serializable sealed nested assembly beforefieldinit testTask@4 - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>> - { - .field public class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@ - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .method assembly specialname rtspecialname instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@) cil managed + IL_0042: ldloc.3 + IL_0043: nop + IL_0044: stloc.2 + IL_0045: ldloc.2 + IL_0046: brfalse.s IL_0065 + + IL_0048: ldarg.0 + IL_0049: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_004e: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0053: ldarg.0 + IL_0054: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0059: ldfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result + IL_005e: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetResult(!0) + IL_0063: leave.s IL_0073 + + IL_0065: leave.s IL_0073 + + } + catch [runtime]System.Object + { + IL_0067: castclass [runtime]System.Exception + IL_006c: stloc.s V_10 + IL_006e: ldloc.s V_10 + IL_0070: stloc.1 + IL_0071: leave.s IL_0073 + + } + IL_0073: ldloc.1 + IL_0074: stloc.s V_11 + IL_0076: ldloc.s V_11 + IL_0078: brtrue.s IL_007b + + IL_007a: ret + + IL_007b: ldarg.0 + IL_007c: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0081: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0086: ldloc.s V_11 + IL_0088: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetException(class [netstandard]System.Exception) + IL_008d: ret + } + + .method public strict virtual instance void SetStateMachine(class [runtime]System.Runtime.CompilerServices.IAsyncStateMachine state) cil managed { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine + .maxstack 8 IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>>::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_000d: ret - } + IL_0001: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0006: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_000b: ldarg.1 + IL_000c: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetStateMachine(class [netstandard]System.Runtime.CompilerServices.IAsyncStateMachine) + IL_0011: ret + } - .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit> Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed + .method public strict virtual instance int32 get_ResumptionPoint() cil managed { - + .override method instance int32 class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::get_ResumptionPoint() + .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_0006: ldarg.0 - IL_0007: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_000c: ldarg.0 - IL_000d: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_0012: newobj instance void Test/'testTask@4-1'::.ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder) - IL_0017: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!1> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Delay(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!1>>) - IL_001c: ldarg.0 - IL_001d: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@4::builder@ - IL_0022: newobj instance void Test/'testTask@4-2'::.ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder) - IL_0027: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!1> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::TryWith(class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!1>, - class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!1>>) - IL_002c: ret - } - - } + IL_0001: ldfld int32 Test/testTask@4::ResumptionPoint + IL_0006: ret + } - .class auto ansi serializable sealed nested assembly beforefieldinit 'testTask@4-1' - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>> - { - .field public class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@ - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .method assembly specialname rtspecialname instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@) cil managed + .method public strict virtual instance valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 get_Data() cil managed { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - + .override method instance !0 class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::get_Data() + .maxstack 8 IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>>::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/'testTask@4-1'::builder@ - IL_000d: ret - } + IL_0001: ldfld valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0006: ret + } - .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit> Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed + .method public strict virtual instance void set_Data(valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 'value') cil managed { - + .override method instance void class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::set_Data(!0) + .maxstack 8 - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/'testTask@4-1'::builder@ - IL_0007: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Zero() - IL_000c: ret - } + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0007: ret + } - } + } .method public static class [runtime]System.Threading.Tasks.Task`1 testTask() cil managed { - - .maxstack 5 - .locals init (class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder V_0) - IL_0000: call class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderModule::get_task() - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: ldloc.0 - IL_0008: ldloc.0 - IL_0009: newobj instance void Test/testTask@4::.ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder) - IL_000e: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!1> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Delay(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!1>>) - IL_0013: callvirt instance class [runtime]System.Threading.Tasks.Task`1 [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder::Run(class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!0>) - IL_0018: ret - } -} + .maxstack 4 + .locals init (valuetype Test/testTask@4 V_0, + valuetype Test/testTask@4& V_1) + IL_0000: ldloca.s V_0 + IL_0002: initobj Test/testTask@4 + IL_0008: ldloca.s V_0 + IL_000a: stloc.1 + IL_000b: ldloc.1 + IL_000c: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0011: call valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Create() + IL_0016: stfld valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_001b: ldloc.1 + IL_001c: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0021: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0026: ldloc.1 + IL_0027: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Start(!!0&) + IL_002c: ldloc.1 + IL_002d: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@4::Data + IL_0032: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0037: call instance class [netstandard]System.Threading.Tasks.Task`1 valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::get_Task() + IL_003c: ret + } + +} """ ])) @@ -937,47 +1330,147 @@ let testTask() = task { while x > 4 do System.Console.WriteLine("loop") } .class public abstract auto ansi sealed Test extends [runtime]System.Object { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) - .class auto ansi serializable sealed nested assembly beforefieldinit testTask@5 - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>> + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .class auto autochar sealed nested assembly beforefieldinit specialname testTask@5 + extends [runtime]System.ValueType + implements [runtime]System.Runtime.CompilerServices.IAsyncStateMachine, + class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1> { - .field public class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@ - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .method assembly specialname rtspecialname instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@) cil managed + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 06 00 00 00 00 00 ) + .field public valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Data + .field public int32 ResumptionPoint + .method public strict virtual instance void MoveNext() cil managed { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext + + .maxstack 4 + .locals init (int32 V_0, + class [runtime]System.Exception V_1, + bool V_2, + class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 V_3, + bool V_4, + bool V_5, + class [runtime]System.Exception V_6, + class [runtime]System.Exception V_7) + IL_0000: ldarg.0 + IL_0001: ldfld int32 Test/testTask@5::ResumptionPoint + IL_0006: stloc.0 + .try + { + IL_0007: ldsfld class Test/'testTask@5-1' Test/'testTask@5-1'::@_instance + IL_000c: stloc.3 + IL_000d: ldc.i4.1 + IL_000e: stloc.s V_4 + IL_0010: br.s IL_0025 + + IL_0012: ldstr "loop" + IL_0017: call void [runtime]System.Console::WriteLine(string) + IL_001c: ldc.i4.1 + IL_001d: stloc.s V_5 + IL_001f: ldloc.s V_5 + IL_0021: stloc.s V_4 + IL_0023: ldc.i4.0 + IL_0024: stloc.0 + IL_0025: ldloc.s V_4 + IL_0027: brfalse.s IL_0033 + + IL_0029: ldloc.3 + IL_002a: ldnull + IL_002b: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) + IL_0030: nop + IL_0031: br.s IL_0035 + + IL_0033: ldc.i4.0 + IL_0034: nop + IL_0035: brtrue.s IL_0012 + + IL_0037: ldloc.s V_4 + IL_0039: stloc.2 + IL_003a: ldloc.2 + IL_003b: brfalse.s IL_005a + + IL_003d: ldarg.0 + IL_003e: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@5::Data + IL_0043: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0048: ldarg.0 + IL_0049: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@5::Data + IL_004e: ldfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result + IL_0053: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetResult(!0) + IL_0058: leave.s IL_0068 + + IL_005a: leave.s IL_0068 + + } + catch [runtime]System.Object + { + IL_005c: castclass [runtime]System.Exception + IL_0061: stloc.s V_6 + IL_0063: ldloc.s V_6 + IL_0065: stloc.1 + IL_0066: leave.s IL_0068 + + } + IL_0068: ldloc.1 + IL_0069: stloc.s V_7 + IL_006b: ldloc.s V_7 + IL_006d: brtrue.s IL_0070 + + IL_006f: ret + + IL_0070: ldarg.0 + IL_0071: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@5::Data + IL_0076: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_007b: ldloc.s V_7 + IL_007d: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetException(class [netstandard]System.Exception) + IL_0082: ret + } + + .method public strict virtual instance void SetStateMachine(class [runtime]System.Runtime.CompilerServices.IAsyncStateMachine state) cil managed + { + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine + .maxstack 8 IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>>::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@5::builder@ - IL_000d: ret - } + IL_0001: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@5::Data + IL_0006: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_000b: ldarg.1 + IL_000c: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetStateMachine(class [netstandard]System.Runtime.CompilerServices.IAsyncStateMachine) + IL_0011: ret + } - .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit> Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed + .method public strict virtual instance int32 get_ResumptionPoint() cil managed { - + .override method instance int32 class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::get_ResumptionPoint() + .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@5::builder@ - IL_0006: ldsfld class Test/'testTask@5-1' Test/'testTask@5-1'::@_instance - IL_000b: ldarg.0 - IL_000c: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@5::builder@ - IL_0011: ldarg.0 - IL_0012: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/testTask@5::builder@ - IL_0017: newobj instance void Test/'testTask@5-2'::.ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder) - IL_001c: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!1> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Delay(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!1>>) - IL_0021: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::While(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, - class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>) - IL_0026: ret - } + IL_0001: ldfld int32 Test/testTask@5::ResumptionPoint + IL_0006: ret + } + + .method public strict virtual instance valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 get_Data() cil managed + { + .override method instance !0 class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::get_Data() + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@5::Data + IL_0006: ret + } - } + .method public strict virtual instance void set_Data(valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 'value') cil managed + { + .override method instance void class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::set_Data(!0) + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@5::Data + IL_0007: ret + } + + } .class auto ansi serializable sealed nested assembly beforefieldinit 'testTask@5-1' extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 @@ -985,133 +1478,108 @@ let testTask() = task { while x > 4 do System.Console.WriteLine("loop") } .field static assembly initonly class Test/'testTask@5-1' @_instance .method assembly specialname rtspecialname instance void .ctor() cil managed { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) + .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::.ctor() IL_0006: ret - } + } .method public strict virtual instance bool Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed { - + .maxstack 8 IL_0000: call int32 Test::get_x() IL_0005: ldc.i4.4 IL_0006: cgt IL_0008: ret - } + } .method private specialname rtspecialname static void .cctor() cil managed { - + .maxstack 10 IL_0000: newobj instance void Test/'testTask@5-1'::.ctor() IL_0005: stsfld class Test/'testTask@5-1' Test/'testTask@5-1'::@_instance IL_000a: ret - } - - } - - .class auto ansi serializable sealed nested assembly beforefieldinit 'testTask@5-2' - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>> - { - .field public class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@ - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .method assembly specialname rtspecialname instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@) cil managed - { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit>>::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/'testTask@5-2'::builder@ - IL_000d: ret - } - - .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit> Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed - { - - .maxstack 8 - IL_0000: ldstr "loop" - IL_0005: call void [runtime]System.Console::WriteLine(string) - IL_000a: ldarg.0 - IL_000b: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder Test/'testTask@5-2'::builder@ - IL_0010: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,class [FSharp.Core]Microsoft.FSharp.Core.Unit> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Zero() - IL_0015: ret - } + } - } + } .field static assembly int32 x@4 - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) + .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) .method public specialname static int32 get_x() cil managed { - + .maxstack 8 IL_0000: ldsfld int32 Test::x@4 IL_0005: ret - } + } .method public specialname static void set_x(int32 'value') cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: stsfld int32 Test::x@4 IL_0006: ret - } + } .method public static class [runtime]System.Threading.Tasks.Task`1 testTask() cil managed { - - .maxstack 5 - .locals init (class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder V_0) - IL_0000: call class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderModule::get_task() - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: ldloc.0 - IL_0008: ldloc.0 - IL_0009: newobj instance void Test/testTask@5::.ctor(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder) - IL_000e: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!1> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Delay(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!1>>) - IL_0013: callvirt instance class [runtime]System.Threading.Tasks.Task`1 [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder::Run(class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!0>) - IL_0018: ret - } + + .maxstack 4 + .locals init (valuetype Test/testTask@5 V_0, + valuetype Test/testTask@5& V_1) + IL_0000: ldloca.s V_0 + IL_0002: initobj Test/testTask@5 + IL_0008: ldloca.s V_0 + IL_000a: stloc.1 + IL_000b: ldloc.1 + IL_000c: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@5::Data + IL_0011: call valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Create() + IL_0016: stfld valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_001b: ldloc.1 + IL_001c: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@5::Data + IL_0021: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0026: ldloc.1 + IL_0027: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Start(!!0&) + IL_002c: ldloc.1 + IL_002d: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Test/testTask@5::Data + IL_0032: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0037: call instance class [netstandard]System.Threading.Tasks.Task`1 valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::get_Task() + IL_003c: ret + } .method private specialname rtspecialname static void .cctor() cil managed { - + .maxstack 8 IL_0000: ldc.i4.0 IL_0001: stsfld int32 ''.$Test::init@ IL_0006: ldsfld int32 ''.$Test::init@ IL_000b: pop IL_000c: ret - } + } .method assembly static void staticInitialization@() cil managed { - + .maxstack 8 IL_0000: ldc.i4.1 IL_0001: stsfld int32 Test::x@4 IL_0006: ret - } + } .property int32 x() { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 09 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 09 00 00 00 00 00 ) .set void Test::set_x(int32) .get int32 Test::get_x() - } -} + } +} """ ])) #endif @@ -1192,95 +1660,283 @@ type Generic1InGeneric1<'T>() = .class public abstract auto ansi sealed Test extends [runtime]System.Object { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) .class auto ansi serializable nested public beforefieldinit Generic1InGeneric1`1 extends [runtime]System.Object { - .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) - .class auto ansi serializable sealed nested assembly beforefieldinit clo@7 - extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!A>> + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .class auto autochar sealed nested assembly beforefieldinit specialname clo@7 + extends [runtime]System.ValueType + implements [runtime]System.Runtime.CompilerServices.IAsyncStateMachine, + class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1> { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 06 00 00 00 00 00 ) + .field public valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 Data + .field public int32 ResumptionPoint .field public class [runtime]System.Threading.Tasks.Task`1 computation - .field public class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@ - .custom instance void [runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [runtime]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - .method assembly specialname rtspecialname instance void .ctor(class [runtime]System.Threading.Tasks.Task`1 computation, class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder builder@) cil managed + .field public valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 awaiter + .method public strict virtual instance void MoveNext() cil managed { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - .custom instance void [runtime]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) - - .maxstack 8 + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext + + .maxstack 5 + .locals init (int32 V_0, + class [runtime]System.Exception V_1, + bool V_2, + class [runtime]System.Threading.Tasks.Task`1 V_3, + bool V_4, + bool V_5, + !A V_6, + !A V_7, + valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 V_8, + class [runtime]System.Exception V_9, + class [runtime]System.Exception V_10) IL_0000: ldarg.0 - IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!A>>::.ctor() - IL_0006: ldarg.0 - IL_0007: ldarg.1 - IL_0008: stfld class [runtime]System.Threading.Tasks.Task`1 class Test/Generic1InGeneric1`1/clo@7::computation - IL_000d: ldarg.0 - IL_000e: ldarg.2 - IL_000f: stfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder class Test/Generic1InGeneric1`1/clo@7::builder@ - IL_0014: ret - } - - .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!A> Invoke(class [FSharp.Core]Microsoft.FSharp.Core.Unit unitVar) cil managed + IL_0001: ldfld int32 valuetype Test/Generic1InGeneric1`1/clo@7::ResumptionPoint + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: sub + IL_000a: switch ( + IL_0015) + IL_0013: br.s IL_0018 + + IL_0015: nop + IL_0016: br.s IL_001b + + IL_0018: nop + IL_0019: ldnull + IL_001a: stloc.1 + .try + { + IL_001b: ldloc.0 + IL_001c: ldc.i4.1 + IL_001d: sub + IL_001e: switch ( + IL_0029) + IL_0027: br.s IL_002c + + IL_0029: nop + IL_002a: br.s IL_0055 + + IL_002c: nop + IL_002d: ldarg.0 + IL_002e: ldfld class [runtime]System.Threading.Tasks.Task`1 valuetype Test/Generic1InGeneric1`1/clo@7::computation + IL_0033: stloc.3 + IL_0034: ldarg.0 + IL_0035: ldloc.3 + IL_0036: callvirt instance valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1 class [netstandard]System.Threading.Tasks.Task`1::GetAwaiter() + IL_003b: stfld valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/Generic1InGeneric1`1/clo@7::awaiter + IL_0040: ldc.i4.1 + IL_0041: stloc.s V_4 + IL_0043: ldarg.0 + IL_0044: ldflda valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/Generic1InGeneric1`1/clo@7::awaiter + IL_0049: call instance bool valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1::get_IsCompleted() + IL_004e: brfalse.s IL_0052 + + IL_0050: br.s IL_006b + + IL_0052: ldc.i4.0 + IL_0053: brfalse.s IL_0059 + + IL_0055: ldc.i4.1 + IL_0056: nop + IL_0057: br.s IL_0062 + + IL_0059: ldarg.0 + IL_005a: ldc.i4.1 + IL_005b: stfld int32 valuetype Test/Generic1InGeneric1`1/clo@7::ResumptionPoint + IL_0060: ldc.i4.0 + IL_0061: nop + IL_0062: stloc.s V_5 + IL_0064: ldloc.s V_5 + IL_0066: stloc.s V_4 + IL_0068: nop + IL_0069: br.s IL_006c + + IL_006b: nop + IL_006c: ldloc.s V_4 + IL_006e: brfalse.s IL_0092 + + IL_0070: ldarg.0 + IL_0071: ldflda valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/Generic1InGeneric1`1/clo@7::awaiter + IL_0076: call instance !0 valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1::GetResult() + IL_007b: stloc.s V_6 + IL_007d: ldloc.s V_6 + IL_007f: stloc.s V_7 + IL_0081: ldarg.0 + IL_0082: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/Generic1InGeneric1`1/clo@7::Data + IL_0087: ldloc.s V_7 + IL_0089: stfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result + IL_008e: ldc.i4.1 + IL_008f: nop + IL_0090: br.s IL_00ab + + IL_0092: ldarg.0 + IL_0093: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/Generic1InGeneric1`1/clo@7::Data + IL_0098: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_009d: ldarg.0 + IL_009e: ldflda valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/Generic1InGeneric1`1/clo@7::awaiter + IL_00a3: ldarg.0 + IL_00a4: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::AwaitUnsafeOnCompleted,valuetype Test/Generic1InGeneric1`1/clo@7>(!!0&, + !!1&) + IL_00a9: ldc.i4.0 + IL_00aa: nop + IL_00ab: brfalse.s IL_00c1 + + IL_00ad: ldarg.0 + IL_00ae: ldloca.s V_8 + IL_00b0: initobj valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 + IL_00b6: ldloc.s V_8 + IL_00b8: stfld valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/Generic1InGeneric1`1/clo@7::awaiter + IL_00bd: ldc.i4.1 + IL_00be: nop + IL_00bf: br.s IL_00c3 + + IL_00c1: ldc.i4.0 + IL_00c2: nop + IL_00c3: stloc.2 + IL_00c4: ldloc.2 + IL_00c5: brfalse.s IL_00e4 + + IL_00c7: ldarg.0 + IL_00c8: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/Generic1InGeneric1`1/clo@7::Data + IL_00cd: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_00d2: ldarg.0 + IL_00d3: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/Generic1InGeneric1`1/clo@7::Data + IL_00d8: ldfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result + IL_00dd: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetResult(!0) + IL_00e2: leave.s IL_00f2 + + IL_00e4: leave.s IL_00f2 + + } + catch [runtime]System.Object + { + IL_00e6: castclass [runtime]System.Exception + IL_00eb: stloc.s V_9 + IL_00ed: ldloc.s V_9 + IL_00ef: stloc.1 + IL_00f0: leave.s IL_00f2 + + } + IL_00f2: ldloc.1 + IL_00f3: stloc.s V_10 + IL_00f5: ldloc.s V_10 + IL_00f7: brtrue.s IL_00fa + + IL_00f9: ret + + IL_00fa: ldarg.0 + IL_00fb: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/Generic1InGeneric1`1/clo@7::Data + IL_0100: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0105: ldloc.s V_10 + IL_0107: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetException(class [netstandard]System.Exception) + IL_010c: ret + } + + .method public strict virtual instance void SetStateMachine(class [runtime]System.Runtime.CompilerServices.IAsyncStateMachine state) cil managed { - + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::SetStateMachine + .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder class Test/Generic1InGeneric1`1/clo@7::builder@ - IL_0006: ldarg.0 - IL_0007: ldfld class [runtime]System.Threading.Tasks.Task`1 class Test/Generic1InGeneric1`1/clo@7::computation - IL_000c: call class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!0> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderExtensions.HighPriority::TaskBuilderBase.ReturnFrom(class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase, - class [runtime]System.Threading.Tasks.Task`1) + IL_0001: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/Generic1InGeneric1`1/clo@7::Data + IL_0006: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_000b: ldarg.1 + IL_000c: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetStateMachine(class [netstandard]System.Runtime.CompilerServices.IAsyncStateMachine) IL_0011: ret - } + } - } + .method public strict virtual instance int32 get_ResumptionPoint() cil managed + { + .override method instance int32 class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::get_ResumptionPoint() + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld int32 valuetype Test/Generic1InGeneric1`1/clo@7::ResumptionPoint + IL_0006: ret + } + + .method public strict virtual instance valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 get_Data() cil managed + { + .override method instance !0 class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::get_Data() + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/Generic1InGeneric1`1/clo@7::Data + IL_0006: ret + } + + .method public strict virtual instance void set_Data(valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 'value') cil managed + { + .override method instance void class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.IResumableStateMachine`1>::set_Data(!0) + + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/Generic1InGeneric1`1/clo@7::Data + IL_0007: ret + } + + } .method public specialname rtspecialname instance void .ctor() cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: callvirt instance void [runtime]System.Object::.ctor() IL_0006: ldarg.0 IL_0007: pop IL_0008: ret - } + } .method public hidebysig instance class [runtime]System.Threading.Tasks.Task`1 Run() cil managed { - + .maxstack 8 IL_0000: ldarg.0 IL_0001: ldc.i4.3 IL_0002: call class [runtime]System.Threading.Tasks.Task`1 [runtime]System.Threading.Tasks.Task::FromResult(!!0) IL_0007: callvirt instance class [runtime]System.Threading.Tasks.Task`1 class Test/Generic1InGeneric1`1::run(class [runtime]System.Threading.Tasks.Task`1) IL_000c: ret - } + } .method assembly hidebysig instance class [runtime]System.Threading.Tasks.Task`1 run(class [runtime]System.Threading.Tasks.Task`1 computation) cil managed { - .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - - .maxstack 6 - .locals init (class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder V_0) - IL_0000: call class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderModule::get_task() - IL_0005: stloc.0 - IL_0006: ldloc.0 - IL_0007: ldloc.0 - IL_0008: ldarg.1 - IL_0009: ldloc.0 - IL_000a: newobj instance void class Test/Generic1InGeneric1`1/clo@7::.ctor(class [runtime]System.Threading.Tasks.Task`1, - class [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder) - IL_000f: callvirt instance class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!1> [FSharp.Core]Microsoft.FSharp.Control.TaskBuilderBase::Delay(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!1>>) - IL_0014: callvirt instance class [runtime]System.Threading.Tasks.Task`1 [FSharp.Core]Microsoft.FSharp.Control.TaskBuilder::Run(class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.ResumableCode`2,!!0>) - IL_0019: ret - } + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) - } + .maxstack 4 + .locals init (valuetype Test/Generic1InGeneric1`1/clo@7 V_0, + valuetype Test/Generic1InGeneric1`1/clo@7& V_1) + IL_0000: ldloca.s V_0 + IL_0002: initobj valuetype Test/Generic1InGeneric1`1/clo@7 + IL_0008: ldloca.s V_0 + IL_000a: stloc.1 + IL_000b: ldloc.1 + IL_000c: ldarg.1 + IL_000d: stfld class [runtime]System.Threading.Tasks.Task`1 valuetype Test/Generic1InGeneric1`1/clo@7::computation + IL_0012: ldloc.1 + IL_0013: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/Generic1InGeneric1`1/clo@7::Data + IL_0018: call valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Create() + IL_001d: stfld valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0022: ldloc.1 + IL_0023: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/Generic1InGeneric1`1/clo@7::Data + IL_0028: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_002d: ldloc.1 + IL_002e: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::Start>(!!0&) + IL_0033: ldloc.1 + IL_0034: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/Generic1InGeneric1`1/clo@7::Data + IL_0039: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_003e: call instance class [netstandard]System.Threading.Tasks.Task`1 valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::get_Task() + IL_0043: ret + } -} + } + +} """ ])) #endif diff --git a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs index c313d4f27ee..a81d2ec3fed 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs @@ -44,9 +44,9 @@ module FSharpFindUsagesService = externalDefinitionItem else definitionItems - |> Array.tryFind (snd >> (=) doc.Project.FilePath) - |> Option.map (fun (definitionItem, _) -> definitionItem) - |> Option.defaultValue externalDefinitionItem + |> Array.tryFindV (snd >> (=) doc.Project.FilePath) + |> ValueOption.map (fun (definitionItem, _) -> definitionItem) + |> ValueOption.defaultValue externalDefinitionItem let referenceItem = FSharpSourceReferenceItem(definitionItem, FSharpDocumentSpan(doc, fixedSpan))