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/protocols_methods.tpz
Topaz · 42378 B · Original file
1
// Collection and validation of protocols, conformances, and receiver methods.2
// Nominal formation precedes this leaf, and member capability lookup consumes3
// the resulting catalogs afterward.5
import types { SyntaxNode }6
import checker_types { TypeValue }7
import checker.model {8
CallSignature,9
CheckerService,10
CheckerState,11
EnumDefinition,12
FunctionDefinition,13
ModuleSyntax,14
NewtypeDefinition,15
ProtocolConformance,16
ProtocolDefinition,17
ProtocolMethodDefinition,18
ReceiverMethodDefinition,19
RecordDefinition,20
emptyType,21
functionType,22
nominal,23
nominalInModule,24
primitive,25
rigid,26
}27
import checker.type_algebra {28
typeEqual,29
typeListText,30
typeText,31
}32
import checker.syntax_index {33
addDiagnostic,34
bindSymbol,35
boolAttribute,36
child,37
children,38
containsString,39
declarationFor,40
definitionNameKey,41
enumDefinitionIndex,42
functionBounds,43
moduleIdentityAt,44
moduleIndexByIdentity,45
newtypeDefinitionIndex,46
protocolDefinition,47
protocolMethodDefinition,48
recordDefinitionIndex,49
referenceFor,50
registerTypeParameters,51
resolvedTypeOfReference,52
spanKey,53
symbolTypeByName,54
text,55
typeParameterNames,56
unwrapExport,57
}58
import checker.nominals {59
formType,60
substitute,61
}63
export function protocolConformanceIndex(64
state: CheckerState,65
moduleIndex: int,66
typeName: string,67
protocol: string,68
) -> int {69
match state.conformanceIndexes.get(conformanceKey(70
moduleIndex,71
typeName,72
protocol,73
)) {74
case Some(index) => index75
case None => -176
}77
}79
export function appendConformance(80
state: CheckerState,81
moduleIndex: int,82
typeName: string,83
protocol: string,84
derived: bool,85
) -> () {86
let mut conformances = state.conformances87
let index = conformances.length88
let mut indexes = state.conformanceIndexes89
indexes.insert(conformanceKey(moduleIndex, typeName, protocol), index)90
let mut typeIndexes = state.conformanceTypeIndexes91
typeIndexes.insert(conformanceTypeKey(typeName, protocol), index)92
conformances.push(ProtocolConformance {93
moduleIndex: moduleIndex,94
typeName: typeName,95
protocol: protocol,96
derived: derived,97
})98
()99
}101
function builtinProtocolDefinition(name: string) -> Option<ProtocolDefinition> {102
let conforming = rigid("Self", "builtin::{name}::protocol")103
if name == "Show" {104
return Some(ProtocolDefinition {105
name: name,106
methods: [ProtocolMethodDefinition {107
name: "show",108
parameterNames: ["value"],109
typeValue: functionType([conforming], [], primitive("string")),110
}],111
})112
}113
if name == "Eq" {114
return Some(ProtocolDefinition {115
name: name,116
methods: [ProtocolMethodDefinition {117
name: "equals",118
parameterNames: ["a", "b"],119
typeValue: functionType(120
[conforming, conforming],121
[],122
primitive("bool"),123
),124
}],125
})126
}127
if name == "Order" {128
return Some(ProtocolDefinition {129
name: name,130
methods: [ProtocolMethodDefinition {131
name: "compare",132
parameterNames: ["a", "b"],133
typeValue: functionType(134
[conforming, conforming],135
[],136
primitive("int"),137
),138
}],139
})140
}141
if name == "JSON" {142
return Some(ProtocolDefinition { name: name, methods: [] })143
}144
None145
}147
function protocolDefinitionForImpl(148
state: CheckerState,149
moduleIndex: int,150
name: string,151
) -> Option<ProtocolDefinition> {152
match builtinProtocolDefinition(name) {153
case Some(found) => Some(found)154
case None => protocolDefinition(state, moduleIndex, name)155
}156
}158
record OwnNominalImplTarget {159
typeValue: TypeValue,160
typeParameterCount: int,161
}163
function ownNominalImplTarget(164
state: CheckerState,165
moduleIndex: int,166
name: string,167
) -> Option<OwnNominalImplTarget> {168
let recordIndex = recordDefinitionIndex(state, moduleIndex, name)169
if recordIndex >= 0 {170
return match state.records.get(recordIndex) {171
case Some(definition) => Some(OwnNominalImplTarget {172
typeValue: nominalInModule(173
"nominal-record",174
name,175
[],176
moduleIdentityAt(state, moduleIndex),177
),178
typeParameterCount: definition.typeParameters.length,179
})180
case None => None181
}182
}183
let enumIndex = enumDefinitionIndex(state, moduleIndex, name)184
if enumIndex >= 0 {185
return match state.enums.get(enumIndex) {186
case Some(definition) => Some(OwnNominalImplTarget {187
typeValue: nominalInModule(188
"enum",189
name,190
[],191
moduleIdentityAt(state, moduleIndex),192
),193
typeParameterCount: definition.typeParameters.length,194
})195
case None => None196
}197
}198
let newtypeIndex = newtypeDefinitionIndex(state, moduleIndex, name)199
if newtypeIndex >= 0 {200
return match state.newtypes.get(newtypeIndex) {201
case Some(definition) => Some(OwnNominalImplTarget {202
typeValue: nominalInModule(203
"newtype",204
name,205
[],206
moduleIdentityAt(state, moduleIndex),207
),208
typeParameterCount: definition.typeParameters.length,209
})210
case None => None211
}212
}213
None214
}216
function predeclareProtocolImplMethod(217
service: CheckerService,218
state: CheckerState,219
module: ModuleSyntax,220
declaration: SyntaxNode,221
) -> () {222
let prepared = prepareFunctionDeclaration(223
service,224
state,225
module,226
declaration,227
None,228
)229
let mut functions = state.functions230
let index = functions.length231
functions.push(prepared.definition)232
let mut pending = state.pendingFunctions233
pending.push(prepared.definition.result.kind == "unknown")234
let mut indexes = state.functionIndexes235
indexes.insert(236
spanKey(237
module.moduleIndex,238
prepared.nameNode.lo,239
prepared.nameNode.hi,240
),241
index,242
)243
()244
}246
function protocolImplMethodDefinition(247
state: CheckerState,248
moduleIndex: int,249
declaration: SyntaxNode,250
) -> Option<FunctionDefinition> {251
let nameNode = match child(declaration, "name") {252
case Some(found) => found253
case None => return None254
}255
match state.functionIndexes.get(spanKey(256
moduleIndex,257
nameNode.lo,258
nameNode.hi,259
)) {260
case Some(index) => state.functions.get(index)261
case None => None262
}263
}265
function protocolImplExpectedType(266
method: ProtocolMethodDefinition,267
receiver: TypeValue,268
) -> TypeValue {269
substitute(method.typeValue, ["Self"], [receiver])270
}272
function protocolImplSignatureText(value: TypeValue) -> string {273
"(" + typeListText(value.parameters) + ") -> `" +274
typeText(match value.result.get(0) {275
case Some(found) => found276
case None => emptyType("unknown")277
}) + "`"278
}280
function registerManualConformance(281
state: CheckerState,282
moduleIndex: int,283
typeName: string,284
protocol: string,285
) -> () {286
appendConformance(state, moduleIndex, typeName, protocol, false)287
}289
record ProtocolImplCheckContext {290
state: CheckerState,291
module: ModuleSyntax,292
protocol: string,293
typeName: string,294
definition: ProtocolDefinition,295
receiver: TypeValue,296
}298
function checkProtocolImplMethod(299
context: ProtocolImplCheckContext,300
method: SyntaxNode,301
seen: Set<string>,302
) -> bool {303
let declaration = match child(method, "declaration") {304
case Some(found) => found305
case None => return false306
}307
let methodNameNode = match child(declaration, "name") {308
case Some(found) => found309
case None => return false310
}311
let methodName = text(context.module.source, methodNameNode)312
match protocolMethodDefinition(313
context.definition,314
methodName,315
) {316
case Some(expectedMethod) => checkProtocolImplMethodAgainstDefinition(317
context,318
method,319
seen,320
declaration,321
methodNameNode,322
methodName,323
expectedMethod,324
)325
case None => {326
addDiagnostic(327
context.state,328
context.module.moduleIndex,329
"TPZ5022",330
"protocol `{context.protocol}` has no method `{methodName}`",331
"",332
methodNameNode,333
)334
false335
}336
}337
}339
function checkProtocolImplMethodAgainstDefinition(340
context: ProtocolImplCheckContext,341
method: SyntaxNode,342
seen: Set<string>,343
declaration: SyntaxNode,344
methodNameNode: SyntaxNode,345
methodName: string,346
expectedMethod: ProtocolMethodDefinition,347
) -> bool {348
if seen.contains(methodName) {349
addDiagnostic(350
context.state,351
context.module.moduleIndex,352
"TPZ5008",353
"method `{methodName}` is implemented twice in `impl {context.protocol}<{context.typeName}>`",354
"",355
methodNameNode,356
)357
return false358
}359
let mut acceptedNames = seen360
acceptedNames.add(methodName)361
if boolAttribute(method, "exported") {362
addDiagnostic(363
context.state,364
context.module.moduleIndex,365
"TPZ5022",366
"protocol implementation method `{context.protocol}.{methodName}` is module-local and cannot be exported",367
"",368
method,369
)370
return false371
}372
if children(declaration, "typeParameters").length > 0 {373
addDiagnostic(374
context.state,375
context.module.moduleIndex,376
"TPZ5022",377
"protocol implementation method `{context.protocol}.{methodName}` cannot be generic",378
"",379
methodNameNode,380
)381
return false382
}383
match child(declaration, "returnType") {384
case Some(_) => ()385
case None => {386
addDiagnostic(387
context.state,388
context.module.moduleIndex,389
"TPZ5022",390
"protocol implementation method `{context.protocol}.{methodName}` requires an explicit return type (use `-> ()` for unit)",391
"",392
methodNameNode,393
)394
return false395
}396
}397
for parameter in children(declaration, "parameters") {398
if boolAttribute(parameter, "variadic") {399
addDiagnostic(400
context.state,401
context.module.moduleIndex,402
"TPZ5022",403
"protocol implementation method `{context.protocol}.{methodName}` cannot be variadic",404
"",405
parameter,406
)407
return false408
}409
}410
for parameter in children(declaration, "parameters") {411
match child(parameter, "default") {412
case Some(_) => {413
addDiagnostic(414
context.state,415
context.module.moduleIndex,416
"TPZ5022",417
"protocol implementation method `{context.protocol}.{methodName}` cannot declare parameter defaults",418
"",419
parameter,420
)421
return false422
}423
case None => ()424
}425
}426
let actualDefinition = match protocolImplMethodDefinition(427
context.state,428
context.module.moduleIndex,429
declaration,430
) {431
case Some(found) => found432
case None => return false433
}434
let actualType = functionType(435
actualDefinition.parameterTypes,436
actualDefinition.variadic,437
actualDefinition.result,438
)439
let expectedType = protocolImplExpectedType(440
expectedMethod,441
context.receiver,442
)443
if typeEqual(actualType, expectedType) {444
return true445
}446
addDiagnostic(447
context.state,448
context.module.moduleIndex,449
"TPZ5022",450
"protocol implementation method `{context.protocol}.{methodName}` must match the declared signature exactly; expected {protocolImplSignatureText(expectedType)}, found {protocolImplSignatureText(actualType)}",451
"",452
methodNameNode,453
)454
false455
}457
function collectProtocolImpl(458
service: CheckerService,459
state: CheckerState,460
module: ModuleSyntax,461
statement: SyntaxNode,462
) -> () {463
let item = unwrapExport(statement)464
if item.kind != "statement/impl" {465
return ()466
}467
if statement.kind == "statement/export" {468
return ()469
}470
let targetNode = match child(item, "target") {471
case Some(found) => found472
case None => return ()473
}474
let protocolNode = match child(item, "name") {475
case Some(found) => found476
case None => return ()477
}478
for method in children(item, "methods") {479
match child(method, "declaration") {480
case Some(declaration) => predeclareProtocolImplMethod(481
service,482
state,483
module,484
declaration,485
)486
case None => ()487
}488
}489
let protocol = text(module.source, protocolNode)490
let typeName = text(module.source, targetNode)491
match protocolDefinitionForImpl(492
state,493
module.moduleIndex,494
protocol,495
) {496
case Some(protocolDefinitionValue) => collectProtocolImplForDefinition(497
state,498
module,499
item,500
targetNode,501
protocolNode,502
protocol,503
typeName,504
protocolDefinitionValue,505
)506
case None => {507
addDiagnostic(508
state,509
module.moduleIndex,510
"TPZ5022",511
"unknown protocol `{protocol}` in `impl {protocol}<{typeName}>`",512
"",513
protocolNode,514
)515
()516
}517
}518
}520
function collectProtocolImplForDefinition(521
state: CheckerState,522
module: ModuleSyntax,523
item: SyntaxNode,524
targetNode: SyntaxNode,525
protocolNode: SyntaxNode,526
protocol: string,527
typeName: string,528
protocolDefinitionValue: ProtocolDefinition,529
) -> () {530
if protocol == "JSON" {531
addDiagnostic(532
state,533
module.moduleIndex,534
"TPZ5022",535
"`JSON` conformance is derive-only; use `derives JSON`",536
"",537
protocolNode,538
)539
return ()540
}541
match ownNominalImplTarget(542
state,543
module.moduleIndex,544
typeName,545
) {546
case Some(target) => collectProtocolImplForTarget(547
state,548
module,549
item,550
targetNode,551
protocolNode,552
protocol,553
typeName,554
protocolDefinitionValue,555
target,556
)557
case None => {558
let ownProtocol = match builtinProtocolDefinition(protocol) {559
case Some(_) => false560
case None => true561
}562
addDiagnostic(563
state,564
module.moduleIndex,565
"TPZ5520",566
if ownProtocol {567
"cannot implement `{protocol}` for `{typeName}`: a protocol impl's conforming type must be an own-module record/enum/newtype"568
} else {569
"cannot implement foreign protocol `{protocol}` for foreign type `{typeName}` (orphan rule §4.2): the protocol or the type must be defined in this module"570
},571
"",572
targetNode,573
)574
()575
}576
}577
}579
function collectProtocolImplForTarget(580
state: CheckerState,581
module: ModuleSyntax,582
item: SyntaxNode,583
targetNode: SyntaxNode,584
protocolNode: SyntaxNode,585
protocol: string,586
typeName: string,587
protocolDefinitionValue: ProtocolDefinition,588
target: OwnNominalImplTarget,589
) -> () {590
if target.typeParameterCount > 0 {591
addDiagnostic(592
state,593
module.moduleIndex,594
"TPZ5022",595
"cannot implement protocol `{protocol}` for generic nominal `{typeName}` yet; generic conformance binders are not defined",596
"",597
targetNode,598
)599
return ()600
}601
let existingIndex = protocolConformanceIndex(602
state,603
module.moduleIndex,604
typeName,605
protocol,606
)607
if existingIndex >= 0 {608
let how = match state.conformances.get(existingIndex) {609
case Some(existing) => if existing.derived {610
"via `derives`"611
} else {612
"by a previous `impl`"613
}614
case None => "by a previous `impl`"615
}616
addDiagnostic(617
state,618
module.moduleIndex,619
"TPZ5521",620
"`{typeName}` already conforms to `{protocol}` {how}; a conformance must be unique",621
"",622
targetNode,623
)624
return ()625
}626
let mut seen: Set<string> = set {}627
let mut valid = true628
let context = ProtocolImplCheckContext {629
state: state,630
module: module,631
protocol: protocol,632
typeName: typeName,633
definition: protocolDefinitionValue,634
receiver: target.typeValue,635
}636
for method in children(item, "methods") {637
if !checkProtocolImplMethod(context, method, seen) {638
valid = false639
}640
}641
for required in protocolDefinitionValue.methods {642
if !seen.contains(required.name) {643
addDiagnostic(644
state,645
module.moduleIndex,646
"TPZ5022",647
"`impl {protocol}<{typeName}>` is missing method `{required.name}`",648
"",649
protocolNode,650
)651
valid = false652
}653
}654
if valid {655
registerManualConformance(656
state,657
module.moduleIndex,658
typeName,659
protocol,660
)661
}662
()663
}665
export function collectProtocolImpls(service: CheckerService, state: CheckerState) -> () {666
for module in state.modules {667
for statement in module.root.children {668
collectProtocolImpl(service, state, module, statement)669
}670
}671
()672
}674
function receiverMethodKey(675
moduleIndex: int,676
typeName: string,677
methodName: string,678
) -> string {679
definitionNameKey(moduleIndex, "{typeName}.{methodName}")680
}682
export function conformanceTypeKey(typeName: string, protocol: string) -> string {683
"{protocol.byteLength()}:{protocol}{typeName}"684
}686
function conformanceKey(687
moduleIndex: int,688
typeName: string,689
protocol: string,690
) -> string {691
definitionNameKey(moduleIndex, conformanceTypeKey(typeName, protocol))692
}694
function builtinReceiverTypeName(name: string) -> bool {695
match name {696
case "int" | "float" | "string" | "bool" | "template" | "Array" | "Map" |697
"Set" | "Option" | "Result" | "JSONValue" | "File" | "Bytes" |698
"ByteBuffer" | "Path" | "Regex" | "Match" | "TOMLValue" | "URL" |699
"Date" | "BigInt" | "Decimal" | "RoundingMode" => true700
case _ => false701
}702
}704
function reservedReceiverMethodName(name: string) -> bool {705
match name {706
case "atLeast" | "atMost" | "scalars" | "startsWith" | "endsWith" |707
"contains" | "indexOf" | "lastIndexOf" | "trim" | "trimStart" |708
"trimEnd" | "byteLength" | "codePointAt" | "split" | "slice" |709
"replace" | "okOr" | "okOrElse" | "map" | "flatMap" | "filter" |710
"reduce" | "push" | "get" | "length" | "join" | "sorted" |711
"sortedBy" | "pop" | "clear" | "reverse" | "insert" | "removeAt" |712
"sort" | "sortBy" | "retain" | "getOr" | "remove" | "keys" |713
"values" | "entries" | "isEmpty" | "containsKey" | "update" |714
"mapValues" | "add" | "toArray" | "union" | "intersection" |715
"difference" | "read" | "write" | "close" | "tag" | "parts" |716
"kind" | "isNull" | "asString" | "asBool" | "asInt" |717
"numberText" | "at" | "asArray" | "decodeUtf8" | "toHex" |718
"toBase64" | "set" | "fill" | "copy" | "toBytes" | "parent" |719
"fileName" | "extension" | "withExtension" | "normalize" |720
"toString" | "isMatch" | "find" | "findAll" | "replaceAll" |721
"start" | "end" | "text" | "groups" | "named" | "scheme" |722
"host" | "path" | "query" | "fragment" | "toIso" | "addDays" |723
"year" | "month" | "day" | "toInt" | "div" | "mod" | "scale" |724
"round" | "value" => true725
case _ => false726
}727
}729
function bareSelfParameter(source: Bytes, parameter: SyntaxNode) -> bool {730
let nameNode = match child(parameter, "name") {731
case Some(found) => found732
case None => return false733
}734
let implicitType = match child(parameter, "type") {735
case Some(found) => found.kind == "type/named" &&736
found.lo == nameNode.lo && found.hi == nameNode.hi737
case None => false738
}739
let noDefault = match child(parameter, "default") {740
case Some(_) => false741
case None => true742
}743
text(source, nameNode) == "self" && !boolAttribute(parameter, "variadic") && implicitType &&744
noDefault745
}747
function predeclareReceiverImplMethod(748
service: CheckerService,749
state: CheckerState,750
module: ModuleSyntax,751
declaration: SyntaxNode,752
typeName: string,753
receiver: TypeValue,754
exported: bool,755
) -> () {756
let prepared = prepareFunctionDeclaration(757
service,758
state,759
module,760
declaration,761
Some(receiver),762
)763
let definition = prepared.definition764
let mut functions = state.functions765
let functionIndex = functions.length766
functions.push(definition)767
let mut pending = state.pendingFunctions768
pending.push(definition.result.kind == "unknown")769
let mut functionIndexes = state.functionIndexes770
functionIndexes.insert(771
spanKey(module.moduleIndex, prepared.nameNode.lo, prepared.nameNode.hi),772
functionIndex,773
)774
let mut receiverMethods = state.receiverMethods775
let methodIndex = receiverMethods.length776
receiverMethods.push(ReceiverMethodDefinition {777
moduleIndex: module.moduleIndex,778
typeName: typeName,779
name: definition.name,780
functionIndex: functionIndex,781
exported: exported,782
})783
let mut indexes = state.receiverMethodIndexes784
indexes.insert(785
receiverMethodKey(module.moduleIndex, typeName, definition.name),786
methodIndex,787
)788
()789
}791
function collectReceiverImplMethod(792
service: CheckerService,793
state: CheckerState,794
module: ModuleSyntax,795
method: SyntaxNode,796
declaration: SyntaxNode,797
typeName: string,798
receiver: TypeValue,799
) -> () {800
let methodNameNode = match child(declaration, "name") {801
case Some(found) => found802
case None => declaration803
}804
let methodName = text(module.source, methodNameNode)805
let parameters = children(declaration, "parameters")806
if parameters.length == 0 {807
addDiagnostic(808
state,809
module.moduleIndex,810
"TPZ5022",811
"method `{methodName}` on `{typeName}` must take `self` as its first parameter",812
"",813
methodNameNode,814
)815
return ()816
}817
let first = parameters[0]818
if !bareSelfParameter(module.source, first) {819
addDiagnostic(820
state,821
module.moduleIndex,822
"TPZ5022",823
"method `{methodName}` on `{typeName}` must take bare `self` as its first parameter (no type annotation, default, or variadic marker)",824
"",825
first,826
)827
return ()828
}829
if children(declaration, "typeParameters").length > 0 {830
addDiagnostic(831
state,832
module.moduleIndex,833
"TPZ5022",834
"generic methods are not supported yet (method `{methodName}`)",835
"",836
methodNameNode,837
)838
return ()839
}840
if reservedReceiverMethodName(methodName) {841
addDiagnostic(842
state,843
module.moduleIndex,844
"TPZ5022",845
"method name `{methodName}` on `{typeName}` collides with a builtin member; choose another name",846
"",847
methodNameNode,848
)849
return ()850
}851
let key = receiverMethodKey(module.moduleIndex, typeName, methodName)852
match state.receiverMethodIndexes.get(key) {853
case Some(_) => {854
addDiagnostic(855
state,856
module.moduleIndex,857
"TPZ5008",858
"method `{methodName}` is already defined for `{typeName}`",859
"",860
methodNameNode,861
)862
return ()863
}864
case None => ()865
}866
let recordIndex = recordDefinitionIndex(867
state,868
module.moduleIndex,869
typeName,870
)871
let mut fieldCollision = false872
match state.records.get(recordIndex) {873
case Some(definition) => for field in definition.fields {874
if field.name == methodName {875
fieldCollision = true876
}877
}878
case None => ()879
}880
if fieldCollision {881
addDiagnostic(882
state,883
module.moduleIndex,884
"TPZ5022",885
"method `{methodName}` on `{typeName}` collides with a field of the same name; rename the method (a field shadows a method)",886
"",887
methodNameNode,888
)889
return ()890
}891
predeclareReceiverImplMethod(892
service,893
state,894
module,895
declaration,896
typeName,897
receiver,898
boolAttribute(method, "exported"),899
)900
()901
}903
function collectReceiverImpl(904
service: CheckerService,905
state: CheckerState,906
module: ModuleSyntax,907
statement: SyntaxNode,908
) -> () {909
let item = unwrapExport(statement)910
if item.kind != "statement/impl" {911
return ()912
}913
if statement.kind == "statement/export" {914
let nameNode = match child(item, "name") {915
case Some(found) => found916
case None => item917
}918
addDiagnostic(919
state,920
module.moduleIndex,921
"TPZ5022",922
"an `impl` block cannot be exported; mark individual methods with `export`",923
"",924
nameNode,925
)926
return ()927
}928
match child(item, "target") {929
case Some(_) => return ()930
case None => ()931
}932
let nameNode = match child(item, "name") {933
case Some(found) => found934
case None => return ()935
}936
let typeName = text(module.source, nameNode)937
match ownNominalImplTarget(938
state,939
module.moduleIndex,940
typeName,941
) {942
case Some(target) => collectReceiverImplForTarget(943
service,944
state,945
module,946
item,947
nameNode,948
typeName,949
target,950
)951
case None => {952
let what = if builtinReceiverTypeName(typeName) {953
"a builtin type"954
} else {955
"not a declared record/enum/newtype in this module"956
}957
addDiagnostic(958
state,959
module.moduleIndex,960
"TPZ5022",961
"cannot define methods on `{typeName}` ({what}); `impl` is only allowed on an own-module record, enum, or newtype",962
"",963
nameNode,964
)965
()966
}967
}968
}970
function collectReceiverImplForTarget(971
service: CheckerService,972
state: CheckerState,973
module: ModuleSyntax,974
item: SyntaxNode,975
nameNode: SyntaxNode,976
typeName: string,977
target: OwnNominalImplTarget,978
) -> () {979
if target.typeParameterCount > 0 {980
addDiagnostic(981
state,982
module.moduleIndex,983
"TPZ5022",984
"cannot define receiver methods on generic nominal `{typeName}` yet; generic `impl` binders are not defined",985
"",986
nameNode,987
)988
return ()989
}990
for method in children(item, "methods") {991
match child(method, "declaration") {992
case Some(declaration) => collectReceiverImplMethod(993
service,994
state,995
module,996
method,997
declaration,998
typeName,999
target.typeValue,1000
)SHA256 87ce2af7c9930041fd20c6358070aa5ed15a72e74cfc3c8a66ebdf28392d7329