未验证 提交 73b875f3 编写于 作者: D Don Syme 提交者: GitHub

Fix codegen for nested tasks that fail state machine compilation (#13415)

* Fix nested state machines if state machine compilation fails

* Fix nested state machines if state machine compilation fails

* cleanup debug printing

* finish cleanup

* add missing file

* fix build

* fix build

* fix test

* Update dummy.fsx

* fix test
上级 ed956687
......@@ -973,7 +973,6 @@ let BuildFSharpMethodApp g m (vref: ValRef) vexp vexprty (args: Exprs) =
let arities = (arityOfVal vref.Deref).AritiesOfArgs
let args3, (leftover, retTy) =
let exprL expr = exprL g expr
((args, vexprty), arities) ||> List.mapFold (fun (args, fty) arity ->
match arity, args with
| (0|1), [] when typeEquiv g (domainOfFunTy g fty) g.unit_ty -> mkUnit g m, (args, rangeOfFunTy g fty)
......
......@@ -356,15 +356,13 @@ let rec CombineRefutations g r1 r2 =
let ShowCounterExample g denv m refuted =
try
let exprL expr = exprL g expr
let refutations = refuted |> List.collect (function RefutedWhenClause -> [] | RefutedInvestigation(path, discrim) -> [RefuteDiscrimSet g m path discrim])
let counterExample, enumCoversKnown =
match refutations with
| [] -> raise CannotRefute
| (r, eck) :: t ->
if verbose then dprintf "r = %s (enumCoversKnownValue = %b)\n" (LayoutRender.showL (exprL r)) eck
List.fold (fun (rAcc, eckAcc) (r, eck) ->
CombineRefutations g rAcc r, eckAcc || eck) (r, eck) t
((r, eck), t) ||> List.fold (fun (rAcc, eckAcc) (r, eck) ->
CombineRefutations g rAcc r, eckAcc || eck)
let text = LayoutRender.showL (NicePrint.dataExprL denv counterExample)
let failingWhenClause = refuted |> List.exists (function RefutedWhenClause -> true | _ -> false)
Some(text, failingWhenClause, enumCoversKnown)
......
此差异已折叠。
......@@ -1394,29 +1394,51 @@ let editorSpecificFlags (tcConfigB: TcConfigBuilder) =
let internalFlags (tcConfigB: TcConfigBuilder) =
[
CompilerOption("stamps", tagNone, OptionUnit ignore, Some(InternalCommandLineOption("--stamps", rangeCmdArgs)), None)
CompilerOption(
"typedtree",
tagNone,
OptionUnit(fun () -> tcConfigB.showTerms <- true),
Some(InternalCommandLineOption("--typedtree", rangeCmdArgs)),
None
)
CompilerOption(
"ranges",
"typedtreefile",
tagNone,
OptionSet DebugPrint.layoutRanges,
Some(InternalCommandLineOption("--ranges", rangeCmdArgs)),
OptionUnit(fun () -> tcConfigB.writeTermsToFiles <- true),
Some(InternalCommandLineOption("--typedtreefile", rangeCmdArgs)),
None
)
CompilerOption(
"terms",
"typedtreestamps",
tagNone,
OptionUnit(fun () -> tcConfigB.showTerms <- true),
Some(InternalCommandLineOption("--terms", rangeCmdArgs)),
OptionUnit(fun () -> DebugPrint.layoutStamps <- true),
Some(InternalCommandLineOption("--typedtreestamps", rangeCmdArgs)),
None
)
CompilerOption(
"termsfile",
"typedtreeranges",
tagNone,
OptionUnit(fun () -> tcConfigB.writeTermsToFiles <- true),
Some(InternalCommandLineOption("--termsfile", rangeCmdArgs)),
OptionUnit(fun () -> DebugPrint.layoutRanges <- true),
Some(InternalCommandLineOption("--typedtreeranges", rangeCmdArgs)),
None
)
CompilerOption(
"typedtreetypes",
tagNone,
OptionUnit(fun () -> DebugPrint.layoutTypes <- true),
Some(InternalCommandLineOption("--typedtreetypes", rangeCmdArgs)),
None
)
CompilerOption(
"typedtreevalreprinfo",
tagNone,
OptionUnit(fun () -> DebugPrint.layoutValReprInfo <- true),
Some(InternalCommandLineOption("--typedtreevalreprinfo", rangeCmdArgs)),
None
)
......@@ -2212,7 +2234,7 @@ let ApplyCommandLineArgs (tcConfigB: TcConfigBuilder, sourceFiles: string list,
let mutable showTermFileCount = 0
let PrintWholeAssemblyImplementation g (tcConfig: TcConfig) outfile header expr =
let PrintWholeAssemblyImplementation (tcConfig: TcConfig) outfile header expr =
if tcConfig.showTerms then
if tcConfig.writeTermsToFiles then
let fileName = outfile + ".terms"
......@@ -2223,10 +2245,10 @@ let PrintWholeAssemblyImplementation g (tcConfig: TcConfig) outfile header expr
.GetWriter()
showTermFileCount <- showTermFileCount + 1
LayoutRender.outL f (Display.squashTo 192 (DebugPrint.implFilesL g expr))
LayoutRender.outL f (Display.squashTo 192 (DebugPrint.implFilesL expr))
else
dprintf "\n------------------\nshowTerm: %s:\n" header
LayoutRender.outL stderr (Display.squashTo 192 (DebugPrint.implFilesL g expr))
LayoutRender.outL stderr (Display.squashTo 192 (DebugPrint.implFilesL expr))
dprintf "\n------------------\n"
//----------------------------------------------------------------------------
......
......@@ -20,7 +20,7 @@ open FSharp.Compiler.TypedTreeOps
let mutable showTermFileCount = 0
let PrintWholeAssemblyImplementation g (tcConfig: TcConfig) outfile header expr =
let PrintWholeAssemblyImplementation (tcConfig: TcConfig) outfile header expr =
if tcConfig.showTerms then
if tcConfig.writeTermsToFiles then
let fileName = outfile + ".terms"
......@@ -31,10 +31,10 @@ let PrintWholeAssemblyImplementation g (tcConfig: TcConfig) outfile header expr
.GetWriter()
showTermFileCount <- showTermFileCount + 1
LayoutRender.outL f (Display.squashTo 192 (DebugPrint.implFilesL g expr))
LayoutRender.outL f (Display.squashTo 192 (DebugPrint.implFilesL expr))
else
dprintf "\n------------------\nshowTerm: %s:\n" header
LayoutRender.outL stderr (Display.squashTo 192 (DebugPrint.implFilesL g expr))
LayoutRender.outL stderr (Display.squashTo 192 (DebugPrint.implFilesL expr))
dprintf "\n------------------\n"
let AddExternalCcuToOptimizationEnv tcGlobals optEnv (ccuinfo: ImportedAssembly) =
......@@ -65,15 +65,13 @@ let ApplyAllOptimizations
// Always optimize once - the results of this step give the x-module optimization
// info. Subsequent optimization steps choose representations etc. which we don't
// want to save in the x-module info (i.e. x-module info is currently "high level").
PrintWholeAssemblyImplementation tcGlobals tcConfig outfile "pass-start" implFiles
PrintWholeAssemblyImplementation tcConfig outfile "pass-start" implFiles
#if DEBUG
if tcConfig.showOptimizationData then
dprintf
"Expression prior to optimization:\n%s\n"
(LayoutRender.showL (Display.squashTo 192 (DebugPrint.implFilesL tcGlobals implFiles)))
dprintf "Expression prior to optimization:\n%s\n" (LayoutRender.showL (Display.squashTo 192 (DebugPrint.implFilesL implFiles)))
if tcConfig.showOptimizationData then
dprintf "CCU prior to optimization:\n%s\n" (LayoutRender.showL (Display.squashTo 192 (DebugPrint.entityL tcGlobals ccu.Contents)))
dprintf "CCU prior to optimization:\n%s\n" (LayoutRender.showL (Display.squashTo 192 (DebugPrint.entityL ccu.Contents)))
#endif
let optEnv0 = optEnv
......@@ -205,7 +203,7 @@ let ApplyAllOptimizations
let implFiles, implFileOptDatas = List.unzip results
let assemblyOptData = Optimizer.UnionOptimizationInfos implFileOptDatas
let tassembly = CheckedAssemblyAfterOptimization implFiles
PrintWholeAssemblyImplementation tcGlobals tcConfig outfile "pass-end" (implFiles |> List.map (fun implFile -> implFile.ImplFile))
PrintWholeAssemblyImplementation tcConfig outfile "pass-end" (implFiles |> List.map (fun implFile -> implFile.ImplFile))
ReportTime tcConfig "Ending Optimizations"
tassembly, assemblyOptData, optEnvFirstLoop
......
......@@ -771,8 +771,6 @@ let FlatEnvPacks g fclassM topValS declist (reqdItemsMap: Zmap<BindingGroupShari
// dump
if verboseTLR then
let bindingL bind = bindingL g bind
dprintf "tlr: packEnv envVals =%s\n" (showL (listL valL env.ReqdVals))
dprintf "tlr: packEnv envSubs =%s\n" (showL (listL valL env.ReqdSubEnvs))
dprintf "tlr: packEnv vals =%s\n" (showL (listL valL vals))
......@@ -795,18 +793,6 @@ let FlatEnvPacks g fclassM topValS declist (reqdItemsMap: Zmap<BindingGroupShari
// step3: chooseEnvPacks
//-------------------------------------------------------------------------
#if DEBUG
let DumpEnvPackM g envPackM =
let bindingL bind = bindingL g bind
for KeyValue(fc, packedReqdItems) in envPackM do
dprintf "packedReqdItems: fc = %A\n" fc
dprintf " reqdTypars = %s\n" (showL (commaListL (List.map typarL packedReqdItems.ep_etps)))
dprintf " aenvs = %s\n" (showL (commaListL (List.map valL packedReqdItems.ep_aenvs)))
dprintf " pack = %s\n" (showL (semiListL (List.map bindingL packedReqdItems.ep_pack)))
dprintf " unpack = %s\n" (showL (semiListL (List.map bindingL packedReqdItems.ep_unpack)))
dprintf "\n"
#endif
/// For each fclass, have an env.
/// Required to choose an PackedReqdItems,
/// e.g. deciding whether to tuple up the environment or not.
......@@ -818,9 +804,6 @@ let DumpEnvPackM g envPackM =
let ChooseReqdItemPackings g fclassM topValS declist reqdItemsMap =
if verboseTLR then dprintf "ChooseReqdItemPackings------\n"
let envPackM = FlatEnvPacks g fclassM topValS declist reqdItemsMap
#if DEBUG
if verboseTLR then DumpEnvPackM g envPackM
#endif
envPackM
//-------------------------------------------------------------------------
......
......@@ -395,11 +395,11 @@ type LowerStateMachine(g: TcGlobals) =
let remake2 (moveNextExprR, stateVars, thisVars) =
if sm_verbose then
printfn "----------- AFTER REWRITE moveNextExprWithJumpTable ----------------------"
printfn "%s" (DebugPrint.showExpr g moveNextExprR)
printfn "%s" (DebugPrint.showExpr moveNextExprR)
printfn "----------- AFTER REWRITE setStateMachineBodyR ----------------------"
printfn "%s" (DebugPrint.showExpr g setStateMachineBodyR)
printfn "%s" (DebugPrint.showExpr setStateMachineBodyR)
printfn "----------- AFTER REWRITE afterCodeBodyR ----------------------"
printfn "%s" (DebugPrint.showExpr g afterCodeBodyR)
printfn "%s" (DebugPrint.showExpr afterCodeBodyR)
LoweredStateMachine
(templateStructTy, dataTy, stateVars, thisVars,
(moveNextThisVar, moveNextExprR),
......@@ -434,13 +434,13 @@ type LowerStateMachine(g: TcGlobals) =
let rec ConvertResumableCode env (pcValInfo: ((Val * Expr) * Expr) option) expr : Result<StateMachineConversionFirstPhaseResult, string> =
if sm_verbose then
printfn "---------ConvertResumableCode-------------------"
printfn "%s" (DebugPrint.showExpr g expr)
printfn "%s" (DebugPrint.showExpr expr)
printfn "---------"
let env, expr = RepeatBindAndApplyOuterDefinitions env expr
if sm_verbose then
printfn "After RepeatBindAndApplyOuterDefinitions:\n%s" (DebugPrint.showExpr g expr)
printfn "After RepeatBindAndApplyOuterDefinitions:\n%s" (DebugPrint.showExpr expr)
printfn "---------"
// Detect the different permitted constructs in the expanded state machine
......@@ -520,14 +520,14 @@ type LowerStateMachine(g: TcGlobals) =
match res with
| Result.Ok res ->
printfn "-------------------"
printfn "Phase 1 Done for %s" (DebugPrint.showExpr g res.phase1)
printfn "Phase 1 Done for %s" (DebugPrint.showExpr res.phase1)
printfn "Phase 1 Done, resumableVars = %A" (res.resumableVars.FreeLocals |> Zset.elements |> List.map (fun v -> v.CompiledName(g.CompilerGlobalState)) |> String.concat ",")
printfn "Phase 1 Done, stateVars = %A" (res.stateVars |> List.map (fun v -> v.CompiledName(g.CompilerGlobalState)) |> String.concat ",")
printfn "Phase 1 Done, thisVars = %A" (res.thisVars |> List.map (fun v -> v.CompiledName(g.CompilerGlobalState)) |> String.concat ",")
printfn "-------------------"
| Result.Error msg->
printfn "Phase 1 failed: %s" msg
printfn "Phase 1 failed for %s" (DebugPrint.showExpr g expr)
printfn "Phase 1 failed for %s" (DebugPrint.showExpr expr)
res
and ConvertResumableEntry env pcValInfo (noneBranchExpr, someVar, someBranchExpr, _rebuild) =
......@@ -872,9 +872,9 @@ type LowerStateMachine(g: TcGlobals) =
if sm_verbose then
printfn "Found state machine override method and code expression..."
printfn "----------- OVERALL EXPRESSION FOR STATE MACHINE CONVERSION ----------------------"
printfn "%s" (DebugPrint.showExpr g overallExpr)
printfn "%s" (DebugPrint.showExpr overallExpr)
printfn "----------- INPUT TO STATE MACHINE CONVERSION ----------------------"
printfn "%s" (DebugPrint.showExpr g codeExpr)
printfn "%s" (DebugPrint.showExpr codeExpr)
printfn "----------- START STATE MACHINE CONVERSION ----------------------"
// Perform phase1 of the conversion
......
......@@ -194,7 +194,6 @@ let seqL xL xs = Seq.fold (fun z x -> z @@ xL x) emptyL xs
let namemapL xL xmap = NameMap.foldBack (fun nm x z -> xL nm x @@ z) xmap emptyL
let rec exprValueInfoL g exprVal =
let exprL expr = exprL g expr
match exprVal with
| ConstValue (x, ty) -> NicePrint.layoutConst g ty x
| UnknownValue -> wordL (tagText "?")
......
......@@ -1403,14 +1403,23 @@ val JoinTyparStaticReq: TyparStaticReq -> TyparStaticReq -> TyparStaticReq
/// Layout for internal compiler debugging purposes
module DebugPrint =
/// A global flag indicating whether debug output should include ValReprInfo
val mutable layoutValReprInfo: bool
/// A global flag indicating whether debug output should include stamps of Val and Entity
val mutable layoutStamps: bool
/// A global flag indicating whether debug output should include ranges
val layoutRanges: bool ref
val mutable layoutRanges: bool
/// A global flag indicating whether debug output should include type information
val mutable layoutTypes: bool
/// Convert a type to a string for debugging purposes
val showType: TType -> string
/// Convert an expression to a string for debugging purposes
val showExpr: TcGlobals -> Expr -> string
val showExpr: Expr -> string
/// Debug layout for a reference to a value
val valRefL: ValRef -> Layout
......@@ -1419,7 +1428,7 @@ module DebugPrint =
val unionCaseRefL: UnionCaseRef -> Layout
/// Debug layout for an value definition at its binding site
val valAtBindL: TcGlobals -> Val -> Layout
val valAtBindL: Val -> Layout
/// Debug layout for an integer
val intL: int -> Layout
......@@ -1445,32 +1454,26 @@ module DebugPrint =
/// Debug layout for a method slot signature
val slotSigL: SlotSig -> Layout
/// Debug layout for the type signature of a module or namespace definition
val entityTypeL: TcGlobals -> ModuleOrNamespaceType -> Layout
/// Debug layout for a module or namespace definition
val entityL: TcGlobals -> ModuleOrNamespace -> Layout
/// Debug layout for the type of a value
val typeOfValL: Val -> Layout
val entityL: ModuleOrNamespace -> Layout
/// Debug layout for a binding of an expression to a value
val bindingL: TcGlobals -> Binding -> Layout
val bindingL: Binding -> Layout
/// Debug layout for an expression
val exprL: TcGlobals -> Expr -> Layout
val exprL: Expr -> Layout
/// Debug layout for a type definition
val tyconL: TcGlobals -> Tycon -> Layout
val tyconL: Tycon -> Layout
/// Debug layout for a decision tree
val decisionTreeL: TcGlobals -> DecisionTree -> Layout
val decisionTreeL: DecisionTree -> Layout
/// Debug layout for an implementation file
val implFileL: TcGlobals -> CheckedImplFile -> Layout
val implFileL: CheckedImplFile -> Layout
/// Debug layout for a list of implementation files
val implFilesL: TcGlobals -> CheckedImplFile list -> Layout
val implFilesL: CheckedImplFile list -> Layout
/// Debug layout for class and record fields
val recdFieldRefL: RecdFieldRef -> Layout
......
......@@ -83,6 +83,7 @@
<Compile Include="FSharp.Core\Microsoft.FSharp.Control\AsyncType.fs" />
<Compile Include="FSharp.Core\Microsoft.FSharp.Control\Tasks.fs" />
<Compile Include="FSharp.Core\Microsoft.FSharp.Control\TasksDynamic.fs" />
<Compile Include="FSharp.Core\Microsoft.FSharp.Control\NestedTaskFailures.fs" />
<Compile Include="FSharp.Core\Microsoft.FSharp.Control\MailboxProcessorType.fs" />
<Compile Include="FSharp.Core\Microsoft.FSharp.Control\AsyncModule.fs" />
<Compile Include="FSharp.Core\Microsoft.FSharp.Control\ObservableModule.fs" />
......
namespace FSharp.Core.UnitTests.Control.Tasks
// The tasks below fail state machine comilation. This failure was causing subsequent problems in code generation.
// See https://github.com/dotnet/fsharp/issues/13404
#nowarn "3511" // state machine not staticlly compilable - this is a separate issue, see https://github.com/dotnet/fsharp/issues/13404
open System
open Microsoft.FSharp.Control
open Xunit
module NestedTasksFailingStateMachine =
module Example1 =
let transfers = [| Some 2,1 |]
let FetchInternalTransfers (includeConfirmeds: int) =
task {
let! mapPrioritiesTransfers =
task {
if includeConfirmeds > 1 then
transfers
|> Array.map(fun (loanid,c) -> loanid.Value, 4)
|> Array.map(fun (k,vs) -> k, 1)
|> Array.map(fun (id,c) -> c,true)
|> ignore
}
return [| 1 |], 1
}
module Example2 =
open System.Linq
let ``get pending internal transfers`` nonAllowedPriority (loanIds:Guid[]) =
task { return [||] }
let FetchInternalTransfers (includeConfirmeds: bool) (transferStep: string) (inform: bool) (workflow: string) =
task {
let canReserve = true
let! transfers =
task { // This is the only real async here
do! System.Threading.Tasks.Task.Delay 500
return [| // simulates data from external source
Some (Guid.NewGuid()),DateTime.Now,"3","4",5m,Some 6,Some "1",Some 71,Some "7",true,DateTime.Now;
Some (Guid.NewGuid()),DateTime.Now,"3","4",5m,Some 6,Some "1",Some 72,Some "7",true,DateTime.Now;
Some (Guid.NewGuid()),DateTime.Now,"3","4",5m,Some 6,Some "1",Some 73,Some "7",true,DateTime.Now;
|]
}
let totalCount = transfers |> Array.length
let checkIfTransfersPending notAllowedPriority =
task {
let transferIds = transfers |> Array.filter(fun (id,c,fa,ta,ts,ir,eb,o,r,me,rm) -> id.IsSome) |> Array.map(fun (id,c,fa,ta,ts,ir,eb,o,r,me,rm) -> id.Value) |> Array.distinct
let! pendingTransfers = ``get pending internal transfers`` notAllowedPriority transferIds
return
transfers
|> Array.map(fun (id,c,fa,ta,ts,ir,eb,o,r,me,rm) ->
c,fa,ta,ts,ir,eb, id.IsNone || (not (pendingTransfers.Contains id.Value)), r,me,rm
)
}
let! mapPrioritiesTransfers =
task {
match transferStep with
| "All" ->
let minOrder =
transfers
|> Array.filter(fun (loanid,c,fa,ta,ts,ir,eb,o,r,me,rm) -> loanid.IsSome && o.IsSome)
|> Array.map(fun (loanid,c,fa,ta,ts,ir,eb,o,r,me,rm) -> loanid.Value, o.Value)
|> Array.groupBy(fun (loanid,_) -> loanid)
|> Array.map(fun (k,vs) -> k, vs |> Array.map(fun (_,o) -> o) |> Array.min)
|> Map.ofArray
let mappedTransfers =
transfers |> Array.map(fun (id,c,fa,ta,ts,ir,eb,o,r,me,rm) ->
let isPrio = includeConfirmeds || o.IsNone || id.IsNone || minOrder.[id.Value] = o.Value
c,fa,ta,ts,ir,eb, isPrio, r, me, rm
)
return mappedTransfers
| "Step1"
| "Postprocessing" ->
return
transfers |> Array.map(fun (id, c, fa, ta, ts, ir, eb, o, r, me, rm) ->
c, fa, ta, ts, ir, eb, true, r, me, rm
)
| "Step2" ->
return! checkIfTransfersPending 1
| "Step3" ->
return! checkIfTransfersPending 2
| "Rebalancing" ->
return! checkIfTransfersPending 4
| _ -> return failwith ("Unknown internal transfer step: " + transferStep)
}
return canReserve, mapPrioritiesTransfers, totalCount
}
let test = FetchInternalTransfers false "All" true "Bank2"
System.Threading.Tasks.Task.WaitAll test
let result = test.Result |> printfn "%A"
type NestedStateMachineTests() =
[<Fact>]
member _.NestedStateMachineFailure1() =
let test = NestedTasksFailingStateMachine.Example1.FetchInternalTransfers 2
test.Result |> printfn "%A"
[<Fact>]
member _.NestedStateMachineFailure2() =
let test = NestedTasksFailingStateMachine.Example2.FetchInternalTransfers false "All" true "Bank2"
System.Threading.Tasks.Task.WaitAll test
let (a, b, c) = test.Result
if a <> true then failwith "failed - expected true"
if b.Length <> 3 then failwith "failed - expected results of length 3"
if c <> 3 then failwith "failed - expected 3"
......@@ -48,10 +48,12 @@
//<Expects status="success">section='- ADVANCED - ' ! option=subsystemversion kind=OptionString</Expects>
//<Expects status="success">section='- ADVANCED - ' ! option=targetprofile kind=OptionString</Expects>
//<Expects status="success">section='- ADVANCED - ' ! option=quotations-debug kind=OptionSwitch</Expects>
//<Expects status="success">section='NoSection ' ! option=stamps kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=ranges kind=OptionSet</Expects>
//<Expects status="success">section='NoSection ' ! option=terms kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=termsfile kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=typedtree kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=typedtreefile kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=typedtreestamps kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=typedtreeranges kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=typedtreetypes kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=typedtreevalreprinfo kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=pause kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=detuple kind=OptionInt</Expects>
//<Expects status="success">section='NoSection ' ! option=simulateException kind=OptionString</Expects>
......
......@@ -31,10 +31,12 @@
//<Expects status="success">section='- ADVANCED - ' ! option=fullpaths kind=OptionUnit</Expects>
//<Expects status="success">section='- ADVANCED - ' ! option=lib kind=OptionStringList</Expects>
//<Expects status="success">section='- ADVANCED - ' ! option=noframework kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=ranges kind=OptionSet</Expects>
//<Expects status="success">section='NoSection ' ! option=terms kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=termsfile kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=stamps kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=typedtree kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=typedtreefile kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=typedtreestamps kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=typedtreeranges kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=typedtreetypes kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=typedtreevalreprinfo kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=pause kind=OptionUnit</Expects>
//<Expects status="success">section='NoSection ' ! option=detuple kind=OptionInt</Expects>
//<Expects status="success">section='NoSection ' ! option=simulateException kind=OptionString</Expects>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册