STUDIO HAZE · topaz
Topaz source
Open by house policy. Topaz is our own language.
Topaz 5.20 · 56 files
compiler/crates/topaz_self_frontend/topaz/checker/call_plan.tpz
Topaz · 41830 B · Original file
1
// Call-target selection and named, default, variadic, and spread planning.2
// Plans describe slot ownership only; call_complete performs inference and the3
// checker facade records the resulting typed call.5
import types { SyntaxNode }6
import checker_types { TypeValue }7
import checker.model {8
CallArgumentPlan,9
CallSignature,10
CheckerService,11
CheckerState,12
FunctionDefinition,13
TypeBinding,14
UserProtocolCallTarget,15
constructor,16
emptyType,17
literal,18
primitive,19
serviceInferExpression,20
}21
import checker.syntax_index {22
addDiagnostic,23
addNode,24
child,25
children,26
protocolMethodDefinition,27
text,28
}29
import checker.nominals { formType }30
import checker.protocols_methods {31
enumDefinitionForType,32
receiverMethodCallSignature,33
referenceTargetType,34
}35
import checker.members_capabilities {36
bindTypeVariable,37
builtinNamespaceFamily,38
typeArgument,39
}40
import checker.call_facts {41
builtinCallTypeParameters,42
builtinFunction,43
builtinNamespaceObject,44
defaultedCallSignature,45
recordInferredExpression,46
requiredCallSignature,47
userProtocolObject,48
}49
import checker.expression_core {50
contextualMemberObjectType,51
inferIdentifierExpression,52
inferOptionalMemberAccess,53
inferPlainMemberAccess,54
optionalReceiver,55
}57
export function nominalConstructorCallResult(58
state: CheckerState,59
moduleIndex: int,60
source: Bytes,61
callee: SyntaxNode,62
) -> Option<TypeValue> {63
if callee.kind == "expression/identifier" {64
match referenceTargetType(state, moduleIndex, callee) {65
case Some(found) => if found.kind == "newtype" {66
return Some(found)67
}68
case None => ()69
}70
}71
if callee.kind == "expression/member" {72
let object = match child(callee, "object") {73
case Some(found) => found74
case None => return None75
}76
let field = match child(callee, "field") {77
case Some(found) => text(source, found)78
case None => return None79
}80
let enumType = match referenceTargetType(81
state,82
moduleIndex,83
object,84
) {85
case Some(found) => found86
case None => return None87
}88
match enumDefinitionForType(state, moduleIndex, enumType) {89
case Some(definition) => for variant in definition.variants {90
if variant.name == field && variant.payloads.length > 0 {91
return Some(enumType)92
}93
}94
case None => ()95
}96
}97
None98
}100
export function declaredCallSignature(101
definition: FunctionDefinition,102
) -> CallSignature {103
CallSignature {104
parameterNames: definition.parameterNames,105
parameterDefaults: definition.parameterDefaults,106
parameterCount: definition.parameterTypes.length,107
variadic: definition.variadic.length > 0,108
positionalOnlyIdentity: "",109
}110
}112
function positionalOnlyCallSignature(113
identity: string,114
parameterNames: Array<string>,115
) -> CallSignature {116
CallSignature {117
...requiredCallSignature(parameterNames, false),118
positionalOnlyIdentity: identity,119
}120
}122
function collectionStaticCallSignature(123
namespace: string,124
name: string,125
) -> Option<CallSignature> {126
if (namespace == "Array" || namespace == "Set") && name == "of" {127
return Some(requiredCallSignature([], true))128
}129
if namespace == "Map" {130
return match name {131
case "new" => Some(requiredCallSignature([], false))132
case "ofEntries" => Some(requiredCallSignature(["entries"], false))133
case _ => None134
}135
}136
if namespace == "Bytes" {137
return match name {138
case "empty" => Some(requiredCallSignature([], false))139
case "encodeUtf8" | "fromHex" | "fromBase64" =>140
Some(requiredCallSignature(["s"], false))141
case "fromArray" => Some(requiredCallSignature(["values"], false))142
case "concat" => Some(requiredCallSignature(["a", "b"], false))143
case _ => None144
}145
}146
if namespace == "ByteBuffer" {147
return match name {148
case "allocate" => Some(defaultedCallSignature(149
["length", "value"],150
[false, true],151
))152
case "fromBytes" => Some(requiredCallSignature(["value"], false))153
case _ => None154
}155
}156
None157
}159
function numericBinaryStaticCallSignature(160
namespace: string,161
name: string,162
) -> Option<CallSignature> {163
if namespace == "Math" {164
return match name {165
case "sqrt" | "abs" | "floor" | "ceil" | "round" |166
"sin" | "cos" | "tan" | "isNaN" | "isFinite" =>167
Some(requiredCallSignature(["x"], false))168
case "parseFloat" => Some(requiredCallSignature(["s"], false))169
case "min" | "max" => Some(requiredCallSignature(["a", "b"], false))170
case _ => None171
}172
}173
if namespace == "Codec" {174
return match name {175
case "zstdCompress" => Some(defaultedCallSignature(176
["bytes", "level"],177
[false, true],178
))179
case "gzipCompress" | "gzipDecompress" | "deflateCompress" |180
"deflateFixedCompress" | "zlibFixedCompress" |181
"reedSolomon255223Protect" | "deflateDecompress" |182
"zstdDecompress" => Some(requiredCallSignature(["bytes"], false))183
case _ => None184
}185
}186
if namespace == "Hash" {187
return match name {188
case "sha256" | "sha512" | "crc32" =>189
Some(requiredCallSignature(["data"], false))190
case "hmacSha256" => Some(requiredCallSignature(191
["key", "message"],192
false,193
))194
case _ => None195
}196
}197
None198
}200
function hostStaticCallSignature(201
namespace: string,202
name: string,203
) -> Option<CallSignature> {204
if namespace == "FS" {205
return match name {206
case "readText" | "readBytes" | "list" =>207
Some(requiredCallSignature(["path"], false))208
case "writeText" => Some(requiredCallSignature(209
["path", "text"],210
false,211
))212
case "writeBytes" => Some(requiredCallSignature(213
["path", "bytes"],214
false,215
))216
case _ => None217
}218
}219
if namespace == "Encoding" {220
return match name {221
case "utf8Encode" | "hexDecode" | "base64Decode" =>222
Some(requiredCallSignature(["text"], false))223
case "utf8Decode" | "hexEncode" | "base64Encode" =>224
Some(requiredCallSignature(["bytes"], false))225
case _ => None226
}227
}228
if namespace == "Cli" {229
return match name {230
case "hasFlag" | "option" | "options" =>231
Some(requiredCallSignature(["args", "name"], false))232
case "positionals" => Some(requiredCallSignature(["args"], false))233
case _ => None234
}235
}236
if namespace == "Path" &&237
(name == "from" || name == "cwdRelative" || name == "project") {238
return Some(requiredCallSignature(["text"], false))239
}240
if namespace == "Regex" && name == "compile" {241
return Some(requiredCallSignature(["pattern"], false))242
}243
None244
}246
function structuredDataStaticCallSignature(247
namespace: string,248
name: string,249
) -> Option<CallSignature> {250
if namespace == "CSV" {251
return match name {252
case "parse" | "parseWithHeader" =>253
Some(requiredCallSignature(["text"], false))254
case "stringify" => Some(requiredCallSignature(["rows"], false))255
case "stringifyWithHeader" => Some(requiredCallSignature(256
["rows", "columns"],257
false,258
))259
case _ => None260
}261
}262
if namespace == "TOML" {263
return match name {264
case "parse" => Some(requiredCallSignature(["text"], false))265
case "stringify" | "toJson" | "fromJson" =>266
Some(requiredCallSignature(["value"], false))267
case _ => None268
}269
}270
if namespace == "JSON" {271
return match name {272
case "parseAs" | "parse" =>273
Some(requiredCallSignature(["text"], false))274
case "decode" | "stringify" =>275
Some(requiredCallSignature(["value"], false))276
case _ => None277
}278
}279
None280
}282
function scalarTestStaticCallSignature(283
namespace: string,284
name: string,285
) -> Option<CallSignature> {286
if namespace == "URL" && name == "parse" {287
return Some(requiredCallSignature(["text"], false))288
}289
if namespace == "Date" {290
return match name {291
case "fromYmd" => Some(requiredCallSignature(292
["year", "month", "day"],293
false,294
))295
case "parseIso" => Some(requiredCallSignature(["text"], false))296
case _ => None297
}298
}299
if namespace == "BigInt" {300
return match name {301
case "fromInt" => Some(requiredCallSignature(["n"], false))302
case "parse" => Some(requiredCallSignature(["text", "radix"], false))303
case _ => None304
}305
}306
if namespace == "Decimal" {307
return match name {308
case "fromInt" => Some(requiredCallSignature(["n"], false))309
case "parse" => Some(requiredCallSignature(["text"], false))310
case _ => None311
}312
}313
if namespace == "Test" {314
return match name {315
case "assert" => Some(defaultedCallSignature(316
["condition", "message"],317
[false, true],318
))319
case "assertEq" | "assertNe" => Some(requiredCallSignature(320
["actual", "expected"],321
false,322
))323
case "assertContains" => Some(requiredCallSignature(324
["text", "needle"],325
false,326
))327
case "assertOk" | "assertErr" | "assertSome" | "assertNone" =>328
Some(requiredCallSignature(["value"], false))329
case "assertGolden" => Some(requiredCallSignature(330
["path", "actual"],331
false,332
))333
case _ => None334
}335
}336
None337
}339
function staticBuiltinCallSignature(340
namespace: string,341
name: string,342
) -> Option<CallSignature> {343
match builtinNamespaceFamily(namespace) {344
case "collection" => collectionStaticCallSignature(namespace, name)345
case "numeric-binary" => numericBinaryStaticCallSignature(namespace, name)346
case "host" => hostStaticCallSignature(namespace, name)347
case "structured-data" => structuredDataStaticCallSignature(namespace, name)348
case "scalar" => scalarTestStaticCallSignature(namespace, name)349
case "protocol" => if namespace == "Show" && name == "show" {350
Some(positionalOnlyCallSignature("Show.show", ["value"]))351
} else if namespace == "Eq" && name == "equals" {352
Some(positionalOnlyCallSignature("Eq.equals", ["a", "b"]))353
} else if namespace == "Order" && name == "compare" {354
Some(positionalOnlyCallSignature("Order.compare", ["a", "b"]))355
} else {356
None357
}358
case _ => None359
}360
}362
export function userProtocolCallTarget(363
state: CheckerState,364
moduleIndex: int,365
source: Bytes,366
callee: SyntaxNode,367
) -> Option<UserProtocolCallTarget> {368
if callee.kind != "expression/member" {369
return None370
}371
let object = match child(callee, "object") {372
case Some(found) => found373
case None => return None374
}375
let field = match child(callee, "field") {376
case Some(found) => text(source, found)377
case None => return None378
}379
match userProtocolObject(state, moduleIndex, source, object) {380
case Some(definition) => match protocolMethodDefinition(definition, field) {381
case Some(method) => Some(UserProtocolCallTarget {382
protocolName: definition.name,383
method: method,384
})385
case None => None386
}387
case None => None388
}389
}391
export function userProtocolCallSignature(392
target: UserProtocolCallTarget,393
) -> CallSignature {394
positionalOnlyCallSignature(395
"{target.protocolName}.{target.method.name}",396
target.method.parameterNames,397
)398
}400
function containerReceiverCallSignature(401
receiver: TypeValue,402
name: string,403
) -> Option<CallSignature> {404
if receiver.kind != "constructor" {405
return None406
}407
if receiver.name == "Option" {408
return match name {409
case "okOr" => Some(requiredCallSignature(["error"], false))410
case "okOrElse" | "map" | "flatMap" =>411
Some(requiredCallSignature(["f"], false))412
case _ => None413
}414
}415
if receiver.name == "Result" {416
return match name {417
case "map" | "flatMap" => Some(requiredCallSignature(["f"], false))418
case _ => None419
}420
}421
if receiver.name == "Array" {422
return match name {423
case "get" => Some(requiredCallSignature(["i"], false))424
case "slice" => Some(requiredCallSignature(["start", "end"], false))425
case "map" | "sortedBy" | "filter" | "sortBy" | "retain" =>426
Some(requiredCallSignature(["f"], false))427
case "join" => Some(requiredCallSignature(["sep"], false))428
case "reduce" => Some(requiredCallSignature(["initial", "f"], false))429
case "indexOf" | "push" => Some(requiredCallSignature(["x"], false))430
case "insert" => Some(requiredCallSignature(431
["index", "value"],432
false,433
))434
case "removeAt" => Some(requiredCallSignature(["index"], false))435
case "sorted" | "pop" | "clear" | "reverse" | "sort" =>436
Some(requiredCallSignature([], false))437
case _ => None438
}439
}440
if receiver.name == "Map" {441
return match name {442
case "insert" => Some(requiredCallSignature(["k", "v"], false))443
case "get" | "remove" | "containsKey" =>444
Some(requiredCallSignature(["k"], false))445
case "getOr" => Some(requiredCallSignature(["k", "default"], false))446
case "isEmpty" | "clear" => Some(requiredCallSignature([], false))447
case "update" => Some(requiredCallSignature(448
["k", "initial", "f"],449
false,450
))451
case "mapValues" | "filter" =>452
Some(requiredCallSignature(["f"], false))453
case _ => None454
}455
}456
if receiver.name == "Set" {457
return match name {458
case "add" | "remove" | "contains" =>459
Some(requiredCallSignature(["x"], false))460
case "union" | "intersection" | "difference" =>461
Some(requiredCallSignature(["other"], false))462
case "isEmpty" | "toArray" | "clear" =>463
Some(requiredCallSignature([], false))464
case _ => None465
}466
}467
None468
}470
function scalarReceiverCallSignature(471
receiver: TypeValue,472
name: string,473
) -> Option<CallSignature> {474
if (receiver.kind == "primitive" || receiver.kind == "literal") &&475
receiver.name == "int" {476
return match name {477
case "atLeast" => Some(requiredCallSignature(["min"], false))478
case "atMost" => Some(requiredCallSignature(["max"], false))479
case _ => None480
}481
}482
if (receiver.kind == "primitive" || receiver.kind == "literal") &&483
receiver.name == "string" {484
return match name {485
case "startsWith" => Some(requiredCallSignature(["prefix"], false))486
case "endsWith" => Some(requiredCallSignature(["suffix"], false))487
case "contains" | "indexOf" | "lastIndexOf" =>488
Some(requiredCallSignature(["sub"], false))489
case "codePointAt" => Some(requiredCallSignature(["i"], false))490
case "split" => Some(requiredCallSignature(["sep"], false))491
case "slice" => Some(requiredCallSignature(["start", "end"], false))492
case "replace" => Some(requiredCallSignature(["old", "new"], false))493
case "scalars" | "trim" | "trimStart" | "trimEnd" | "byteLength" =>494
Some(requiredCallSignature([], false))495
case _ => None496
}497
}498
None499
}501
function runtimeReceiverCallSignature(502
receiver: TypeValue,503
name: string,504
) -> Option<CallSignature> {505
if receiver.kind == "file" {506
return match name {507
case "write" => Some(requiredCallSignature(["s"], false))508
case "read" | "close" => Some(requiredCallSignature([], false))509
case _ => None510
}511
}512
if receiver.kind == "json-value" {513
return match name {514
case "get" => Some(requiredCallSignature(["key"], false))515
case "at" => Some(requiredCallSignature(["index"], false))516
case "kind" | "isNull" | "asString" | "asBool" | "asInt" |517
"numberText" | "length" | "asArray" | "keys" | "values" =>518
Some(requiredCallSignature([], false))519
case _ => None520
}521
}522
if receiver.kind == "bytes" {523
return match name {524
case "get" => Some(requiredCallSignature(["index"], false))525
case "slice" => Some(requiredCallSignature(["start", "end"], false))526
case "decodeUtf8" | "toHex" | "toBase64" | "length" |527
"isEmpty" | "toArray" => Some(requiredCallSignature([], false))528
case _ => None529
}530
}531
if receiver.kind == "byte-buffer" {532
return match name {533
case "get" => Some(requiredCallSignature(["index"], false))534
case "set" => Some(requiredCallSignature(["index", "value"], false))535
case "fill" => Some(requiredCallSignature(536
["start", "length", "value"],537
false,538
))539
case "copy" => Some(requiredCallSignature(540
["source", "sourceStart", "targetStart", "length"],541
false,542
))543
case "length" | "toBytes" => Some(requiredCallSignature([], false))544
case _ => None545
}546
}547
if receiver.kind == "path" {548
return match name {549
case "join" => Some(requiredCallSignature(["child"], false))550
case "withExtension" => Some(requiredCallSignature(["ext"], false))551
case "parent" | "fileName" | "extension" | "normalize" | "toString" =>552
Some(requiredCallSignature([], false))553
case _ => None554
}555
}556
if receiver.kind == "regex" {557
return match name {558
case "isMatch" | "find" | "findAll" | "split" =>559
Some(requiredCallSignature(["text"], false))560
case "replaceAll" => Some(requiredCallSignature(561
["text", "replacement"],562
false,563
))564
case _ => None565
}566
}567
if receiver.kind == "url" {568
return match name {569
case "scheme" | "path" | "toString" | "host" | "fragment" | "query" =>570
Some(requiredCallSignature([], false))571
case _ => None572
}573
}574
if receiver.kind == "date" {575
return match name {576
case "addDays" => Some(requiredCallSignature(["days"], false))577
case "toIso" | "year" | "month" | "day" =>578
Some(requiredCallSignature([], false))579
case _ => None580
}581
}582
if receiver.kind == "big-int" {583
return match name {584
case "toString" => Some(requiredCallSignature(["radix"], false))585
case "div" | "mod" => Some(requiredCallSignature(["other"], false))586
case "toInt" => Some(requiredCallSignature([], false))587
case _ => None588
}589
}590
if receiver.kind == "decimal" {591
return match name {592
case "round" => Some(defaultedCallSignature(593
["scale", "mode"],594
[false, true],595
))596
case "div" => Some(defaultedCallSignature(597
["other", "scale", "mode"],598
[false, false, true],599
))600
case "toString" | "scale" | "toInt" =>601
Some(requiredCallSignature([], false))602
case _ => None603
}604
}605
None606
}608
export function builtinReceiverCallSignature(609
receiver: TypeValue,610
name: string,611
) -> Option<CallSignature> {612
if receiver.kind == "union" {613
for member in receiver.members {614
match builtinReceiverCallSignature(member, name) {615
case Some(found) => return Some(found)616
case None => ()617
}618
}619
return None620
}621
match containerReceiverCallSignature(receiver, name) {622
case Some(found) => return Some(found)623
case None => ()624
}625
match scalarReceiverCallSignature(receiver, name) {626
case Some(found) => return Some(found)627
case None => ()628
}629
runtimeReceiverCallSignature(receiver, name)630
}632
export function builtinMemberCallSignature(633
service: CheckerService,634
state: CheckerState,635
moduleIndex: int,636
source: Bytes,637
call: SyntaxNode,638
callee: SyntaxNode,639
) -> Option<CallSignature> {640
if callee.kind != "expression/member" &&641
callee.kind != "expression/optional-access" {642
return None643
}644
let object = match child(callee, "object") {645
case Some(found) => found646
case None => return None647
}648
let field = match child(callee, "field") {649
case Some(found) => found650
case None => return None651
}652
match userProtocolObject(state, moduleIndex, source, object) {653
case Some(_) => return None654
case None => ()655
}656
if builtinNamespaceObject(service, state, moduleIndex, source, object) {657
return staticBuiltinCallSignature(658
text(source, object),659
text(source, field),660
)661
}662
let objectType = serviceInferExpression(service, state, moduleIndex, source, object)663
let receiverType = if callee.kind == "expression/optional-access" {664
match optionalReceiver(contextualMemberObjectType(665
state,666
call,667
objectType,668
)) {669
case Some(receiver) => receiver.innerType670
case None => emptyType("unknown")671
}672
} else {673
objectType674
}675
match receiverMethodCallSignature(676
state,677
moduleIndex,678
receiverType,679
text(source, field),680
) {681
case Some(signature) => Some(signature)682
case None => builtinReceiverCallSignature(receiverType, text(source, field))683
}684
}686
function callParameterIndex(687
signature: CallSignature,688
name: string,689
) -> int {690
let mut index = 0691
while index < signature.parameterCount {692
match signature.parameterNames.get(index) {693
case Some(parameterName) => if parameterName == name {694
return index695
}696
case None => ()697
}698
index += 1699
}700
-1701
}703
function reportNamedCallArity(704
state: CheckerState,705
moduleIndex: int,706
node: SyntaxNode,707
signature: CallSignature,708
filled: Array<bool>,709
leadingSlot: int,710
supplied: int,711
overflow: int,712
) -> () {713
let mut required = 0714
let mut missing = false715
let mut index = 0716
while index < signature.parameterCount {717
let defaulted = match signature.parameterDefaults.get(index) {718
case Some(value) => value719
case None => false720
}721
let present = match filled.get(index) {722
case Some(value) => value723
case None => false724
}725
if !defaulted {726
required += 1727
if !present {728
missing = true729
}730
}731
index += 1732
}733
if overflow > 0 || missing {734
if signature.positionalOnlyIdentity != "" {735
let noun = if required == 1 { "argument" } else { "arguments" }736
addDiagnostic(737
state,738
moduleIndex,739
"TPZ5004",740
"`{signature.positionalOnlyIdentity}` takes {required} {noun}, found {supplied}",741
"",742
node,743
)744
} else if leadingSlot == -2 {745
addDiagnostic(746
state,747
moduleIndex,748
"TPZ5004",749
"the pipeline inserts the piped value, but this function takes no parameters",750
"",751
node,752
)753
} else {754
let optional = signature.variadic || signature.parameterCount > required755
let suffix = if optional { "+" } else { "" }756
let noun = if required == 1 { "argument" } else { "arguments" }757
addDiagnostic(758
state,759
moduleIndex,760
"TPZ5004",761
"this call needs {required}{suffix} {noun}, found {supplied}",762
"",763
node,764
)765
}766
}767
()768
}770
record NamedCallPlan {771
slots: Array<int>,772
filled: Array<bool>,773
positional: int,774
sawNamed: bool,775
sawSpread: bool,776
overflow: int,777
leadingSlot: int,778
invalid: bool,779
}781
function emptyNamedCallPlan(782
signature: CallSignature,783
hasLeading: bool,784
) -> NamedCallPlan {785
let mut filled: Array<bool> = []786
let mut index = 0787
while index < signature.parameterCount {788
filled.push(false)789
index += 1790
}791
let mut positional = 0792
let mut overflow = 0793
let mut leadingSlot = -3794
if hasLeading {795
if signature.parameterCount > 0 {796
filled[0] = true797
positional = 1798
leadingSlot = 0799
} else if signature.variadic {800
leadingSlot = -1801
} else {802
overflow = 1803
leadingSlot = -2804
}805
}806
NamedCallPlan {807
slots: [],808
filled: filled,809
positional: positional,810
sawNamed: false,811
sawSpread: false,812
overflow: overflow,813
leadingSlot: leadingSlot,814
invalid: overflow > 0,815
}816
}818
function planNamedSignatureArgument(819
state: CheckerState,820
moduleIndex: int,821
source: Bytes,822
signature: CallSignature,823
plan: NamedCallPlan,824
argument: SyntaxNode,825
) -> NamedCallPlan {826
let nameNode = match child(argument, "name") {827
case Some(found) => found828
case None => argument829
}830
let parameterIndex = callParameterIndex(signature, text(source, nameNode))831
let available = parameterIndex >= 0 && match plan.filled.get(parameterIndex) {832
case Some(value) => !value833
case None => false834
}835
let mut slots = plan.slots836
if available {837
let mut filled = plan.filled838
filled[parameterIndex] = true839
slots.push(parameterIndex)840
} else {841
let message = if parameterIndex == 0 && plan.leadingSlot == 0 {842
"`{text(source, nameNode)}` is already supplied by the pipeline (§11)"843
} else {844
"no parameter named `{text(source, nameNode)}`"845
}846
addDiagnostic(847
state,848
moduleIndex,849
"TPZ5004",850
message,851
"",852
nameNode,853
)854
slots.push(-2)855
return NamedCallPlan {856
...plan,857
sawNamed: true,858
invalid: true,859
}860
}861
NamedCallPlan { ...plan, sawNamed: true }862
}864
function hasUnsatisfiedFixedParameter(865
signature: CallSignature,866
plan: NamedCallPlan,867
) -> bool {868
let mut index = plan.positional869
while index < signature.parameterCount {870
let filled = match plan.filled.get(index) {871
case Some(value) => value872
case None => false873
}874
let defaulted = match signature.parameterDefaults.get(index) {875
case Some(value) => value876
case None => false877
}878
if !filled && !defaulted {879
return true880
}881
index += 1882
}883
false884
}886
function planSpreadSignatureArgument(887
state: CheckerState,888
moduleIndex: int,889
signature: CallSignature,890
plan: NamedCallPlan,891
argument: SyntaxNode,892
) -> NamedCallPlan {893
let mut slots = plan.slots894
let mut invalid = plan.invalid895
if plan.sawNamed {896
addDiagnostic(897
state,898
moduleIndex,899
"TPZ5004",900
"named arguments must follow spread arguments",901
"",902
argument,903
)904
invalid = true905
}906
if !plan.sawSpread && hasUnsatisfiedFixedParameter(signature, plan) {907
addDiagnostic(908
state,909
moduleIndex,910
"TPZ5004",911
"a spread argument cannot skip an unsatisfied fixed parameter",912
"",913
argument,914
)915
invalid = true916
}917
slots.push(-1)918
NamedCallPlan {919
...plan,920
sawSpread: true,921
invalid: invalid,922
}923
}925
function stageEarlierCallArgumentForSlot(926
slots: Array<int>,927
target: int,928
) -> Array<int> {929
let mut staged = slots930
let mut index = 0931
while index < staged.length {932
match staged.get(index) {933
case Some(slot) => if slot == target {934
staged[index] = -2935
return staged936
}937
case None => ()938
}939
index += 1940
}941
staged942
}944
function planPositionalSignatureArgument(945
state: CheckerState,946
moduleIndex: int,947
signature: CallSignature,948
plan: NamedCallPlan,949
argument: SyntaxNode,950
) -> NamedCallPlan {951
let mut invalid = plan.invalid952
if plan.sawNamed {953
addDiagnostic(954
state,955
moduleIndex,956
"TPZ5004",957
"positional arguments may not follow named arguments",958
"",959
argument,960
)961
invalid = true962
}963
if plan.sawSpread {964
let mut slots = plan.slots965
slots.push(-1)966
return NamedCallPlan {967
...plan,968
slots: slots,969
invalid: invalid,970
}971
}972
let mut positional = plan.positional973
if !plan.sawNamed {974
while positional < signature.parameterCount {975
let alreadyFilled = match plan.filled.get(positional) {976
case Some(value) => value977
case None => false978
}979
if !alreadyFilled { break }980
positional += 1981
}982
}983
let mut slots = plan.slots984
if positional < signature.parameterCount {985
if plan.sawNamed {986
slots = stageEarlierCallArgumentForSlot(slots, positional)987
}988
let mut filled = plan.filled989
filled[positional] = true990
slots.push(positional)991
positional += 1992
NamedCallPlan {993
...plan,994
positional: positional,995
invalid: invalid,996
}997
} else if signature.variadic {998
slots.push(-1)999
NamedCallPlan {1000
...plan,SHA256 e103291bb5fb898b02d082d21fddefdb59abfc52ad3a37c9205f8a821fcd4b66