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/resolver/graph.tpz

Topaz · 24608 B · Original file

1// Entry admission, module loading, dependency order, and cycle diagnosis.
2// Host queries are derived from explicit facts; scope tables and initializer
3// validation are left to sibling resolver leaves.
5import layout { normalize }
6import parser { parse }
7import raw { lex }
8import types {
9 PreviewGeneratedStdModule,
10 PreviewHostQuery,
11 PreviewImportEdge,
12 PreviewModuleResult,
13 PreviewResolvedDiagnostic,
14 ResolveResult,
16import unicode { caseFold, nfd }
17import resolver.model_facts {
18 DiscoveredGraph,
19 EdgeDraft,
20 ImportDraft,
21 ImportPathDisposition,
22 ModuleDependencyCatalog,
23 ModuleDraft,
24 PreparedImport,
25 ResolverHostFactCatalog,
26 ResolverInputs,
27 addQuery,
28 appendModuleDiagnostics,
29 contains,
30 diagnostic,
31 hasParentPathSegment,
32 pathJoin,
33 sortQueries,
34 sourceFact,
35 stringJoin,
37import resolver.modules_tables { importDrafts }
39function generatedStdModule(
40 modules: Array<PreviewGeneratedStdModule>,
41 identity: string,
42) -> Option<PreviewGeneratedStdModule> {
43 for module in modules {
44 if module.identity == identity {
45 return Some(module)
46 }
47 }
48 None
51function modulePath(root: string, segments: Array<string>) -> string {
52 pathJoin(root, "{stringJoin(segments, "/")}.tpz")
55export function moduleIdentity(entry: string, root: string) -> string {
56 let mut relative = entry
57 if root != "" && entry.startsWith("{root}/") {
58 let bytes = Bytes.encodeUtf8(entry)
59 match bytes.slice(Bytes.encodeUtf8(root).length() + 1, bytes.length()).decodeUtf8() {
60 case Ok(value) => {
61 relative = value
62 }
63 case Err(_) => ()
64 }
65 }
66 if relative.endsWith(".tpz") {
67 let bytes = Bytes.encodeUtf8(relative)
68 match bytes.slice(0, bytes.length() - 4).decodeUtf8() {
69 case Ok(value) => {
70 relative = value
71 }
72 case Err(_) => ()
73 }
74 }
75 relative.replace("/", ".")
78export function parseModule(
79 sourceOrdinal: int,
80 identity: string,
81 path: string,
82 source: string,
83 entry: bool,
84 externModule: bool,
85 generatedStd: bool,
86 maxAstNodes: int,
87 maxAstDepth: int,
88) -> Result<ModuleDraft, string> {
89 let raw = lex(source)
90 let layout = normalize(raw.tokens, source)
91 let parsed = parse(layout.tokens, source, maxAstNodes, maxAstDepth)?
92 let mut diagnostics = raw.diagnostics
93 for found in layout.diagnostics {
94 diagnostics.push(found)
95 }
96 for found in parsed.diagnostics {
97 diagnostics.push(found)
98 }
99 let sourceBytes = Bytes.encodeUtf8(source)
100 Ok(ModuleDraft {
101 result: PreviewModuleResult {
102 sourceOrdinal: sourceOrdinal,
103 identity: identity,
104 path: path,
105 source: source,
106 entry: entry,
107 extern: externModule,
108 generatedStd: generatedStd,
109 raw: raw.tokens,
110 layout: layout.tokens,
111 ast: parsed.nodes,
112 },
113 source: sourceBytes,
114 root: parsed.root,
115 imports: importDrafts(parsed.root, sourceBytes),
116 diagnostics: diagnostics,
117 })
120function isExtern(externModules: Array<string>, identity: string) -> bool {
121 contains(externModules, identity)
124function isExternNamespace(externModules: Array<string>, identity: string) -> bool {
125 let root = match identity.split(".").get(0) {
126 case Some(value) => value
127 case None => identity
128 }
129 for module in externModules {
130 if module == root || module.startsWith("{root}.") {
131 return true
132 }
133 }
134 false
137function validateSegment(
138 facts: ResolverHostFactCatalog,
139 dir: string,
140 name: string,
141 directory: bool,
142) -> ImportPathDisposition {
143 let fact = match sourceFact(facts, "list-directory", dir) {
144 case Some(value) => value
145 case None => return ImportPathDisposition { kind: "pending", collisionDetail: "" }
146 }
147 if fact.status == "unreadable" {
148 return ImportPathDisposition {
149 kind: "unreadable",
150 collisionDetail: fact.reasonCode,
151 }
152 }
153 if fact.status != "present" {
154 return ImportPathDisposition { kind: "missing", collisionDetail: "" }
155 }
156 let mut exact = false
157 let mut matches: Array<string> = []
158 let normalized = nfd(name)
159 let folded = caseFold(normalized)
160 for entry in fact.entries {
161 let sameKind = (directory && entry.kind == "directory") ||
162 (!directory && entry.kind == "file")
163 if sameKind {
164 if entry.name == name {
165 exact = true
166 }
167 let candidate = nfd(entry.name)
168 if candidate == normalized || caseFold(candidate) == folded {
169 matches.push(entry.name)
170 }
171 }
172 }
173 if matches.length > 1 {
174 ImportPathDisposition {
175 kind: "collision",
176 collisionDetail: ": {stringJoin(matches, " / ")}",
177 }
178 } else if exact {
179 ImportPathDisposition { kind: "ok", collisionDetail: "" }
180 } else {
181 ImportPathDisposition { kind: "missing", collisionDetail: "" }
182 }
185function prepareImport(
186 inputs: ResolverInputs,
187 import: ImportDraft,
188 generated: Option<PreviewGeneratedStdModule>,
189 queries: Array<PreviewHostQuery>,
190) -> Result<PreparedImport, ImportPathDisposition> {
191 match generated {
192 case Some(value) => return Ok(PreparedImport {
193 path: value.path,
194 source: value.source,
195 physicalAlias: "",
196 generatedStd: true,
197 })
198 case None => ()
199 }
200 let first = match import.segments.get(0) {
201 case Some(value) => value
202 case None => return Err(ImportPathDisposition {
203 kind: "missing",
204 collisionDetail: "",
205 })
206 }
207 let path = modulePath(if first == "std" { "" } else { inputs.root }, import.segments)
208 if first == "std" {
209 addQuery(queries, inputs.hostFacts, "read-source", path)
210 return match sourceFact(inputs.hostFacts, "read-source", path) {
211 case Some(value) => if value.status == "present" {
212 Ok(PreparedImport {
213 path: path,
214 source: value.source,
215 physicalAlias: "",
216 generatedStd: false,
217 })
218 } else if value.status == "unreadable" {
219 Err(ImportPathDisposition {
220 kind: "source-unreadable",
221 collisionDetail: value.reasonCode,
222 })
223 } else if value.status == "invalid-utf8" {
224 Err(ImportPathDisposition {
225 kind: "source-invalid-utf8",
226 collisionDetail: "",
227 })
228 } else {
229 Err(ImportPathDisposition { kind: "missing", collisionDetail: "" })
230 }
231 case None => Err(ImportPathDisposition {
232 kind: "pending",
233 collisionDetail: "",
234 })
235 }
236 }
237 addQuery(queries, inputs.hostFacts, "physical-containment", path)
238 let containment = match sourceFact(inputs.hostFacts, "physical-containment", path) {
239 case Some(value) => if value.status == "outside" {
240 return Err(ImportPathDisposition { kind: "outside", collisionDetail: "" })
241 } else {
242 value
243 }
244 case None => return Err(ImportPathDisposition {
245 kind: "pending",
246 collisionDetail: "",
247 })
248 }
249 let mut dir = inputs.root
250 let mut index = 0
251 for segment in import.segments {
252 addQuery(queries, inputs.hostFacts, "list-directory", dir)
253 let name = if index + 1 == import.segments.length {
254 "{segment}.tpz"
255 } else {
256 segment
257 }
258 let disposition = validateSegment(
259 inputs.hostFacts,
260 dir,
261 name,
262 index + 1 < import.segments.length,
263 )
264 if disposition.kind != "ok" {
265 return Err(disposition)
266 }
267 if index + 1 < import.segments.length {
268 dir = pathJoin(dir, segment)
269 }
270 index += 1
271 }
272 addQuery(queries, inputs.hostFacts, "read-source", path)
273 match sourceFact(inputs.hostFacts, "read-source", path) {
274 case Some(value) => if value.status == "present" {
275 Ok(PreparedImport {
276 path: path,
277 source: value.source,
278 physicalAlias: if containment.status == "inside" {
279 containment.aliasClass
280 } else {
281 ""
282 },
283 generatedStd: false,
284 })
285 } else if value.status == "unreadable" {
286 Err(ImportPathDisposition {
287 kind: "source-unreadable",
288 collisionDetail: value.reasonCode,
289 })
290 } else if value.status == "invalid-utf8" {
291 Err(ImportPathDisposition {
292 kind: "source-invalid-utf8",
293 collisionDetail: "",
294 })
295 } else {
296 Err(ImportPathDisposition { kind: "missing", collisionDetail: "" })
297 }
298 case None => Err(ImportPathDisposition {
299 kind: "pending",
300 collisionDetail: "",
301 })
302 }
305export function dependencyOrder(
306 modules: Array<ModuleDraft>,
307 catalog: ModuleDependencyCatalog,
308) -> Array<ModuleDraft> {
309 let mut remaining: Set<string> = set {}
310 for identity in catalog.identities {
311 remaining.add(identity)
312 }
313 let mut done: Set<string> = set {}
314 let mut output: Array<ModuleDraft> = []
315 while output.length < modules.length {
316 let mut ready: Option<int> = None
317 for identity in catalog.identities {
318 if !remaining.contains(identity) {
319 continue
320 }
321 let mut blocked = false
322 match catalog.dependencies.get(identity) {
323 case Some(targets) => for target in targets {
324 if !done.contains(target) {
325 blocked = true
326 }
327 }
328 case None => ()
329 }
330 if !blocked {
331 ready = catalog.moduleIndexes.get(identity)
332 break
333 }
334 }
335 let selected = match ready {
336 case Some(index) => modules[index]
337 case None => return modules
338 }
339 remaining.remove(selected.result.identity)
340 output.push(selected)
341 done.add(selected.result.identity)
342 }
343 output
346export function moduleDependencyCatalog(
347 modules: Array<ModuleDraft>,
348 edges: Array<EdgeDraft>,
349) -> ModuleDependencyCatalog {
350 let mut identities: Array<string> = []
351 let mut moduleIndexes: Map<string, int> = Map.new()
352 let mut dependencies: Map<string, Set<string>> = Map.new()
353 let mut dependents: Map<string, Set<string>> = Map.new()
354 let mut publicEdges: Array<PreviewImportEdge> = []
355 let mut moduleIndexValue = 0
356 for module in modules {
357 identities.push(module.result.identity)
358 moduleIndexes.insert(module.result.identity, moduleIndexValue)
359 dependencies.insert(module.result.identity, set {})
360 dependents.insert(module.result.identity, set {})
361 moduleIndexValue += 1
362 }
363 identities.sort()
364 for edge in edges {
365 if moduleIndexes.containsKey(edge.from) && moduleIndexes.containsKey(edge.to) {
366 publicEdges.push(PreviewImportEdge { from: edge.from, to: edge.to })
367 match dependencies.get(edge.from) {
368 case Some(found) => {
369 let mut targets = found
370 targets.add(edge.to)
371 }
372 case None => ()
373 }
374 match dependents.get(edge.to) {
375 case Some(found) => {
376 let mut sources = found
377 sources.add(edge.from)
378 }
379 case None => ()
380 }
381 }
382 }
383 ModuleDependencyCatalog {
384 identities: identities,
385 moduleIndexes: moduleIndexes,
386 dependencies: dependencies,
387 dependents: dependents,
388 publicEdges: publicEdges,
389 }
392function cycleFrom(
393 start: string,
394 current: string,
395 catalog: ModuleDependencyCatalog,
396 path: Array<string>,
397 visited: Set<string>,
398) -> Option<Array<string>> {
399 let mut targets = match catalog.dependencies.get(current) {
400 case Some(found) => found.toArray()
401 case None => []
402 }
403 targets.sort()
404 let mut activePath = path
405 let mut activeVisited = visited
406 for target in targets {
407 if target == start {
408 if path.length == 1 {
409 continue
410 }
411 let mut result: Array<string> = []
412 for item in path {
413 result.push(item)
414 }
415 result.push(start)
416 return Some(result)
417 }
418 if activeVisited.contains(target) {
419 continue
420 }
421 activePath.push(target)
422 activeVisited.add(target)
423 let found = cycleFrom(start, target, catalog, activePath, activeVisited)
424 activePath.pop()
425 activeVisited.remove(target)
426 match found {
427 case Some(result) => return Some(result)
428 case None => ()
429 }
430 }
431 None
434function collectReachable(
435 current: string,
436 graph: Map<string, Set<string>>,
437 visited: Set<string>,
438) -> () {
439 let targets = match graph.get(current) {
440 case Some(found) => found
441 case None => return ()
442 }
443 let mut activeVisited = visited
444 for next in targets {
445 if !activeVisited.contains(next) {
446 activeVisited.add(next)
447 let _ = collectReachable(next, graph, activeVisited)
448 }
449 }
450 ()
453function reachableFrom(
454 start: string,
455 graph: Map<string, Set<string>>,
456) -> Set<string> {
457 let mut reachable: Set<string> = set {}
458 reachable.add(start)
459 collectReachable(start, graph, reachable)
460 reachable
463export function diagnoseCycles(
464 catalog: ModuleDependencyCatalog,
465 edges: Array<EdgeDraft>,
466 diagnostics: Array<PreviewResolvedDiagnostic>,
467) -> () {
468 let mut covered: Set<string> = set {}
469 for identity in catalog.identities {
470 if covered.contains(identity) {
471 continue
472 }
473 let mut pathVisited: Set<string> = set {}
474 pathVisited.add(identity)
475 match cycleFrom(identity, identity, catalog, [identity], pathVisited) {
476 case Some(path) => {
477 let next = path[1]
478 let cycleText = stringJoin(path, " -> ")
479 for edge in edges {
480 if edge.from == identity && edge.to == next {
481 diagnostic(
482 diagnostics,
483 edge.moduleIndex,
484 "TPZ3006",
485 "import cycle: {cycleText}",
486 edge.lo,
487 edge.hi,
488 )
489 break
490 }
491 ()
492 }
493 let forward = reachableFrom(identity, catalog.dependencies)
494 let reverse = reachableFrom(identity, catalog.dependents)
495 for candidate in catalog.identities {
496 if forward.contains(candidate) && reverse.contains(candidate) {
497 covered.add(candidate)
498 }
499 }
500 ()
501 }
502 case None => {
503 for edge in edges {
504 if edge.from == identity && edge.to == identity {
505 diagnostic(
506 diagnostics,
507 edge.moduleIndex,
508 "TPZ3006",
509 "module imports itself: `{identity}`",
510 edge.lo,
511 edge.hi,
512 )
513 covered.add(identity)
514 break
515 }
516 ()
517 }
518 ()
519 }
520 }
521 ()
522 }
523 ()
526export function pendingResult(queries: Array<PreviewHostQuery>) -> ResolveResult {
527 ResolveResult {
528 queries: sortQueries(queries),
529 modules: [],
530 edges: [],
531 scopes: [],
532 declarations: [],
533 references: [],
534 exports: [],
535 diagnostics: [],
536 }
539export function validateEntryPath(
540 entry: string,
541 root: string,
542 diagnostics: Array<PreviewResolvedDiagnostic>,
543) -> bool {
544 let parentSegment = hasParentPathSegment(entry) || hasParentPathSegment(root)
545 let rootIsEntry = root != "" && entry == root
546 if parentSegment ||
547 rootIsEntry ||
548 (root != "" && !entry.startsWith("{root}/")) {
549 diagnostic(
550 diagnostics,
551 0,
552 "TPZ3002",
553 if parentSegment {
554 "entry and root paths must not contain parent (`..`) segments"
555 } else if rootIsEntry {
556 "the source root `{root}` must be a directory containing the entry, not the entry file itself"
557 } else {
558 "the root `{root}` does not contain the entry `{entry}`"
559 },
560 0,
561 0,
562 )
563 return false
564 }
565 true
568export function validateEntryPhysicalContainment(
569 entry: string,
570 facts: ResolverHostFactCatalog,
571 diagnostics: Array<PreviewResolvedDiagnostic>,
572) -> bool {
573 match sourceFact(facts, "physical-containment", entry) {
574 case Some(value) => if value.status == "outside" {
575 diagnostic(
576 diagnostics,
577 0,
578 "TPZ3005",
579 "the entry `{entry}` resolves outside the root (symlink/alias containment)",
580 0,
581 0,
582 )
583 false
584 } else {
585 true
586 }
587 case None => true
588 }
591export function readEntrySource(
592 entry: string,
593 facts: ResolverHostFactCatalog,
594 diagnostics: Array<PreviewResolvedDiagnostic>,
595) -> Option<string> {
596 match sourceFact(facts, "read-source", entry) {
597 case Some(value) => if value.status == "present" {
598 Some(value.source)
599 } else if value.status == "unreadable" {
600 diagnostic(
601 diagnostics,
602 0,
603 "TPZ3003",
604 "cannot load entry `{entry}`: {value.reasonCode}",
605 0,
606 0,
607 )
608 None
609 } else if value.status == "invalid-utf8" {
610 diagnostic(
611 diagnostics,
612 0,
613 "TPZ3003",
614 "cannot load entry `{entry}`: source is not valid UTF-8",
615 0,
616 0,
617 )
618 None
619 } else {
620 diagnostic(
621 diagnostics,
622 0,
623 "TPZ3001",
624 "entry file `{entry}` does not exist",
625 0,
626 0,
627 )
628 None
629 }
630 case None => {
631 diagnostic(
632 diagnostics,
633 0,
634 "TPZ3001",
635 "entry file `{entry}` does not exist",
636 0,
637 0,
638 )
639 None
640 }
641 }
644function validateImportedTopLevel(
645 module: ModuleDraft,
646 target: string,
647 moduleIndexValue: int,
648 diagnostics: Array<PreviewResolvedDiagnostic>,
649) -> () {
650 for statement in module.root.children {
651 let allowed = statement.kind == "statement/import" ||
652 statement.kind == "statement/export" ||
653 statement.kind == "statement/function" ||
654 statement.kind == "statement/impl" ||
655 statement.kind == "statement/protocol" ||
656 statement.kind == "statement/type-alias" ||
657 statement.kind == "statement/enum" ||
658 statement.kind == "statement/record" ||
659 statement.kind == "statement/newtype" ||
660 statement.kind == "statement/let" ||
661 statement.kind == "statement/const"
662 if !allowed {
663 diagnostic(
664 diagnostics,
665 moduleIndexValue,
666 "TPZ3007",
667 "imported module `{target}` contains a top-level free statement; free statements are entry-only (the same file is valid as an entry)",
668 statement.lo,
669 statement.hi,
670 )
671 }
672 }
673 ()
676function recordImportEdge(
677 module: ModuleDraft,
678 moduleIndexValue: int,
679 import: ImportDraft,
680 importedHere: Array<string>,
681 edges: Array<EdgeDraft>,
682 diagnostics: Array<PreviewResolvedDiagnostic>,
683) -> bool {
684 let firstSegment = match import.segments.get(0) {
685 case Some(value) => value
686 case None => ""
687 }
688 if firstSegment == "topaz" {
689 diagnostic(
690 diagnostics,
691 moduleIndexValue,
692 "TPZ3016",
693 "the module path root `topaz` is reserved; user modules cannot live under it",
694 import.pathLo,
695 import.pathHi,
696 )
697 return false
698 }
699 let mut graphEdges = edges
700 graphEdges.push(EdgeDraft {
701 from: module.result.identity,
702 to: import.target,
703 moduleIndex: moduleIndexValue,
704 lo: import.pathLo,
705 hi: import.pathHi,
706 })
707 if contains(importedHere, import.target) {
708 diagnostic(
709 diagnostics,
710 moduleIndexValue,
711 "TPZ3017",
712 "`{import.target}` is already imported by this module; a logical module may appear in at most one import item",
713 import.pathLo,
714 import.pathHi,
715 )
716 return false
717 }
718 let mut admitted = importedHere
719 admitted.push(import.target)
720 true
723function reportImportDisposition(
724 inputs: ResolverInputs,
725 import: ImportDraft,
726 disposition: ImportPathDisposition,
727 moduleIndexValue: int,
728 diagnostics: Array<PreviewResolvedDiagnostic>,
729) -> () {
730 if disposition.kind == "pending" {
731 return ()
732 }
733 if disposition.kind == "outside" {
734 diagnostic(
735 diagnostics,
736 moduleIndexValue,
737 "TPZ3005",
738 "`{import.target}` resolves outside the root (symlink/alias containment)",
739 import.pathLo,
740 import.pathHi,
741 )
742 return ()
743 }
744 if disposition.kind == "collision" {
745 diagnostic(
746 diagnostics,
747 moduleIndexValue,
748 "TPZ3004",
749 "the path `{import.target}` collides with another candidate under the module name keys{disposition.collisionDetail}",
750 import.pathLo,
751 import.pathHi,
752 )
753 return ()
754 }
755 if disposition.kind == "unreadable" {
756 diagnostic(
757 diagnostics,
758 moduleIndexValue,
759 "TPZ3003",
760 "cannot inspect module path for `{import.target}`: {disposition.collisionDetail}",
761 import.pathLo,
762 import.pathHi,
763 )
764 return ()
765 }
766 if disposition.kind == "source-unreadable" ||
767 disposition.kind == "source-invalid-utf8" {
768 diagnostic(
769 diagnostics,
770 moduleIndexValue,
771 "TPZ3003",
772 if disposition.kind == "source-invalid-utf8" {
773 "cannot load module `{import.target}`: source is not valid UTF-8"
774 } else {
775 "cannot load module `{import.target}`: {disposition.collisionDetail}"
776 },
777 import.pathLo,
778 import.pathHi,
779 )
780 return ()
781 }
782 if disposition.kind == "missing" {
783 let standard = match import.segments.get(0) {
784 case Some(value) => value == "std"
785 case None => false
786 }
787 let externNamespace = !standard &&
788 isExternNamespace(inputs.externModules, import.target)
789 diagnostic(
790 diagnostics,
791 moduleIndexValue,
792 if externNamespace { "TPZ5030" } else { "TPZ3001" },
793 if externNamespace {
794 "extern module `{import.target}` is not declared in topaz.toml"
795 } else if standard {
796 "no std module for `{import.target}` (expected virtual `{stringJoin(import.segments, "/")}.tpz`)"
797 } else {
798 "no module file for `{import.target}` (expected `{modulePath(inputs.root, import.segments)}` by exact scalars)"
799 },
800 import.pathLo,
801 import.pathHi,
802 )
803 }
804 ()
807function loadImportedModule(
808 inputs: ResolverInputs,
809 import: ImportDraft,
810 prepared: PreparedImport,
811 moduleIndexValue: int,
812) -> Result<ModuleDraft, string> {
813 parseModule(
814 moduleIndexValue,
815 import.target,
816 prepared.path,
817 prepared.source,
818 false,
819 isExtern(inputs.externModules, import.target),
820 prepared.generatedStd,
821 inputs.maxAstNodes,
822 inputs.maxAstDepth,
823 )
826export function discoverModuleGraph(
827 entryDraft: ModuleDraft,
828 inputs: ResolverInputs,
829 queries: Array<PreviewHostQuery>,
830 diagnostics: Array<PreviewResolvedDiagnostic>,
831) -> Result<DiscoveredGraph, string> {
832 let mut discovered: Array<ModuleDraft> = [entryDraft]
833 let mut queued: Set<string> = set { entryDraft.result.identity }
834 let mut physicalIdentities: Map<string, string> = Map.new()
835 match sourceFact(inputs.hostFacts, "physical-containment", entryDraft.result.path) {
836 case Some(fact) => if fact.status == "inside" && fact.aliasClass != "" {
837 physicalIdentities.insert(fact.aliasClass, entryDraft.result.identity)
838 }
839 case None => ()
840 }
841 appendModuleDiagnostics(diagnostics, 0, entryDraft.diagnostics)
842 let mut edges: Array<EdgeDraft> = []
843 let mut next = 0
844 while next < discovered.length {
845 let module = discovered[next]
846 let mut importedHere: Array<string> = []
847 for import in module.imports {
848 if !recordImportEdge(
849 module,
850 next,
851 import,
852 importedHere,
853 edges,
854 diagnostics,
855 ) {
856 continue
857 }
858 if queued.contains(import.target) {
859 continue
860 }
861 queued.add(import.target)
862 let generated = generatedStdModule(inputs.generatedStdModules, import.target)
863 match prepareImport(inputs, import, generated, queries) {
864 case Ok(prepared) => {
865 if prepared.physicalAlias != "" {
866 match physicalIdentities.get(prepared.physicalAlias) {
867 case Some(existing) => {
868 diagnostic(
869 diagnostics,
870 next,
871 "TPZ3004",
872 "the modules `{existing}` and `{import.target}` resolve to the same physical file; one physical file cannot have two module identities",
873 import.pathLo,
874 import.pathHi,
875 )
876 continue
877 }
878 case None => physicalIdentities.insert(prepared.physicalAlias, import.target)
879 }
880 }
881 let imported = loadImportedModule(
882 inputs,
883 import,
884 prepared,
885 discovered.length,
886 )?
887 let importedIndex = discovered.length
888 appendModuleDiagnostics(diagnostics, importedIndex, imported.diagnostics)
889 validateImportedTopLevel(imported, import.target, importedIndex, diagnostics)
890 discovered.push(imported)
891 }
892 case Err(disposition) => {
893 reportImportDisposition(
894 inputs,
895 import,
896 disposition,
897 next,
898 diagnostics,
899 )
900 }
901 }
902 }
903 next += 1
904 }
905 Ok(DiscoveredGraph {
906 modules: discovered,
907 edges: edges,
908 })

SHA256 b0dc672402bff2c4df9937c2486a12ea4a2caeb264db9aefe31efdea7ea1c5e1