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_complete.tpz
Topaz · 44856 B · Original file
1
// Argument inference and completion of checker call preparations.2
// call_plan selects signatures; this leaf binds actuals and resolves remaining3
// type variables through the shared expression callbacks.5
import types { SyntaxNode }6
import checker_types { TypeValue }7
import checker.model {8
CallArgumentPlan,9
CallPreparation,10
CallResultCandidates,11
CallSignature,12
CheckerService,13
CheckerState,14
CompletedCall,15
InferredCallArguments,16
LeadingCallArgument,17
TypeBinding,18
constructor,19
emptyType,20
functionType,21
literal,22
nominal,23
rigid,24
serviceInferExpression,25
}26
import checker.type_algebra {27
hasHole,28
transformTypeComponents,29
typeEqual,30
typeText,31
unionType,32
widen,33
}34
import checker.syntax_index {35
addDiagnostic,36
addNode,37
child,38
children,39
containsString,40
functionDefinitionForReference,41
replaceNodeType,42
text,43
}44
import checker.nominals { substitute }45
import checker.protocols_methods {46
newtypeDefinitionForType,47
receiverMethodCallSignature,48
receiverMethodType,49
}50
import checker.members_capabilities {51
applyBindings,52
bindingIndex,53
checkFunctionBounds,54
collectTypeBindings,55
comparableType,56
gateCollectionKey,57
iterableElement,58
jsonCapability,59
memberType,60
orderCapability,61
protocolCallResult,62
rigidOrUnionRigid,63
rigidProtocolBound,64
typeConforms,65
}66
import checker.call_facts {67
addCall,68
argumentValue,69
builtinCallTypeParameters,70
builtinNamespaceObject,71
contextualBuiltinArgumentType,72
contextualBuiltinCall,73
contextualGeneratedLispexCall,74
contextualStandardWrapperCall,75
currentExpectedExpression,76
inferExpressionWithExpected,77
isBareBindingExpression,78
calleeReference,79
refineExpressionToExpected,80
reportExpectedType,81
unshadowedIdentifier,82
}83
import checker.expression_core {84
checkNominalConstructionContext,85
inferLambda,86
wrapOptionalResult,87
}88
import checker.call_plan {89
builtinMemberCallSignature,90
builtinReceiverCallSignature,91
callArgumentExpectedType,92
callSlotExpectedType,93
declaredCallSignature,94
explicitCallBindings,95
inferCallCallee,96
nominalConstructorCallResult,97
planSignatureArguments,98
planTypedCallArguments,99
unknownCallArgumentPlan,100
userProtocolCallSignature,101
userProtocolCallTarget,102
}104
function unsolvedCallExpectation(105
value: TypeValue,106
parameterOrigins: Array<string>,107
) -> Option<TypeValue> {108
if value.kind == "rigid" && (value.origin.startsWith("builtin::") ||109
containsString(parameterOrigins, value.origin)) {110
// A generic parameter is a pass-through inference context. An unannotated111
// callable parameter is an actual unknown expectation and cannot solve a112
// polymorphic constructor's missing type argument.113
return Some(TypeValue { ...emptyType("unknown"), origin: "generic-call-expectation" })114
}115
None116
}118
export function callArgumentInferenceContext(119
expected: TypeValue,120
parameterOrigins: Array<string>,121
) -> TypeValue {122
transformTypeComponents(123
expected,124
(value: TypeValue) => unsolvedCallExpectation(value, parameterOrigins),125
)126
}128
export function inferContextualCallArgument(129
service: CheckerService,130
state: CheckerState,131
moduleIndex: int,132
source: Bytes,133
node: SyntaxNode,134
expected: Option<TypeValue>,135
) -> TypeValue {136
if node.kind == "expression/parenthesized" {137
match child(node, "operand") {138
case Some(operand) => {139
let inferred = inferContextualCallArgument(service, state, moduleIndex, source, operand, expected)140
addNode(state, moduleIndex, "expression", node, inferred)141
return inferred142
}143
case None => ()144
}145
}146
match expected {147
case Some(context) => {148
if node.kind == "expression/lambda" && context.kind == "function" {149
let inferred = inferLambda(service, state, moduleIndex, source, node, Some(context))150
addNode(state, moduleIndex, "expression", node, inferred)151
return inferred152
}153
if context.kind == "function" {154
match calleeReference(state, moduleIndex, node) {155
case Some(reference) => match functionDefinitionForReference(state, reference) {156
case Some(definition) => if definition.typeParameters.length > 0 {157
let inferred = serviceInferExpression(service, state, moduleIndex, source, node)158
let mut bindings: Array<TypeBinding> = []159
collectTypeBindings(inferred, context, bindings, true)160
checkFunctionBounds(state, moduleIndex, node, definition, bindings)161
let specialized = applyBindings(inferred, bindings)162
replaceNodeType(state, moduleIndex, "expression", node, specialized)163
return specialized164
}165
case None => ()166
}167
case None => ()168
}169
}170
inferExpressionWithExpected(service, state, moduleIndex, source, node, context, true)171
}172
case None => serviceInferExpression(service, state, moduleIndex, source, node)173
}174
}176
export function inferCallArguments(177
service: CheckerService,178
state: CheckerState,179
moduleIndex: int,180
source: Bytes,181
node: SyntaxNode,182
callee: SyntaxNode,183
calleeType: TypeValue,184
argumentSlots: Array<int>,185
initialActuals: Array<TypeValue>,186
) -> InferredCallArguments {187
let mut inferredTypes: Array<TypeValue> = []188
let mut inferredNodes: Array<SyntaxNode> = []189
let mut contextualActuals: Array<TypeValue> = []190
let mut argumentBindings: Array<TypeBinding> = []191
let definition = match calleeReference(state, moduleIndex, callee) {192
case Some(reference) => functionDefinitionForReference(state, reference)193
case None => None194
}195
let parameterOrigins = match definition {196
case Some(found) => found.typeParameterOrigins197
case None => []198
}199
for actual in initialActuals {200
contextualActuals.push(actual)201
}202
while contextualActuals.length < calleeType.parameters.length {203
contextualActuals.push(emptyType("unknown"))204
}205
let arguments = children(node, "arguments")206
let mut order: Array<int> = []207
let mut index = 0208
for argument in arguments {209
order.push(index)210
inferredTypes.push(emptyType("unknown"))211
inferredNodes.push(argumentValue(argument))212
index += 1213
}214
// Type dependencies follow parameter slots. The call's evaluation plan215
// continues to preserve the source order of argument effects.216
order.sortBy((position: int) => match argumentSlots.get(position) {217
case Some(slot) => if slot >= 0 { slot } else { calleeType.parameters.length }218
case None => calleeType.parameters.length219
})220
for position in order {221
let argument = arguments[position]222
let valueNode = argumentValue(argument)223
let slot = match argumentSlots.get(position) {224
case Some(found) => found225
case None => -2226
}227
let declaredExpected = contextualBuiltinArgumentType(228
state,229
moduleIndex,230
source,231
callee,232
slot,233
contextualActuals,234
callArgumentExpectedType(calleeType, argument, slot),235
)236
// Earlier actuals specialize a later callback before its body is checked.237
// A still-unsolved builtin scheme variable is an inference hole, not a238
// rigid requirement imposed on the callback's result.239
let expected = match declaredExpected {240
case Some(found) => Some(callArgumentInferenceContext(241
applyBindings(found, argumentBindings),242
parameterOrigins))243
case None => None244
}245
let inferred = inferContextualCallArgument(246
service, state, moduleIndex, source, valueNode, expected)247
inferredTypes[position] = inferred248
match declaredExpected {249
case Some(found) => collectTypeBindings(found, inferred, argumentBindings, true)250
case None => ()251
}252
if slot >= 0 && slot < contextualActuals.length {253
contextualActuals[slot] = inferred254
}255
}256
InferredCallArguments {257
types: inferredTypes,258
nodes: inferredNodes,259
}260
}262
export function leadingCallActuals(263
leading: Option<LeadingCallArgument>,264
) -> Array<TypeValue> {265
match leading {266
case Some(argument) => [argument.typeValue]267
case None => []268
}269
}271
function completeCallActuals(272
leading: Option<LeadingCallArgument>,273
explicit: Array<TypeValue>,274
) -> Array<TypeValue> {275
let mut actuals = leadingCallActuals(leading)276
for actual in explicit {277
actuals.push(actual)278
}279
actuals280
}282
function collectCallTypeBindings(283
state: CheckerState,284
node: SyntaxNode,285
calleeType: TypeValue,286
argumentPlan: CallArgumentPlan,287
actuals: Array<TypeValue>,288
leading: Option<LeadingCallArgument>,289
bindings: Array<TypeBinding>,290
) -> () {291
let mut inferredBindings = bindings292
match currentExpectedExpression(state, node) {293
case Some(expectedResult) => match calleeType.result.get(0) {294
case Some(declaredResult) => collectTypeBindings(295
declaredResult,296
expectedResult,297
inferredBindings,298
false,299
)300
case None => ()301
}302
case None => ()303
}304
collectCallInputTypeBindings(305
node,306
calleeType,307
argumentPlan,308
actuals,309
leading,310
inferredBindings,311
)312
}314
function collectCallInputTypeBindings(315
node: SyntaxNode,316
calleeType: TypeValue,317
argumentPlan: CallArgumentPlan,318
actuals: Array<TypeValue>,319
leading: Option<LeadingCallArgument>,320
bindings: Array<TypeBinding>,321
) -> () {322
let mut inferredBindings = bindings323
match leading {324
case Some(argument) => match callSlotExpectedType(325
calleeType,326
argumentPlan.leadingSlot,327
false,328
) {329
case Some(expected) => collectTypeBindings(330
expected,331
argument.typeValue,332
inferredBindings,333
true,334
)335
case None => ()336
}337
case None => ()338
}339
let mut index = 0340
for argument in children(node, "arguments") {341
let slot = match argumentPlan.slots.get(index) {342
case Some(found) => found343
case None => -2344
}345
match callArgumentExpectedType(calleeType, argument, slot) {346
case Some(expected) => match actuals.get(index) {347
case Some(actual) => collectTypeBindings(348
expected,349
actual,350
inferredBindings,351
true,352
)353
case None => ()354
}355
case None => ()356
}357
index += 1358
}359
()360
}362
function projectedCallMember(363
source: Bytes,364
callee: SyntaxNode,365
receiverType: TypeValue,366
) -> string {367
if !rigidOrUnionRigid(receiverType) ||368
(callee.kind != "expression/member" &&369
callee.kind != "expression/optional-access") {370
return ""371
}372
match child(callee, "field") {373
case Some(field) => text(source, field)374
case None => ""375
}376
}378
function specializeCallCallee(379
state: CheckerState,380
moduleIndex: int,381
source: Bytes,382
node: SyntaxNode,383
callee: SyntaxNode,384
calleeType: TypeValue,385
actuals: Array<TypeValue>,386
bindings: Array<TypeBinding>,387
) -> TypeValue {388
match contextualStandardWrapperCall(389
state,390
moduleIndex,391
node,392
callee,393
calleeType,394
actuals,395
) {396
case Some(found) => found397
case None => match contextualGeneratedLispexCall(398
state,399
moduleIndex,400
source,401
node,402
callee,403
actuals,404
) {405
case Some(found) => found406
case None => match contextualBuiltinCall(407
state,408
moduleIndex,409
source,410
node,411
callee,412
calleeType,413
) {414
case Some(found) => found415
case None => applyBindings(calleeType, bindings)416
}417
}418
}419
}421
function eraseUnboundBuiltinCallTypeParameter(422
value: TypeValue,423
parameters: Array<string>,424
bindings: Array<TypeBinding>,425
) -> Option<TypeValue> {426
if value.kind == "rigid" && containsString(parameters, value.name) &&427
bindingIndex(bindings, value.name) < 0 {428
return Some(emptyType("unknown"))429
}430
None431
}433
function eraseUnboundBuiltinCallTypeParameters(434
service: CheckerService,435
state: CheckerState,436
moduleIndex: int,437
source: Bytes,438
callee: SyntaxNode,439
receiverType: TypeValue,440
bindings: Array<TypeBinding>,441
specialized: TypeValue,442
) -> TypeValue {443
let parameters = builtinCallTypeParameters(444
service,445
state,446
moduleIndex,447
source,448
callee,449
receiverType,450
)451
if parameters.length == 0 {452
return specialized453
}454
transformTypeComponents(455
specialized,456
(component: TypeValue) => eraseUnboundBuiltinCallTypeParameter(457
component,458
parameters,459
bindings,460
),461
)462
}464
function refineCallArguments(465
state: CheckerState,466
moduleIndex: int,467
node: SyntaxNode,468
calleeType: TypeValue,469
argumentSlots: Array<int>,470
skipFirstSlot: bool,471
actuals: Array<TypeValue>,472
actualNodes: Array<SyntaxNode>,473
bindings: Array<TypeBinding>,474
) -> () {475
let arguments = children(node, "arguments")476
let mut index = 0477
while index < actuals.length {478
let expected = match arguments.get(index) {479
case Some(argument) => match argumentSlots.get(index) {480
case Some(slot) => if skipFirstSlot && slot == 0 {481
None482
} else {483
callArgumentExpectedType(calleeType, argument, slot)484
}485
case None => None486
}487
case None => None488
}489
match expected {490
case Some(expectedType) => match actualNodes.get(index) {491
case Some(actualNode) => match actuals.get(index) {492
case Some(actualType) => {493
let specializedActual = applyBindings(actualType, bindings)494
if !typeEqual(specializedActual, actualType) {495
replaceNodeType(496
state,497
moduleIndex,498
"expression",499
actualNode,500
specializedActual,501
)502
}503
let refined = refineExpressionToExpected(504
state,505
moduleIndex,506
actualNode,507
specializedActual,508
expectedType,509
)510
reportExpectedType(511
state,512
moduleIndex,513
actualNode,514
expectedType,515
refined,516
)517
}518
case None => ()519
}520
case None => ()521
}522
case None => ()523
}524
index += 1525
}526
()527
}529
function refineLeadingCallArgument(530
state: CheckerState,531
moduleIndex: int,532
calleeType: TypeValue,533
argumentPlan: CallArgumentPlan,534
leading: Option<LeadingCallArgument>,535
diagnosticNode: SyntaxNode,536
) -> () {537
match leading {538
case Some(argument) => match callSlotExpectedType(539
calleeType,540
argumentPlan.leadingSlot,541
false,542
) {543
case Some(expected) => {544
let refined = refineExpressionToExpected(545
state,546
moduleIndex,547
argument.node,548
argument.typeValue,549
expected,550
)551
reportExpectedType(552
state,553
moduleIndex,554
diagnosticNode,555
expected,556
refined,557
)558
}559
case None => ()560
}561
case None => ()562
}563
}565
function callResultType(566
specializedCallee: TypeValue,567
calleeType: TypeValue,568
constructorResult: Option<TypeValue>,569
protocolResult: Option<TypeValue>,570
bindings: Array<TypeBinding>,571
) -> TypeValue {572
match specializedCallee.result.get(0) {573
case Some(found) => found574
case None => match constructorResult {575
case Some(found) => found576
case None => match protocolResult {577
case Some(found) => found578
case None => match calleeType.result.get(0) {579
case Some(found) => applyBindings(found, bindings)580
case None => if calleeType.kind == "nominal-record" {581
calleeType582
} else {583
emptyType("unknown")584
}585
}586
}587
}588
}589
}591
record BuiltinCallTarget {592
namespace: string,593
member: string,594
}596
function builtinCallTarget(597
service: CheckerService,598
state: CheckerState,599
moduleIndex: int,600
source: Bytes,601
callee: SyntaxNode,602
) -> BuiltinCallTarget {603
if callee.kind != "expression/member" &&604
callee.kind != "expression/optional-access" {605
return BuiltinCallTarget { namespace: "", member: "" }606
}607
let object = match child(callee, "object") {608
case Some(found) => found609
case None => return BuiltinCallTarget { namespace: "", member: "" }610
}611
BuiltinCallTarget {612
namespace: if builtinNamespaceObject(613
service,614
state,615
moduleIndex,616
source,617
object,618
) {619
text(source, object)620
} else {621
""622
},623
member: match child(callee, "field") {624
case Some(found) => text(source, found)625
case None => ""626
},627
}628
}630
function preparedCallActual(631
preparation: CallPreparation,632
inferred: InferredCallArguments,633
slot: int,634
) -> Option<TypeValue> {635
match preparation.leading {636
case Some(argument) => if preparation.argumentPlan.leadingSlot == slot {637
return Some(argument.typeValue)638
}639
case None => ()640
}641
let mut index = 0642
for actual in inferred.types {643
match preparation.argumentPlan.slots.get(index) {644
case Some(actualSlot) => if actualSlot == slot {645
return Some(actual)646
}647
case None => ()648
}649
index += 1650
}651
None652
}654
function preparedCallActualNode(655
preparation: CallPreparation,656
inferred: InferredCallArguments,657
slot: int,658
) -> Option<SyntaxNode> {659
match preparation.leading {660
case Some(argument) => if preparation.argumentPlan.leadingSlot == slot {661
return Some(preparation.diagnosticNode)662
}663
case None => ()664
}665
let mut index = 0666
for actualNode in inferred.nodes {667
match preparation.argumentPlan.slots.get(index) {668
case Some(actualSlot) => if actualSlot == slot {669
return Some(actualNode)670
}671
case None => ()672
}673
index += 1674
}675
None676
}678
function userProtocolCallConformance(679
state: CheckerState,680
moduleIndex: int,681
preparation: CallPreparation,682
inferred: InferredCallArguments,683
) -> string {684
let target = match preparation.userProtocolTarget {685
case Some(found) => found686
case None => return "not-protocol"687
}688
match preparedCallActual(preparation, inferred, 0) {689
case Some(actual) => {690
let value = widen(actual)691
if hasHole(value) {692
"defer"693
} else if typeConforms(694
state,695
moduleIndex,696
value,697
target.protocolName,698
) {699
"accept"700
} else {701
"reject"702
}703
}704
case None => "defer"705
}706
}708
function gateUserProtocolCall(709
state: CheckerState,710
moduleIndex: int,711
preparation: CallPreparation,712
inferred: InferredCallArguments,713
conformance: string,714
) -> () {715
let target = match preparation.userProtocolTarget {716
case Some(found) => found717
case None => return ()718
}719
let actualCount = inferred.types.length + match preparation.leading {720
case Some(_) => 1721
case None => 0722
}723
if conformance == "accept" ||724
(conformance == "defer" && actualCount == 0) {725
let expectedCount = target.method.typeValue.parameters.length726
if actualCount != expectedCount {727
addDiagnostic(728
state,729
moduleIndex,730
"TPZ5004",731
"`{target.protocolName}.{target.method.name}` takes {expectedCount} argument" +732
if expectedCount == 1 { "" } else { "s" } +733
", found {actualCount}",734
"",735
preparation.diagnosticNode,736
)737
}738
}739
if conformance != "reject" {740
return ()741
}742
match preparedCallActual(preparation, inferred, 0) {743
case Some(actual) => {744
let value = widen(actual)745
let nominal = value.kind == "nominal-record" ||746
value.kind == "enum" || value.kind == "newtype" ||747
value.kind == "foreign" || value.kind == "rigid"748
addDiagnostic(749
state,750
moduleIndex,751
"TPZ5522",752
if nominal {753
"`{typeText(value)}` does not conform to `{target.protocolName}`"754
} else {755
"`{typeText(value)}` does not conform to `{target.protocolName}`: a protocol receiver must be a record/enum/newtype"756
},757
"",758
match preparedCallActualNode(preparation, inferred, 0) {759
case Some(found) => found760
case None => preparation.diagnosticNode761
},762
)763
}764
case None => ()765
}766
()767
}769
function gatePreparedCallCapabilities(770
service: CheckerService,771
state: CheckerState,772
moduleIndex: int,773
source: Bytes,774
node: SyntaxNode,775
preparation: CallPreparation,776
inferred: InferredCallArguments,777
bindings: Array<TypeBinding>,778
rawResult: TypeValue,779
) -> () {780
let target = builtinCallTarget(781
service,782
state,783
moduleIndex,784
source,785
preparation.callee,786
)787
let bareCallContext = match currentExpectedExpression(state, node) {788
case Some(_) => false789
case None => true790
}791
let bareBindingCall = isBareBindingExpression(state, node)792
let unknownExpectation = match currentExpectedExpression(state, node) {793
case Some(expected) => expected.kind == "unknown" && expected.origin == "" ||794
expected.kind == "inference-variable"795
case None => false796
}797
let constructorName = if unshadowedIdentifier(state, moduleIndex, preparation.callee) {798
text(source, preparation.callee)799
} else { "" }800
if (constructorName == "Ok" || constructorName == "Err" || constructorName == "Some") &&801
(bareBindingCall || unknownExpectation) && hasHole(rawResult) {802
let mut unknownInput = false803
for actual in inferred.types { if hasHole(actual) { unknownInput = true } }804
if !unknownInput {805
addDiagnostic(state, moduleIndex, "TPZ5020",806
"this expression needs a contextual type (§22.1): annotate the binding or surrounding expectation",807
"", preparation.diagnosticNode)808
}809
}810
if bareCallContext && bareBindingCall &&811
target.namespace == "Map" && target.member == "new" &&812
hasHole(rawResult) {813
addDiagnostic(814
state,815
moduleIndex,816
"TPZ5020",817
"this expression needs a contextual type (§22.1): annotate the binding or surrounding expectation",818
"",819
preparation.diagnosticNode,820
)821
}822
if preparation.callee.kind == "expression/identifier" &&823
unshadowedIdentifier(state, moduleIndex, preparation.callee) &&824
(text(source, preparation.callee) == "map" ||825
text(source, preparation.callee) == "filter" ||826
text(source, preparation.callee) == "reduce") {827
match preparedCallActual(preparation, inferred, 0) {828
case Some(iterable) => if iterableElement(iterable).kind == "unknown" &&829
!hasHole(iterable) {830
addDiagnostic(831
state,832
moduleIndex,833
"TPZ5001",834
"`{typeText(iterable)}` is not iterable (§10)",835
"",836
match preparedCallActualNode(preparation, inferred, 0) {837
case Some(actualNode) => actualNode838
case None => preparation.diagnosticNode839
},840
)841
}842
case None => ()843
}844
if bareCallContext && hasHole(rawResult) {845
addDiagnostic(846
state,847
moduleIndex,848
"TPZ5020",849
"this expression needs a contextual type (§22.1): annotate the binding or surrounding expectation",850
"",851
preparation.diagnosticNode,852
)853
}854
}855
if bareCallContext &&856
((target.namespace == "Set" && target.member == "of") ||857
(target.namespace == "Map" &&858
(target.member == "new" || target.member == "ofEntries"))) &&859
rawResult.kind == "constructor" {860
match rawResult.arguments.get(0) {861
case Some(key) => if !hasHole(key) { gateCollectionKey(862
service,863
state,864
moduleIndex,865
preparation.diagnosticNode,866
key,867
) }868
case None => ()869
}870
}871
if target.namespace == "" &&872
(target.member == "sorted" || target.member == "sort") &&873
preparation.receiverType.kind == "constructor" &&874
preparation.receiverType.name == "Array" {875
match preparation.receiverType.arguments.get(0) {876
case Some(element) => {877
let specialized = applyBindings(element, bindings)878
if orderCapability(879
state,880
moduleIndex,881
specialized,882
[],883
) == "reject" {884
addDiagnostic(885
state,886
moduleIndex,887
"TPZ5007",888
"`{typeText(specialized)}` is not ordered comparable, so `.{target.member}()` cannot sort it",889
"",890
preparation.diagnosticNode,891
)892
}893
}894
case None => ()895
}896
}897
if target.namespace == "" &&898
(target.member == "sortedBy" || target.member == "sortBy") {899
match preparedCallActual(preparation, inferred, 0) {900
case Some(callback) => if callback.kind == "function" {901
match callback.result.get(0) {902
case Some(result) => {903
let key = applyBindings(result, bindings)904
if orderCapability(state, moduleIndex, key, []) == "reject" {905
addDiagnostic(906
state,907
moduleIndex,908
"TPZ5007",909
"the `{target.member}` key type `{typeText(key)}` is not ordered comparable, so `.{target.member}()` cannot sort it",910
"",911
preparation.diagnosticNode,912
)913
}914
}915
case None => ()916
}917
}918
case None => ()919
}920
}921
if target.namespace == "JSON" && target.member == "stringify" {922
match preparedCallActual(preparation, inferred, 0) {923
case Some(actual) => {924
let value = applyBindings(actual, bindings)925
if jsonCapability(state, moduleIndex, value, [], false) == "reject" &&926
!rigidProtocolBound(state, value, "JSON") {927
addDiagnostic(928
state,929
moduleIndex,930
"TPZ5533",931
"`{typeText(value)}` is not JSON-encodable, so `JSON.stringify` cannot encode it",932
"",933
preparation.diagnosticNode,934
)935
}936
}937
case None => ()938
}939
}940
if target.namespace == "JSON" &&941
(target.member == "parseAs" || target.member == "decode") {942
let typeArguments = children(node, "typeArguments")943
if typeArguments.length == 0 {944
if bareCallContext {945
addDiagnostic(946
state,947
moduleIndex,948
"TPZ5020",949
"this expression needs a contextual type (§22.1): annotate the binding or surrounding expectation",950
"",951
preparation.diagnosticNode,952
)953
}954
addDiagnostic(955
state,956
moduleIndex,957
"TPZ5534",958
"`JSON.{target.member}` requires an explicit type argument, e.g. `JSON.{target.member}<User>(...)`",959
"",960
preparation.diagnosticNode,961
)962
} else if rawResult.kind == "constructor" && rawResult.name == "Result" {963
match rawResult.arguments.get(0) {964
case Some(value) => if jsonCapability(965
state,966
moduleIndex,967
value,968
[],969
true,970
) == "reject" {971
addDiagnostic(972
state,973
moduleIndex,974
"TPZ5534",975
"`{typeText(value)}` is not JSON-decodable, so `JSON.{target.member}` cannot decode into it",976
"",977
preparation.diagnosticNode,978
)979
}980
case None => ()981
}982
}983
}984
if target.namespace == "Test" &&985
(target.member == "assertEq" || target.member == "assertNe") {986
match preparedCallActual(preparation, inferred, 0) {987
case Some(value) => {988
let actual = applyBindings(value, bindings)989
if !comparableType(state, moduleIndex, actual, []) {990
addDiagnostic(991
state,992
moduleIndex,993
"TPZ5007",994
"`{typeText(actual)}` is not comparable, so `Test.{target.member}` cannot compare it",995
"",996
preparation.diagnosticNode,997
)998
}999
}1000
case None => ()SHA256 0529d01100994e8d987ab7d2021667635be4fba825a8dc8224a6544d6092e052