slow.monster

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/members_capabilities.tpz

Topaz · 58903 B · Original file

1// Member catalogs and capability rules for nominal and builtin types.
2// Formation supplies declared shapes; expression and call inference consume the
3// resolved member and Eq, Order, JSON, iterable, and key decisions.
5import types { SyntaxNode }
6import checker_types { TypeValue }
7import checker.model {
8 CheckerService,
9 CheckerState,
10 FunctionDefinition,
11 TypeBinding,
12 constructor,
13 emptyType,
14 functionType,
15 inference,
16 literal,
17 nominal,
18 primitive,
19 rigid,
20 serviceBuiltinNamespaceObject,
21 structural,
23import checker.type_algebra {
24 hasHole,
25 transformTypeComponents,
26 typeContains,
27 typeEqual,
28 typeListText,
29 typeText,
30 unionType,
31 widen,
33import checker.syntax_index {
34 addDiagnostic,
35 child,
36 children,
37 containsString,
38 text,
40import checker.nominals { substitute }
41import checker.protocols_methods {
42 conformanceTypeKey,
43 enumDefinitionForType,
44 newtypeDefinitionForType,
45 protocolConformanceIndex,
46 receiverMethodType,
47 recordDefinitionForType,
50export function iterableElement(value: TypeValue) -> TypeValue {
51 if value.kind == "constructor" &&
52 (value.name == "Array" || value.name == "Set" || value.name == "Range") {
53 return match value.arguments.get(0) {
54 case Some(found) => found
55 case None => emptyType("unknown")
56 }
57 }
58 if value.kind == "rigid" || value.kind == "foreign" {
59 return rigid("ElemOf<{typeText(value)}>", "builtin::iterable")
60 }
61 emptyType("unknown")
64export record ArraySpreadElement {
65 status: string,
66 element: TypeValue,
69export function arraySpreadElement(value: TypeValue) -> ArraySpreadElement {
70 if value.kind == "constructor" && value.name == "Array" {
71 return ArraySpreadElement {
72 status: "element",
73 element: match value.arguments.get(0) {
74 case Some(found) => found
75 case None => emptyType("unknown")
76 },
77 }
78 }
79 if value.kind == "rigid" || value.kind == "foreign" {
80 return ArraySpreadElement {
81 status: "element",
82 element: rigid("ElemOf<{typeText(value)}>", "builtin::array-spread"),
83 }
84 }
85 if value.kind == "union" {
86 let mut elements: Array<TypeValue> = []
87 let mut staged = false
88 for member in value.members {
89 let spread = arraySpreadElement(member)
90 if spread.status == "invalid" {
91 return spread
92 }
93 if spread.status == "stage" {
94 staged = true
95 } else {
96 elements.push(spread.element)
97 }
98 }
99 return if staged {
100 ArraySpreadElement {
101 status: "stage",
102 element: emptyType("unknown"),
103 }
104 } else {
105 ArraySpreadElement {
106 status: "element",
107 element: unionType(elements),
108 }
109 }
110 }
111 if hasHole(value) {
112 ArraySpreadElement {
113 status: "stage",
114 element: emptyType("unknown"),
115 }
116 } else {
117 ArraySpreadElement {
118 status: "invalid",
119 element: emptyType("unknown"),
120 }
121 }
124record KeyCapabilityFailure {
125 subject: string,
126 kind: string,
129export function capabilityPath(seen: Array<string>, key: string) -> Array<string> {
130 let mut nested: Array<string> = []
131 for item in seen {
132 nested.push(item)
133 }
134 nested.push(key)
135 nested
138export function nominalCapabilityKey(value: TypeValue) -> string {
139 "{value.kind}:{value.origin}:{value.identity}<{typeListText(value.arguments)}>"
142record NominalCapabilityProjection {
143 moduleIndex: int,
144 children: Array<TypeValue>,
147function nominalCapabilityType(value: TypeValue) -> bool {
148 value.kind == "nominal-record" || value.kind == "enum" ||
149 value.kind == "newtype"
152function nominalCapabilityProjection(
153 state: CheckerState,
154 moduleIndex: int,
155 value: TypeValue,
156) -> NominalCapabilityProjection {
157 let mut children: Array<TypeValue> = []
158 if value.kind == "nominal-record" {
159 return match recordDefinitionForType(state, moduleIndex, value) {
160 case Some(definition) => {
161 for field in definition.fields {
162 children.push(substitute(
163 field.typeValue,
164 definition.typeParameters,
165 value.arguments,
166 ))
167 }
168 NominalCapabilityProjection {
169 moduleIndex: definition.moduleIndex,
170 children: children,
171 }
172 }
173 case None => NominalCapabilityProjection {
174 moduleIndex: moduleIndex,
175 children: children,
176 }
177 }
178 }
179 if value.kind == "enum" {
180 return match enumDefinitionForType(state, moduleIndex, value) {
181 case Some(definition) => {
182 for variant in definition.variants {
183 for payload in variant.payloads {
184 children.push(substitute(
185 payload,
186 definition.typeParameters,
187 value.arguments,
188 ))
189 }
190 }
191 NominalCapabilityProjection {
192 moduleIndex: definition.moduleIndex,
193 children: children,
194 }
195 }
196 case None => NominalCapabilityProjection {
197 moduleIndex: moduleIndex,
198 children: children,
199 }
200 }
201 }
202 match newtypeDefinitionForType(state, moduleIndex, value) {
203 case Some(definition) => {
204 children.push(substitute(
205 definition.base,
206 definition.typeParameters,
207 value.arguments,
208 ))
209 NominalCapabilityProjection {
210 moduleIndex: definition.moduleIndex,
211 children: children,
212 }
213 }
214 case None => NominalCapabilityProjection {
215 moduleIndex: moduleIndex,
216 children: children,
217 }
218 }
221export function containsByteBuffer(
222 state: CheckerState,
223 moduleIndex: int,
224 value: TypeValue,
225 seen: Array<string>,
226) -> bool {
227 let widened = widen(value)
228 if widened.kind == "byte-buffer" {
229 return true
230 }
231 if widened.kind == "function" {
232 return false
233 }
234 if widened.kind == "constructor" || widened.kind == "foreign" {
235 for argument in widened.arguments {
236 if containsByteBuffer(state, moduleIndex, argument, seen) {
237 return true
238 }
239 }
240 return false
241 }
242 if widened.kind == "record" {
243 for field in widened.fields {
244 if containsByteBuffer(state, moduleIndex, field, seen) {
245 return true
246 }
247 }
248 return false
249 }
250 if widened.kind == "union" {
251 for member in widened.members {
252 if containsByteBuffer(state, moduleIndex, member, seen) {
253 return true
254 }
255 }
256 return false
257 }
258 if nominalCapabilityType(widened) {
259 for argument in widened.arguments {
260 if containsByteBuffer(state, moduleIndex, argument, seen) {
261 return true
262 }
263 }
264 let key = nominalCapabilityKey(widened)
265 if containsString(seen, key) {
266 return false
267 }
268 let projection = nominalCapabilityProjection(state, moduleIndex, widened)
269 let nested = capabilityPath(seen, key)
270 for child in projection.children {
271 if containsByteBuffer(
272 state,
273 projection.moduleIndex,
274 child,
275 nested,
276 ) {
277 return true
278 }
279 }
280 return false
281 }
282 false
285export function comparableType(
286 state: CheckerState,
287 moduleIndex: int,
288 value: TypeValue,
289 seen: Array<string>,
290) -> bool {
291 let widened = widen(value)
292 if widened.kind == "template" || widened.kind == "file" ||
293 widened.kind == "json-value" || widened.kind == "toml-value" ||
294 widened.kind == "function" || widened.kind == "byte-buffer" ||
295 widened.kind == "regex" {
296 return false
297 }
298 if widened.kind == "constructor" {
299 if widened.name == "Map" || widened.name == "Set" {
300 return false
301 }
302 for argument in widened.arguments {
303 if !comparableType(state, moduleIndex, argument, seen) {
304 return false
305 }
306 }
307 return true
308 }
309 if widened.kind == "record" {
310 for field in widened.fields {
311 if !comparableType(state, moduleIndex, field, seen) {
312 return false
313 }
314 }
315 return true
316 }
317 if widened.kind == "union" {
318 for member in widened.members {
319 if !comparableType(state, moduleIndex, member, seen) {
320 return false
321 }
322 }
323 return true
324 }
325 if nominalCapabilityType(widened) {
326 let key = nominalCapabilityKey(widened)
327 if containsString(seen, key) {
328 return true
329 }
330 let projection = nominalCapabilityProjection(state, moduleIndex, widened)
331 let nested = capabilityPath(seen, key)
332 for child in projection.children {
333 if !comparableType(
334 state,
335 projection.moduleIndex,
336 child,
337 nested,
338 ) {
339 return false
340 }
341 }
342 return true
343 }
344 true
347function capabilityAnd(left: string, right: string) -> string {
348 if left == "reject" || right == "reject" {
349 "reject"
350 } else if left == "defer" || right == "defer" {
351 "defer"
352 } else {
353 "accept"
354 }
357export function orderCapability(
358 state: CheckerState,
359 moduleIndex: int,
360 value: TypeValue,
361 seen: Array<string>,
362) -> string {
363 let widened = widen(value)
364 if widened.kind == "primitive" {
365 return if widened.name == "int" || widened.name == "float" ||
366 widened.name == "string" {
367 "accept"
368 } else {
369 "reject"
370 }
371 }
372 if widened.kind == "literal" {
373 return if widened.name == "int" || widened.name == "float" ||
374 widened.name == "string" {
375 "accept"
376 } else {
377 "reject"
378 }
379 }
380 if widened.kind == "bytes" || widened.kind == "path" ||
381 widened.kind == "url" || widened.kind == "date" ||
382 widened.kind == "big-int" || widened.kind == "decimal" {
383 return "accept"
384 }
385 if widened.kind == "inference-variable" {
386 return "defer"
387 }
388 if nominalCapabilityType(widened) {
389 let key = nominalCapabilityKey(widened)
390 if containsString(seen, key) {
391 return "accept"
392 }
393 let mut status = "accept"
394 let projection = nominalCapabilityProjection(state, moduleIndex, widened)
395 let nested = capabilityPath(seen, key)
396 for child in projection.children {
397 status = capabilityAnd(status, orderCapability(
398 state,
399 projection.moduleIndex,
400 child,
401 nested,
402 ))
403 }
404 return status
405 }
406 "reject"
409export function jsonCapability(
410 state: CheckerState,
411 moduleIndex: int,
412 value: TypeValue,
413 seen: Array<string>,
414 decoding: bool,
415) -> string {
416 let widened = widen(value)
417 if widened.kind == "primitive" {
418 return if widened.name == "int" || widened.name == "bool" ||
419 widened.name == "string" || widened.name == "unit" {
420 "accept"
421 } else {
422 "reject"
423 }
424 }
425 if widened.kind == "literal" {
426 return if widened.name == "float" { "reject" } else { "accept" }
427 }
428 if widened.kind == "json-value" {
429 return "accept"
430 }
431 if widened.kind == "match" {
432 return if decoding { "reject" } else { "accept" }
433 }
434 if widened.kind == "inference-variable" {
435 return "defer"
436 }
437 if widened.kind == "constructor" {
438 if widened.name == "Option" || widened.name == "Array" {
439 return match widened.arguments.get(0) {
440 case Some(argument) => jsonCapability(
441 state,
442 moduleIndex,
443 argument,
444 seen,
445 decoding,
446 )
447 case None => "reject"
448 }
449 }
450 if widened.name == "Map" {
451 let key = match widened.arguments.get(0) {
452 case Some(argument) => {
453 let shown = widen(argument)
454 if (shown.kind == "primitive" || shown.kind == "literal") &&
455 shown.name == "string" {
456 "accept"
457 } else if shown.kind == "inference-variable" {
458 "defer"
459 } else {
460 "reject"
461 }
462 }
463 case None => "reject"
464 }
465 return capabilityAnd(key, match widened.arguments.get(1) {
466 case Some(argument) => jsonCapability(
467 state,
468 moduleIndex,
469 argument,
470 seen,
471 decoding,
472 )
473 case None => "reject"
474 })
475 }
476 return "reject"
477 }
478 if widened.kind == "record" {
479 let mut status = "accept"
480 for field in widened.fields {
481 status = capabilityAnd(status, jsonCapability(
482 state,
483 moduleIndex,
484 field,
485 seen,
486 decoding,
487 ))
488 }
489 return status
490 }
491 if nominalCapabilityType(widened) {
492 let key = nominalCapabilityKey(widened)
493 if containsString(seen, key) {
494 return if decoding { "reject" } else { "accept" }
495 }
496 let mut status = "accept"
497 let projection = nominalCapabilityProjection(state, moduleIndex, widened)
498 let nested = capabilityPath(seen, key)
499 for child in projection.children {
500 status = capabilityAnd(status, jsonCapability(
501 state,
502 projection.moduleIndex,
503 child,
504 nested,
505 decoding,
506 ))
507 }
508 return status
509 }
510 "reject"
513function nonKeyableType(
514 state: CheckerState,
515 moduleIndex: int,
516 value: TypeValue,
517 seen: Array<string>,
518) -> Option<KeyCapabilityFailure> {
519 let widened = widen(value)
520 if widened.kind == "byte-buffer" {
521 return Some(KeyCapabilityFailure {
522 subject: "ByteBuffer",
523 kind: "mutable byte buffer",
524 })
525 }
526 if widened.kind == "constructor" {
527 if widened.name == "Map" {
528 return Some(KeyCapabilityFailure {
529 subject: "`Map` value",
530 kind: "Map",
531 })
532 }
533 if widened.name == "Set" {
534 return Some(KeyCapabilityFailure {
535 subject: "`Set` value",
536 kind: "Set",
537 })
538 }
539 if widened.name == "Range" {
540 return Some(KeyCapabilityFailure {
541 subject: "`range` value",
542 kind: "range",
543 })
544 }
545 for argument in widened.arguments {
546 match nonKeyableType(state, moduleIndex, argument, seen) {
547 case Some(failure) => return Some(failure)
548 case None => ()
549 }
550 }
551 return None
552 }
553 if widened.kind == "function" {
554 return Some(KeyCapabilityFailure {
555 subject: "function value",
556 kind: "function",
557 })
558 }
559 let specialKind = match widened.kind {
560 case "template" => "template"
561 case "file" => "File"
562 case "json-value" => "JSONValue"
563 case "regex" => "Regex"
564 case "rounding-mode" => "RoundingMode"
565 case "match" => "Match"
566 case "toml-value" => "TOMLValue"
567 case _ => ""
568 }
569 if specialKind != "" {
570 return Some(KeyCapabilityFailure {
571 subject: if specialKind == "template" {
572 "template value"
573 } else {
574 "`{specialKind}` value"
575 },
576 kind: specialKind,
577 })
578 }
579 if widened.kind == "union" {
580 for member in widened.members {
581 match nonKeyableType(state, moduleIndex, member, seen) {
582 case Some(failure) => return Some(failure)
583 case None => ()
584 }
585 }
586 return None
587 }
588 if widened.kind == "record" {
589 for field in widened.fields {
590 match nonKeyableType(state, moduleIndex, field, seen) {
591 case Some(failure) => return Some(failure)
592 case None => ()
593 }
594 }
595 return None
596 }
597 if nominalCapabilityType(widened) {
598 let key = nominalCapabilityKey(widened)
599 if containsString(seen, key) {
600 return None
601 }
602 let projection = nominalCapabilityProjection(state, moduleIndex, widened)
603 let nested = capabilityPath(seen, key)
604 for child in projection.children {
605 match nonKeyableType(
606 state,
607 projection.moduleIndex,
608 child,
609 nested,
610 ) {
611 case Some(failure) => return Some(failure)
612 case None => ()
613 }
614 }
615 return None
616 }
617 None
620export function gateCollectionKey(
621 service: CheckerService,
622 state: CheckerState,
623 moduleIndex: int,
624 node: SyntaxNode,
625 value: TypeValue,
626) -> () {
627 match nonKeyableType(state, moduleIndex, value, []) {
628 case Some(failure) => addDiagnostic(
629 state,
630 moduleIndex,
631 "TPZ5007",
632 "{failure.subject} is not a valid Map/Set key ({failure.kind} keys are not supported yet)",
633 "",
634 node,
635 )
636 case None => ()
637 }
638 ()
641function declaredMemberType(
642 state: CheckerState,
643 moduleIndex: int,
644 object: TypeValue,
645 name: string,
646) -> Option<TypeValue> {
647 match recordDefinitionForType(state, moduleIndex, object) {
648 case Some(definition) => for field in definition.fields {
649 if field.name == name {
650 return Some(substitute(
651 field.typeValue,
652 definition.typeParameters,
653 object.arguments,
654 ))
655 }
656 }
657 case None => ()
658 }
659 match enumDefinitionForType(state, moduleIndex, object) {
660 case Some(definition) => for variant in definition.variants {
661 if variant.name == name {
662 if variant.payloads.length == 0 {
663 return Some(object)
664 }
665 let mut payloads: Array<TypeValue> = []
666 for payload in variant.payloads {
667 payloads.push(substitute(
668 payload,
669 definition.typeParameters,
670 object.arguments,
671 ))
672 }
673 return Some(functionType(payloads, [], object))
674 }
675 }
676 case None => ()
677 }
678 match newtypeDefinitionForType(state, moduleIndex, object) {
679 case Some(definition) => if name == "value" {
680 return Some(functionType([], [], substitute(
681 definition.base,
682 definition.typeParameters,
683 object.arguments,
684 )))
685 }
686 case None => ()
687 }
688 if object.kind == "record" {
689 let mut index = 0
690 for fieldName in object.fieldNames {
691 if fieldName == name {
692 return Some(match object.fields.get(index) {
693 case Some(found) => found
694 case None => emptyType("unknown")
695 })
696 }
697 index += 1
698 }
699 }
700 None
703export function typeArgument(object: TypeValue, index: int) -> TypeValue {
704 match object.arguments.get(index) {
705 case Some(found) => found
706 case None => emptyType("unknown")
707 }
710function optionMemberType(object: TypeValue, name: string) -> TypeValue {
711 let value = typeArgument(object, 0)
712 let output = rigid("U", "builtin::Option.{name}")
713 match name {
714 case "okOr" => functionType(
715 [output],
716 [],
717 constructor("Result", [value, output]),
718 )
719 case "okOrElse" => functionType(
720 [functionType([], [], output)],
721 [],
722 constructor("Result", [value, output]),
723 )
724 case "map" => functionType(
725 [functionType([value], [], output)],
726 [],
727 constructor("Option", [output]),
728 )
729 case "flatMap" => functionType(
730 [functionType([value], [], constructor("Option", [output]))],
731 [],
732 constructor("Option", [output]),
733 )
734 case _ => emptyType("unknown")
735 }
738function resultMemberType(object: TypeValue, name: string) -> TypeValue {
739 let value = typeArgument(object, 0)
740 let error = typeArgument(object, 1)
741 let output = rigid("U", "builtin::Result.{name}")
742 match name {
743 case "map" => functionType(
744 [functionType([value], [], output)],
745 [],
746 constructor("Result", [output, error]),
747 )
748 case "flatMap" => functionType(
749 [functionType(
750 [value],
751 [],
752 constructor("Result", [output, error]),
753 )],
754 [],
755 constructor("Result", [output, error]),
756 )
757 case _ => emptyType("unknown")
758 }
761function arrayMemberType(object: TypeValue, name: string) -> TypeValue {
762 let element = iterableElement(object)
763 match name {
764 case "length" => primitive("int")
765 case "get" => functionType(
766 [primitive("int")],
767 [],
768 constructor("Option", [element]),
769 )
770 case "slice" => functionType(
771 [primitive("int"), primitive("int")],
772 [],
773 object,
774 )
775 case "map" => {
776 let output = rigid("U", "builtin::Array.map")
777 functionType(
778 [functionType([element], [], output)],
779 [],
780 constructor("Array", [output]),
781 )
782 }
783 case "join" => functionType([primitive("string")], [], primitive("string"))
784 case "sorted" => functionType([], [], object)
785 case "sortedBy" => {
786 let key = rigid("K", "builtin::Array.sortedBy")
787 functionType([functionType([element], [], key)], [], object)
788 }
789 case "filter" => functionType(
790 [functionType([element], [], primitive("bool"))],
791 [],
792 object,
793 )
794 case "reduce" => {
795 let output = rigid("U", "builtin::Array.reduce")
796 functionType(
797 [output, functionType([output, element], [], output)],
798 [],
799 output,
800 )
801 }
802 case "indexOf" => functionType(
803 [element],
804 [],
805 constructor("Option", [primitive("int")]),
806 )
807 case "push" => functionType([element], [], primitive("unit"))
808 case "pop" => functionType([], [], constructor("Option", [element]))
809 case "clear" | "reverse" | "sort" =>
810 functionType([], [], primitive("unit"))
811 case "sortBy" => {
812 let key = rigid("K", "builtin::Array.sortBy")
813 functionType(
814 [functionType([element], [], key)],
815 [],
816 primitive("unit"),
817 )
818 }
819 case "retain" => functionType(
820 [functionType([element], [], primitive("bool"))],
821 [],
822 primitive("unit"),
823 )
824 case "insert" => functionType(
825 [primitive("int"), element],
826 [],
827 primitive("unit"),
828 )
829 case "removeAt" => functionType(
830 [primitive("int")],
831 [],
832 constructor("Option", [element]),
833 )
834 case _ => emptyType("unknown")
835 }
838function setMemberType(object: TypeValue, name: string) -> TypeValue {
839 let element = iterableElement(object)
840 match name {
841 case "length" => primitive("int")
842 case "toArray" => functionType([], [], constructor("Array", [element]))
843 case "contains" => functionType([element], [], primitive("bool"))
844 case "add" => functionType([element], [], primitive("unit"))
845 case "remove" => functionType([element], [], primitive("bool"))
846 case "isEmpty" => functionType([], [], primitive("bool"))
847 case "union" | "intersection" | "difference" =>
848 functionType([object], [], object)
849 case "clear" => functionType([], [], primitive("unit"))
850 case _ => emptyType("unknown")
851 }
854function mapMemberType(object: TypeValue, name: string) -> TypeValue {
855 let key = typeArgument(object, 0)
856 let item = typeArgument(object, 1)
857 match name {
858 case "length" => primitive("int")
859 case "keys" => constructor("Array", [key])
860 case "values" => constructor("Array", [item])
861 case "entries" => constructor("Array", [structural(
862 ["key", "value"],
863 [key, item],
864 )])
865 case "get" => functionType([key], [], constructor("Option", [item]))
866 case "getOr" => functionType([key, item], [], item)
867 case "containsKey" => functionType([key], [], primitive("bool"))
868 case "insert" => functionType([key, item], [], primitive("unit"))
869 case "remove" => functionType([key], [], constructor("Option", [item]))
870 case "isEmpty" => functionType([], [], primitive("bool"))
871 case "clear" => functionType([], [], primitive("unit"))
872 case "update" => functionType(
873 [key, item, functionType([item], [], item)],
874 [],
875 primitive("unit"),
876 )
877 case "mapValues" => {
878 let output = rigid("W", "builtin::Map.mapValues")
879 functionType(
880 [functionType([item], [], output)],
881 [],
882 constructor("Map", [key, output]),
883 )
884 }
885 case "filter" => functionType(
886 [functionType([key, item], [], primitive("bool"))],
887 [],
888 object,
889 )
890 case _ => emptyType("unknown")
891 }
894function stringMemberType(name: string) -> TypeValue {
895 match name {
896 case "byteLength" => functionType([], [], primitive("int"))
897 case "trim" | "trimStart" | "trimEnd" =>
898 functionType([], [], primitive("string"))
899 case "contains" | "startsWith" | "endsWith" =>
900 functionType([primitive("string")], [], primitive("bool"))
901 case "replace" => functionType(
902 [primitive("string"), primitive("string")],
903 [],
904 primitive("string"),
905 )
906 case "indexOf" | "lastIndexOf" => functionType(
907 [primitive("string")],
908 [],
909 constructor("Option", [primitive("int")]),
910 )
911 case "split" => functionType(
912 [primitive("string")],
913 [],
914 constructor("Array", [primitive("string")]),
915 )
916 case "slice" => functionType(
917 [primitive("int"), primitive("int")],
918 [],
919 primitive("string"),
920 )
921 case "codePointAt" => functionType(
922 [primitive("int")],
923 [],
924 constructor("Option", [primitive("int")]),
925 )
926 case "scalars" => functionType(
927 [],
928 [],
929 constructor("Array", [primitive("string")]),
930 )
931 case _ => emptyType("unknown")
932 }
935function bytesMemberType(name: string) -> TypeValue {
936 match name {
937 case "length" => functionType([], [], primitive("int"))
938 case "isEmpty" => functionType([], [], primitive("bool"))
939 case "get" => functionType(
940 [primitive("int")],
941 [],
942 constructor("Option", [primitive("int")]),
943 )
944 case "slice" => functionType(
945 [primitive("int"), primitive("int")],
946 [],
947 emptyType("bytes"),
948 )
949 case "decodeUtf8" => functionType(
950 [],
951 [],
952 constructor("Result", [primitive("string"), primitive("string")]),
953 )
954 case "toArray" => functionType(
955 [],
956 [],
957 constructor("Array", [primitive("int")]),
958 )
959 case "toHex" | "toBase64" => functionType([], [], primitive("string"))
960 case _ => emptyType("unknown")
961 }
964function byteBufferMemberType(name: string) -> TypeValue {
965 match name {
966 case "length" => functionType([], [], primitive("int"))
967 case "get" => functionType([primitive("int")], [], primitive("int"))
968 case "set" => functionType(
969 [primitive("int"), primitive("int")],
970 [],
971 primitive("unit"),
972 )
973 case "fill" => functionType(
974 [primitive("int"), primitive("int"), primitive("int")],
975 [],
976 primitive("unit"),
977 )
978 case "copy" => functionType(
979 [
980 emptyType("byte-buffer"),
981 primitive("int"),
982 primitive("int"),
983 primitive("int"),
984 ],
985 [],
986 primitive("unit"),
987 )
988 case "toBytes" => functionType([], [], emptyType("bytes"))
989 case _ => emptyType("unknown")
990 }
993function fileMemberType(name: string) -> TypeValue {
994 match name {
995 case "read" => functionType(
996 [],
997 [],
998 constructor("Result", [primitive("string"), primitive("string")]),
999 )
1000 case "write" => functionType(

SHA256 9fba93e664b71aa80f1f016d13ac92225fa35e8ed226404ea798e79312370489