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

Topaz · 23553 B · Original file

1import types {
2 PreviewAstNode,
3 PreviewCheckDiagnostic,
4 PreviewModuleResult,
5 PreviewResolvedReference,
6 PreviewToken,
7 PreviewTypeAtom,
8 PreviewTypedCall,
9 PreviewTypedCapture,
10 PreviewTypedNode,
13record ProfileSpan {
14 lo: int,
15 hi: int,
18record ProfileDenial {
19 rule: string,
20 message: string,
23function moduleText(source: Bytes, lo: int, hi: int) -> string {
24 match source.slice(lo, hi).decodeUtf8() {
25 case Ok(value) => value
26 case Err(_) => ""
27 }
30function sameFinding(
31 left: PreviewCheckDiagnostic,
32 right: PreviewCheckDiagnostic,
33) -> bool {
34 left.moduleIndex == right.moduleIndex &&
35 left.lo == right.lo &&
36 left.hi == right.hi &&
37 left.code == right.code &&
38 left.message == right.message &&
39 left.profileRule == right.profileRule
42function before(
43 left: PreviewCheckDiagnostic,
44 right: PreviewCheckDiagnostic,
45) -> bool {
46 left.moduleIndex < right.moduleIndex ||
47 (left.moduleIndex == right.moduleIndex && left.lo < right.lo) ||
48 (left.moduleIndex == right.moduleIndex && left.lo == right.lo &&
49 left.hi < right.hi) ||
50 (left.moduleIndex == right.moduleIndex && left.lo == right.lo &&
51 left.hi == right.hi && left.profileRule < right.profileRule) ||
52 (left.moduleIndex == right.moduleIndex && left.lo == right.lo &&
53 left.hi == right.hi && left.profileRule == right.profileRule &&
54 left.message < right.message)
57function insertFinding(
58 output: Array<PreviewCheckDiagnostic>,
59 finding: PreviewCheckDiagnostic,
60) -> () {
61 let mut target = output
62 let mut index = 0
63 while index < target.length {
64 let existing = target[index]
65 if sameFinding(existing, finding) {
66 return ()
67 }
68 if before(finding, existing) {
69 target.insert(index, finding)
70 return ()
71 }
72 index += 1
73 }
74 target.push(finding)
75 ()
78function insertTypedFinding(
79 output: Array<PreviewCheckDiagnostic>,
80 finding: PreviewCheckDiagnostic,
81) -> () {
82 let mut target = output
83 let mut index = 0
84 while index < target.length {
85 let existing = target[index]
86 if existing.moduleIndex == finding.moduleIndex &&
87 existing.lo == finding.lo &&
88 existing.hi == finding.hi {
89 return ()
90 }
91 if before(finding, existing) {
92 target.insert(index, finding)
93 return ()
94 }
95 index += 1
96 }
97 target.push(finding)
98 ()
101function finding(
102 moduleIndex: int,
103 lo: int,
104 hi: int,
105 rule: string,
106 message: string,
107 primaryMessage: string,
108 notes: Array<string>,
109) -> PreviewCheckDiagnostic {
110 PreviewCheckDiagnostic {
111 moduleIndex: moduleIndex,
112 code: "TPZ5801",
113 message: message,
114 primaryMessage: primaryMessage,
115 lo: lo,
116 hi: hi,
117 secondary: [],
118 notes: notes,
119 profileRule: rule,
120 }
123function sourceFinding(
124 moduleIndex: int,
125 lo: int,
126 hi: int,
127 rule: string,
128 message: string,
129) -> PreviewCheckDiagnostic {
130 finding(
131 moduleIndex,
132 lo,
133 hi,
134 rule,
135 message,
136 "not in the deterministic compiler-kernel inventory",
137 [
138 "profile rule: {rule}",
139 "move this effect to the Rust host shell or use a deterministic admitted value/library leaf",
140 ],
141 )
144function typedFinding(
145 moduleIndex: int,
146 lo: int,
147 hi: int,
148 rule: string,
149 message: string,
150) -> PreviewCheckDiagnostic {
151 finding(
152 moduleIndex,
153 lo,
154 hi,
155 rule,
156 message,
157 "Bootstrap Profile package boundary",
158 ["profile rule: {rule}"],
159 )
162record DirectChildIndexes {
163 byParent: Map<int, Map<string, int>>,
166record ProfileSpanIndexes {
167 byModule: Map<int, Map<int, Map<int, int>>>,
170function directChildIndexes(
171 nodes: Array<PreviewAstNode>,
172) -> DirectChildIndexes {
173 let mut byParent: Map<int, Map<string, int>> = Map.new()
174 let mut index = 0
175 for node in nodes {
176 match byParent.get(node.parent) {
177 case Some(found) => {
178 let mut byField = found
179 match byField.get(node.field) {
180 case Some(_) => ()
181 case None => byField.insert(node.field, index)
182 }
183 }
184 case None => {
185 let mut byField: Map<string, int> = Map.new()
186 byField.insert(node.field, index)
187 byParent.insert(node.parent, byField)
188 }
189 }
190 index += 1
191 }
192 DirectChildIndexes { byParent: byParent }
195function directChildIndex(
196 indexes: DirectChildIndexes,
197 parent: int,
198 field: string,
199) -> Option<int> {
200 match indexes.byParent.get(parent) {
201 case Some(byField) => byField.get(field)
202 case None => None
203 }
206function directChild(
207 nodes: Array<PreviewAstNode>,
208 indexes: DirectChildIndexes,
209 parent: int,
210 field: string,
211) -> Option<PreviewAstNode> {
212 match directChildIndex(indexes, parent, field) {
213 case Some(index) => Some(nodes[index])
214 case None => None
215 }
218function insertProfileSpanIndex(
219 indexes: ProfileSpanIndexes,
220 moduleIndex: int,
221 lo: int,
222 hi: int,
223 index: int,
224) -> () {
225 let mut byModule = indexes.byModule
226 let mut byLo = match byModule.get(moduleIndex) {
227 case Some(found) => found
228 case None => {
229 let value: Map<int, Map<int, int>> = Map.new()
230 byModule.insert(moduleIndex, value)
231 value
232 }
233 }
234 let mut byHi = match byLo.get(lo) {
235 case Some(found) => found
236 case None => {
237 let value: Map<int, int> = Map.new()
238 byLo.insert(lo, value)
239 value
240 }
241 }
242 match byHi.get(hi) {
243 case Some(_) => ()
244 case None => byHi.insert(hi, index)
245 }
248function profileSpanIndex(
249 indexes: ProfileSpanIndexes,
250 moduleIndex: int,
251 lo: int,
252 hi: int,
253) -> Option<int> {
254 match indexes.byModule.get(moduleIndex) {
255 case Some(byLo) => match byLo.get(lo) {
256 case Some(byHi) => byHi.get(hi)
257 case None => None
258 }
259 case None => None
260 }
263function memberReference(
264 catalog: ProfileReferenceCatalog,
265 moduleIndex: int,
266 lo: int,
267 hi: int,
268) -> Option<PreviewResolvedReference> {
269 match profileSpanIndex(catalog.memberReferences, moduleIndex, lo, hi) {
270 case Some(index) => Some(catalog.references[index])
271 case None => None
272 }
275function memberIdentity(
276 reference: Option<PreviewResolvedReference>,
277 objectName: string,
278 fieldName: string,
279) -> string {
280 match reference {
281 case Some(found) => {
282 let reference = found
283 let targetName = if reference.targetName == "" {
284 fieldName
285 } else {
286 reference.targetName
287 }
288 "{reference.targetModule}::{targetName}"
289 }
290 case None => "{objectName}::{fieldName}"
291 }
294function composeSpan(
295 module: PreviewModuleResult,
296 childIndexes: DirectChildIndexes,
297 node: PreviewAstNode,
298 ordinal: int,
299) -> ProfileSpan {
300 match [
301 directChild(module.ast, childIndexes, ordinal, "left"),
302 directChild(module.ast, childIndexes, ordinal, "right"),
303 ] {
304 case [Some(left), Some(right)] => for token in module.raw {
305 if token.kind == "gt-gt" &&
306 token.lo >= left.hi &&
307 token.hi <= right.lo {
308 return ProfileSpan { lo: token.lo, hi: token.hi }
309 }
310 }
311 case _ => ()
312 }
313 ProfileSpan { lo: node.lo, hi: node.hi }
316function identityHasHead(identity: string, head: string) -> bool {
317 identity == head ||
318 identity.startsWith("{head}.") ||
319 identity.startsWith("{head}::")
322function deniedModule(identity: string) -> bool {
323 identityHasHead(identity, "std.fs") ||
324 identityHasHead(identity, "std.io") ||
325 identityHasHead(identity, "std.path") ||
326 identityHasHead(identity, "std.cli") ||
327 identityHasHead(identity, "std.test") ||
328 identityHasHead(identity, "std.regex") ||
329 identityHasHead(identity, "std.codec") ||
330 identityHasHead(identity, "std.crypto") ||
331 identityHasHead(identity, "std.time") ||
332 identityHasHead(identity, "std.random") ||
333 identityHasHead(identity, "std.process") ||
334 identityHasHead(identity, "std.database")
337function deniedLeaf(identity: string) -> bool {
338 deniedModule(identity) ||
339 identityHasHead(identity, "FS") ||
340 identityHasHead(identity, "Cli") ||
341 identityHasHead(identity, "Path") ||
342 identityHasHead(identity, "HTTP") ||
343 identityHasHead(identity, "DOM") ||
344 identityHasHead(identity, "Test") ||
345 identityHasHead(identity, "Regex") ||
346 identityHasHead(identity, "Date") ||
347 identityHasHead(identity, "Math") ||
348 identityHasHead(identity, "HMAC") ||
349 identityHasHead(identity, "Base64") ||
350 identityHasHead(identity, "Deflate") ||
351 identityHasHead(identity, "Zlib") ||
352 identityHasHead(identity, "ReedSolomon")
355function testFrameworkIdentity(identity: string) -> bool {
356 identityHasHead(identity, "std.test") || identityHasHead(identity, "Test")
359function testMember(name: string) -> bool {
360 name == "assert" ||
361 name == "assertEq" ||
362 name == "assertNe" ||
363 name == "assertContains" ||
364 name == "assertOk" ||
365 name == "assertErr" ||
366 name == "assertSome" ||
367 name == "assertNone" ||
368 name == "assertGolden"
371function typeDenial(atoms: Array<PreviewTypeAtom>) -> Option<ProfileDenial> {
372 for atom in atoms {
373 if (atom.kind == "primitive" || atom.kind == "literal") &&
374 atom.name == "float" {
375 return Some(ProfileDenial {
376 rule: "bootstrap/no-float",
377 message: "`float` is not available to the deterministic Bootstrap Profile",
378 })
379 }
380 if atom.kind == "file" || atom.kind == "path" {
381 return Some(ProfileDenial {
382 rule: "bootstrap/no-resource",
383 message: "host file and path values are not available to the Bootstrap Profile",
384 })
385 }
386 if atom.kind == "regex" ||
387 atom.kind == "match" ||
388 atom.kind == "toml-value" ||
389 atom.kind == "url" ||
390 atom.kind == "date" ||
391 atom.kind == "big-int" ||
392 atom.kind == "decimal" ||
393 atom.kind == "rounding-mode" {
394 return Some(ProfileDenial {
395 rule: "bootstrap/no-host-leaf",
396 message: "this runtime value family is outside the Bootstrap Profile inventory",
397 })
398 }
399 }
400 None
403function appendTypeFinding(
404 output: Array<PreviewCheckDiagnostic>,
405 moduleIndex: int,
406 lo: int,
407 hi: int,
408 atoms: Array<PreviewTypeAtom>,
409) -> () {
410 match typeDenial(atoms) {
411 case Some(value) => insertTypedFinding(
412 output,
413 typedFinding(moduleIndex, lo, hi, value.rule, value.message),
414 )
415 case None => ()
416 }
419function appendCallTypeFinding(
420 output: Array<PreviewCheckDiagnostic>,
421 call: PreviewTypedCall,
422) -> () {
423 match typeDenial(call.calleeType) {
424 case Some(value) => insertTypedFinding(
425 output,
426 typedFinding(
427 call.moduleIndex,
428 call.lo,
429 call.hi,
430 value.rule,
431 value.message,
432 ),
433 )
434 case None => match typeDenial(call.resultType) {
435 case Some(value) => insertTypedFinding(
436 output,
437 typedFinding(
438 call.moduleIndex,
439 call.lo,
440 call.hi,
441 value.rule,
442 value.message,
443 ),
444 )
445 case None => ()
446 }
447 }
450function appendTestFramework(
451 output: Array<PreviewCheckDiagnostic>,
452 profile: string,
453 moduleIndex: int,
454 lo: int,
455 hi: int,
456 label: string,
457) -> () {
458 let rule = if profile == "agent-pack" {
459 "agent-pack/no-test-framework"
460 } else if profile == "test-profile" {
461 "test-profile/no-test-framework"
462 } else {
463 "bootstrap/no-test-framework"
464 }
465 insertFinding(
466 output,
467 finding(
468 moduleIndex,
469 lo,
470 hi,
471 rule,
472 "test-framework APIs are not allowed by profile `{profile}`",
473 label,
474 [
475 "profile rule: {rule}",
476 "the executable test-profile grants only the canonical free `assert(...)` function",
477 ],
478 ),
479 )
482record ProfileReferenceCatalog {
483 references: Array<PreviewResolvedReference>,
484 resolvedTargets: ProfileSpanIndexes,
485 memberReferences: ProfileSpanIndexes,
488record ProfileModuleContext {
489 profile: string,
490 moduleIndex: int,
491 module: PreviewModuleResult,
492 source: Bytes,
493 referenceCatalog: ProfileReferenceCatalog,
494 childIndexes: DirectChildIndexes,
497function profileReferenceCatalog(
498 references: Array<PreviewResolvedReference>,
499) -> ProfileReferenceCatalog {
500 let resolvedTargets = ProfileSpanIndexes { byModule: Map.new() }
501 let memberReferences = ProfileSpanIndexes { byModule: Map.new() }
502 let mut referenceIndex = 0
503 for reference in references {
504 if reference.targetModuleIndex >= 0 {
505 insertProfileSpanIndex(
506 resolvedTargets,
507 reference.moduleIndex,
508 reference.lo,
509 reference.hi,
510 referenceIndex,
511 )
512 }
513 if reference.targetModule != "" {
514 insertProfileSpanIndex(
515 memberReferences,
516 reference.moduleIndex,
517 reference.lo,
518 reference.hi,
519 referenceIndex,
520 )
521 }
522 referenceIndex += 1
523 }
524 ProfileReferenceCatalog {
525 references: references,
526 resolvedTargets: resolvedTargets,
527 memberReferences: memberReferences,
528 }
531function appendCompositionFinding(
532 output: Array<PreviewCheckDiagnostic>,
533 context: ProfileModuleContext,
534 node: PreviewAstNode,
535 ordinal: int,
536) -> () {
537 if node.kind != "expression/compose" ||
538 (context.profile != "agent-pack" && context.profile != "test-profile") {
539 return ()
540 }
541 let span = composeSpan(context.module, context.childIndexes, node, ordinal)
542 let rule = "{context.profile}/no-composition"
543 insertFinding(
544 output,
545 finding(
546 context.moduleIndex,
547 span.lo,
548 span.hi,
549 rule,
550 "function composition is not allowed by profile `{context.profile}`",
551 "profile-disallowed `>>`",
552 [
553 "profile rule: {rule}",
554 "use an explicit lambda, or a pipeline only when it preserves the intended semantics",
555 ],
556 ),
557 )
560function appendIdentifierFinding(
561 output: Array<PreviewCheckDiagnostic>,
562 context: ProfileModuleContext,
563 node: PreviewAstNode,
564) -> () {
565 if node.kind != "expression/identifier" {
566 return ()
567 }
568 let name = moduleText(context.source, node.lo, node.hi)
569 let unresolved = profileSpanIndex(
570 context.referenceCatalog.resolvedTargets,
571 context.moduleIndex,
572 node.lo,
573 node.hi,
574 ) == None
575 if context.profile == "bootstrap" && unresolved &&
576 (name == "print" || name == "input" || name == "open" || name == "assert") {
577 insertFinding(
578 output,
579 sourceFinding(
580 context.moduleIndex,
581 node.lo,
582 node.hi,
583 "bootstrap/no-host-leaf",
584 "runtime leaf `{name}` is not available to the Bootstrap Profile",
585 ),
586 )
587 } else if context.profile == "agent-pack" && unresolved && name == "assert" {
588 insertFinding(
589 output,
590 finding(
591 context.moduleIndex,
592 node.lo,
593 node.hi,
594 "agent-pack/no-assert",
595 "`assert` is not allowed by profile `agent-pack`",
596 "test-only function reference",
597 [
598 "profile rule: agent-pack/no-assert",
599 "use `--profile test-profile` only for test code, or express the failure with canonical Result/control flow",
600 ],
601 ),
602 )
603 }
606function bootstrapSyntaxDenial(kind: string) -> Option<ProfileDenial> {
607 if kind == "expression/float" {
608 Some(ProfileDenial {
609 rule: "bootstrap/no-float",
610 message: "`float` is not available to the deterministic Bootstrap Profile",
611 })
612 } else if kind == "expression/duration" {
613 Some(ProfileDenial {
614 rule: "bootstrap/no-duration",
615 message: "duration values are not available to the deterministic Bootstrap Profile",
616 })
617 } else if kind == "expression/concurrent" {
618 Some(ProfileDenial {
619 rule: "bootstrap/no-concurrency",
620 message: "`concurrent` is not available to the deterministic Bootstrap Profile",
621 })
622 } else if kind == "statement/using" {
623 Some(ProfileDenial {
624 rule: "bootstrap/no-resource",
625 message: "`using` and host resource values are not available to the Bootstrap Profile",
626 })
627 } else {
628 None
629 }
632function appendBootstrapSyntaxFinding(
633 output: Array<PreviewCheckDiagnostic>,
634 context: ProfileModuleContext,
635 node: PreviewAstNode,
636) -> () {
637 if context.profile != "bootstrap" {
638 return ()
639 }
640 match bootstrapSyntaxDenial(node.kind) {
641 case Some(denial) => insertFinding(
642 output,
643 sourceFinding(
644 context.moduleIndex,
645 node.lo,
646 node.hi,
647 denial.rule,
648 denial.message,
649 ),
650 )
651 case None => ()
652 }
655function appendImportFinding(
656 output: Array<PreviewCheckDiagnostic>,
657 context: ProfileModuleContext,
658 node: PreviewAstNode,
659 ordinal: int,
660) -> () {
661 if node.kind != "statement/import" {
662 return ()
663 }
664 // The parser nests the module path under the statement's `import-item`.
665 let item = match directChildIndex(context.childIndexes, ordinal, "import") {
666 case Some(index) => index
667 case None => return ()
668 }
669 let pathIndex = match directChildIndex(context.childIndexes, item, "path") {
670 case Some(index) => index
671 case None => return ()
672 }
673 let path = context.module.ast[pathIndex]
674 let identity = modulePathIdentity(context, pathIndex)
675 if context.profile == "bootstrap" && deniedModule(identity) {
676 insertFinding(
677 output,
678 sourceFinding(
679 context.moduleIndex,
680 path.lo,
681 path.hi,
682 "bootstrap/no-host-module",
683 "module `{identity}` is not available to the Bootstrap Profile",
684 ),
685 )
686 }
687 if identity == "std.test" {
688 appendTestFramework(
689 output,
690 context.profile,
691 context.moduleIndex,
692 path.lo,
693 path.hi,
694 "test-only `std.test` import",
695 )
696 }
699// Joins the path segments, which directly follow their module path in the
700// flattened tree, so spacing or comments between segments keep one identity.
701function modulePathIdentity(context: ProfileModuleContext, path: int) -> string {
702 let mut segments: Array<string> = []
703 let mut index = path + 1
704 while index < context.module.ast.length {
705 let segment = context.module.ast[index]
706 if segment.parent != path {
707 break
708 }
709 segments.push(moduleText(context.source, segment.lo, segment.hi))
710 index += 1
711 }
712 segments.join(".")
715function appendMemberFinding(
716 output: Array<PreviewCheckDiagnostic>,
717 context: ProfileModuleContext,
718 node: PreviewAstNode,
719 ordinal: int,
720) -> () {
721 if node.kind != "expression/member" && node.kind != "expression/optional-access" {
722 return ()
723 }
724 match [
725 directChild(context.module.ast, context.childIndexes, ordinal, "object"),
726 directChild(context.module.ast, context.childIndexes, ordinal, "field"),
727 ] {
728 case [Some(object), Some(field)] => if object.kind == "expression/identifier" {
729 let objectName = moduleText(context.source, object.lo, object.hi)
730 let fieldName = moduleText(context.source, field.lo, field.hi)
731 let objectResolved = profileSpanIndex(
732 context.referenceCatalog.resolvedTargets,
733 context.moduleIndex,
734 object.lo,
735 object.hi,
736 ) != None
737 let resolvedMember = memberReference(
738 context.referenceCatalog,
739 context.moduleIndex,
740 field.lo,
741 field.hi,
742 )
743 let memberResolved = match resolvedMember {
744 case Some(_) => true
745 case None => false
746 }
747 let identity = memberIdentity(
748 resolvedMember,
749 objectName,
750 fieldName,
751 )
752 if context.profile == "bootstrap" &&
753 (memberResolved || !objectResolved) && deniedLeaf(identity) {
754 insertFinding(
755 output,
756 sourceFinding(
757 context.moduleIndex,
758 node.lo,
759 node.hi,
760 "bootstrap/no-host-leaf",
761 "runtime leaf `{identity}` is not available to the Bootstrap Profile",
762 ),
763 )
764 }
765 let testNamespace = if memberResolved {
766 testFrameworkIdentity(identity)
767 } else {
768 !objectResolved && objectName == "Test"
769 }
770 if testNamespace && testMember(fieldName) {
771 appendTestFramework(
772 output,
773 context.profile,
774 context.moduleIndex,
775 node.lo,
776 node.hi,
777 "test-only `Test.*` namespace member",
778 )
779 }
780 }
781 case _ => ()
782 }
785function appendSourceNodeFindings(
786 output: Array<PreviewCheckDiagnostic>,
787 context: ProfileModuleContext,
788 node: PreviewAstNode,
789 ordinal: int,
790) -> () {
791 appendCompositionFinding(output, context, node, ordinal)
792 appendIdentifierFinding(output, context, node)
793 appendBootstrapSyntaxFinding(output, context, node)
794 appendImportFinding(output, context, node, ordinal)
795 appendMemberFinding(output, context, node, ordinal)
798function appendSourceFindings(
799 output: Array<PreviewCheckDiagnostic>,
800 profile: string,
801 modules: Array<PreviewModuleResult>,
802 referenceCatalog: ProfileReferenceCatalog,
803) -> () {
804 let mut moduleIndex = 0
805 for module in modules {
806 if module.identity != "std" && !module.identity.startsWith("std.") {
807 let context = ProfileModuleContext {
808 profile: profile,
809 moduleIndex: moduleIndex,
810 module: module,
811 source: Bytes.encodeUtf8(module.source),
812 referenceCatalog: referenceCatalog,
813 childIndexes: directChildIndexes(module.ast),
814 }
815 let mut ordinal = 0
816 for node in module.ast {
817 appendSourceNodeFindings(output, context, node, ordinal)
818 ordinal += 1
819 }
820 }
821 moduleIndex += 1
822 }
823 ()
826function appendBootstrapTypedFindings(
827 output: Array<PreviewCheckDiagnostic>,
828 typedNodes: Array<PreviewTypedNode>,
829 typedCalls: Array<PreviewTypedCall>,
830 typedCaptures: Array<PreviewTypedCapture>,
831) -> () {
832 let mut typedOutput: Array<PreviewCheckDiagnostic> = []
833 for node in typedNodes {
834 if node.ambient {
835 insertTypedFinding(
836 typedOutput,
837 typedFinding(
838 node.moduleIndex,
839 node.lo,
840 node.hi,
841 "bootstrap/no-ambient-type",
842 "the compiler kernel may not retain an ambient or unexplained type",
843 ),
844 )
845 }
846 }
847 for call in typedCalls {
848 if call.ambient {
849 insertTypedFinding(
850 typedOutput,
851 typedFinding(
852 call.moduleIndex,
853 call.lo,
854 call.hi,
855 "bootstrap/no-ambient-type",
856 "the compiler kernel may not retain an unexplained callable or result type",
857 ),
858 )
859 }
860 }
861 for node in typedNodes {
862 appendTypeFinding(typedOutput, node.moduleIndex, node.lo, node.hi, node.typeValue)
863 }
864 for call in typedCalls {
865 appendCallTypeFinding(typedOutput, call)
866 }
867 for capture in typedCaptures {
868 appendTypeFinding(
869 typedOutput,
870 capture.moduleIndex,
871 capture.referenceLo,
872 capture.referenceHi,
873 capture.typeValue,
874 )
875 }
876 for found in typedOutput {
877 insertFinding(output, found)
878 }
879 ()
882export function checkProfile(
883 profile: string,
884 modules: Array<PreviewModuleResult>,
885 references: Array<PreviewResolvedReference>,
886 typedNodes: Array<PreviewTypedNode>,
887 typedCalls: Array<PreviewTypedCall>,
888 typedCaptures: Array<PreviewTypedCapture>,
889) -> Result<Array<PreviewCheckDiagnostic>, string> {
890 if profile == "" {
891 return Ok([])
892 }
893 if profile != "agent-pack" &&
894 profile != "test-profile" &&
895 profile != "bootstrap" {
896 return Err("unsupported compiler profile `{profile}`")
897 }
898 let mut output: Array<PreviewCheckDiagnostic> = []
899 let referenceCatalog = profileReferenceCatalog(references)
900 appendSourceFindings(output, profile, modules, referenceCatalog)
901 if profile == "bootstrap" {
902 appendBootstrapTypedFindings(output, typedNodes, typedCalls, typedCaptures)
903 }
904 Ok(output)

SHA256 4f5bc0cdb1e60b03e838db64fde4e0758d185e88638353984c00cfbfec698bd9