Skip to main content

morphir_core/node_address/
index.rs

1//! Semantic node index for normalized V3 and V4 distributions.
2
3use super::{
4    ArtifactRevision, ArtifactSelector, IrFormatVersion, NodeFingerprintBuilder, NodeOwner,
5    NodeRoot, NodeStep, NodeUri, Sha256Digest, semantic_json,
6};
7use crate::format_version::{NormalizedFormatVersion, ScalarValue, SupportTable};
8use crate::ir::{classic, v4};
9use crate::naming::{Name, PackageName, Path};
10use serde::Serialize;
11use std::collections::HashMap;
12
13/// The kind of node found at a semantic address.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum IndexedNodeKind {
16    Distribution,
17    Package,
18    Module,
19    TypeDefinition,
20    ValueDefinition,
21    Constructor,
22    TypeExpression,
23    ValueExpression,
24    Pattern,
25    EntryPoint,
26}
27
28/// Distinct outcomes of semantic node lookup or index construction.
29#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
30pub enum NodeResolutionError {
31    #[error("artifact selector does not match the indexed distribution")]
32    ArtifactMismatch,
33    #[error("artifact selector matches multiple current or pinned distributions")]
34    AmbiguousArtifact,
35    #[error("IR format version does not match the indexed distribution")]
36    FormatVersionMismatch,
37    #[error("the requested immutable revision is unavailable in this index")]
38    RevisionUnavailable,
39    #[error("acquired snapshot bytes do not match the requested revision")]
40    RevisionMismatch,
41    #[error("the node path or positional guard is stale")]
42    StaleTarget,
43    #[error("more than one semantic node has the same address")]
44    AmbiguousTarget,
45    #[error("invalid normalized IR name: {0}")]
46    InvalidName(String),
47    #[error("cannot fingerprint a semantic child: {0}")]
48    InvalidFingerprint(String),
49    #[error("cannot decode immutable snapshot: {0}")]
50    InvalidSnapshot(String),
51}
52
53/// A resolved occurrence in the normalized semantic model. Equal subtrees can
54/// have different addresses, so reverse lookup uses the occurrence's URI.
55#[derive(Debug, Clone, PartialEq)]
56pub struct ResolvedNode {
57    pub kind: IndexedNodeKind,
58    pub semantic_value: serde_json::Value,
59}
60
61#[derive(Debug, Clone)]
62struct IndexedNode {
63    address: NodeUri,
64    node: ResolvedNode,
65}
66
67/// An index of addressable nodes in one loaded distribution.
68#[derive(Debug)]
69pub struct NodeIndex {
70    artifact: ArtifactSelector,
71    format: IrFormatVersion,
72    nodes: HashMap<(NodeRoot, Vec<NodeStep>), IndexedNode>,
73}
74
75/// Caller-supplied current distributions and exact acquired snapshots.
76///
77/// This catalog decodes each snapshot from the exact bytes it hashes, then
78/// builds its index. A caller cannot pair one artifact's digest with another's
79/// index. Pinned resolution never falls back to a current distribution.
80#[derive(Default)]
81pub struct NodeCatalog {
82    current: Vec<NodeIndex>,
83    snapshots: Vec<(Sha256Digest, NodeIndex)>,
84}
85
86impl NodeCatalog {
87    pub fn new() -> Self {
88        Self::default()
89    }
90
91    pub fn add_current(&mut self, index: NodeIndex) {
92        self.current.push(index);
93    }
94
95    /// Register one V4 JSON snapshot, optionally checking an expected pin.
96    pub fn add_v4_json_snapshot(
97        &mut self,
98        bytes: &[u8],
99        expected: Option<&Sha256Digest>,
100    ) -> Result<Sha256Digest, NodeResolutionError> {
101        let digest = verify_snapshot_digest(bytes, expected)?;
102        let text = std::str::from_utf8(bytes)
103            .map_err(|error| NodeResolutionError::InvalidSnapshot(error.to_string()))?;
104        let (file, _) = crate::ir::json::read_ir_file(text)
105            .map_err(|error| NodeResolutionError::InvalidSnapshot(error.to_string()))?;
106        let index = NodeIndex::v4_file(&file)?;
107        self.snapshots.push((digest.clone(), index));
108        Ok(digest)
109    }
110
111    /// Register one Classic V3 JSON snapshot, optionally checking a pin.
112    pub fn add_v3_json_snapshot(
113        &mut self,
114        bytes: &[u8],
115        expected: Option<&Sha256Digest>,
116    ) -> Result<Sha256Digest, NodeResolutionError> {
117        let digest = verify_snapshot_digest(bytes, expected)?;
118        let index = NodeIndex::v3_json(bytes)?;
119        self.snapshots.push((digest.clone(), index));
120        Ok(digest)
121    }
122
123    pub fn resolve(&self, address: &NodeUri) -> Result<IndexedNodeKind, NodeResolutionError> {
124        self.resolve_node(address).map(|node| node.kind)
125    }
126
127    pub fn resolve_node(&self, address: &NodeUri) -> Result<&ResolvedNode, NodeResolutionError> {
128        match &address.revision {
129            ArtifactRevision::Current => {
130                let mut matching = self
131                    .current
132                    .iter()
133                    .filter(|index| index.artifact == address.artifact);
134                let index = matching
135                    .next()
136                    .ok_or(NodeResolutionError::ArtifactMismatch)?;
137                if matching.next().is_some() {
138                    return Err(NodeResolutionError::AmbiguousArtifact);
139                }
140                index.resolve_node(address)
141            }
142            ArtifactRevision::Pinned(digest) => {
143                let mut matching = self.snapshots.iter().filter(|(candidate, index)| {
144                    candidate == digest && index.artifact == address.artifact
145                });
146                let (_, index) = matching
147                    .next()
148                    .ok_or(NodeResolutionError::RevisionUnavailable)?;
149                if matching.next().is_some() {
150                    return Err(NodeResolutionError::AmbiguousArtifact);
151                }
152                if address.format != index.format {
153                    return Err(NodeResolutionError::FormatVersionMismatch);
154                }
155                let node = index
156                    .nodes
157                    .get(&(address.root.clone(), address.steps.clone()))
158                    .ok_or(NodeResolutionError::StaleTarget)?;
159                if let Some(guard) = &address.guard
160                    && node.address.guard.as_ref() != Some(guard)
161                {
162                    return Err(NodeResolutionError::StaleTarget);
163                }
164                Ok(&node.node)
165            }
166        }
167    }
168}
169
170fn verify_snapshot_digest(
171    bytes: &[u8],
172    expected: Option<&Sha256Digest>,
173) -> Result<Sha256Digest, NodeResolutionError> {
174    let actual = Sha256Digest::from_bytes(bytes);
175    if expected.is_some_and(|expected| expected != &actual) {
176        return Err(NodeResolutionError::RevisionMismatch);
177    }
178    Ok(actual)
179}
180
181#[derive(Clone)]
182struct WalkContext {
183    root: NodeRoot,
184    steps: Vec<NodeStep>,
185    lineage: Option<NodeFingerprintBuilder>,
186    linked_metadata_guards: bool,
187}
188
189impl WalkContext {
190    fn root(root: NodeRoot) -> Self {
191        Self {
192            root,
193            steps: Vec::new(),
194            lineage: None,
195            linked_metadata_guards: false,
196        }
197    }
198
199    fn v4_root(root: NodeRoot, format: IrFormatVersion) -> Self {
200        Self {
201            linked_metadata_guards: format.major() == 4 && format.minor() == 1,
202            ..Self::root(root)
203        }
204    }
205
206    fn named(&self, step: NodeStep) -> Self {
207        let mut next = self.clone();
208        next.steps.push(step);
209        next
210    }
211
212    fn ordered<T: Serialize>(
213        &self,
214        step: NodeStep,
215        child: &T,
216    ) -> Result<Self, NodeResolutionError> {
217        let mut next = self.named(step.clone());
218        let mut lineage = next.lineage.unwrap_or_else(|| {
219            if self.linked_metadata_guards {
220                NodeFingerprintBuilder::for_v4_1()
221            } else {
222                NodeFingerprintBuilder::new()
223            }
224        });
225        lineage
226            .push(&step, child)
227            .map_err(|error| NodeResolutionError::InvalidFingerprint(error.to_string()))?;
228        next.lineage = Some(lineage);
229        Ok(next)
230    }
231}
232
233impl NodeIndex {
234    /// Index a complete V4 file using its exact normalized format version.
235    pub fn v4_file(file: &v4::IRFile) -> Result<Self, NodeResolutionError> {
236        let artifact = ArtifactSelector::Package(file.distribution.package_name().clone());
237        Self::v4_file_with_selector(file, artifact)
238    }
239
240    /// Index a complete V4 file under a package selector or workspace alias.
241    pub fn v4_file_with_selector(
242        file: &v4::IRFile,
243        artifact: ArtifactSelector,
244    ) -> Result<Self, NodeResolutionError> {
245        let scalar = match &file.format_version {
246            v4::FormatVersion::String(version) => ScalarValue::String(version.clone()),
247            v4::FormatVersion::Integer(version) => ScalarValue::Integer(u64::from(*version)),
248        };
249        let normalized =
250            NormalizedFormatVersion::from_scalar(&scalar, &SupportTable::linked_metadata())
251                .map_err(|_| NodeResolutionError::FormatVersionMismatch)?;
252        if normalized.release.major() != 4
253            || !normalized.is_supported()
254            || (file.has_linked_metadata() && normalized.release != IrFormatVersion::new(4, 1, 0))
255        {
256            return Err(NodeResolutionError::FormatVersionMismatch);
257        }
258        Self::v4_with_format(&file.distribution, artifact, normalized.release)
259    }
260
261    /// Index a normalized V4 distribution and all currently supported semantic nodes.
262    pub fn v4(distribution: &v4::Distribution) -> Result<Self, NodeResolutionError> {
263        let artifact = ArtifactSelector::Package(distribution.package_name().clone());
264        Self::v4_with_selector(distribution, artifact)
265    }
266
267    /// Index a V4 distribution under its package name or an exact workspace alias.
268    pub fn v4_with_selector(
269        distribution: &v4::Distribution,
270        artifact: ArtifactSelector,
271    ) -> Result<Self, NodeResolutionError> {
272        Self::v4_with_format(distribution, artifact, IrFormatVersion::new(4, 0, 0))
273    }
274
275    fn v4_with_format(
276        distribution: &v4::Distribution,
277        artifact: ArtifactSelector,
278        format: IrFormatVersion,
279    ) -> Result<Self, NodeResolutionError> {
280        if let ArtifactSelector::Package(package) = &artifact
281            && package != distribution.package_name()
282        {
283            return Err(NodeResolutionError::ArtifactMismatch);
284        }
285        let mut index = Self::new(artifact, format);
286        index.add(
287            &WalkContext::root(NodeRoot::Distribution),
288            IndexedNodeKind::Distribution,
289            distribution,
290        )?;
291        match distribution {
292            v4::Distribution::Library(library) => {
293                index.add(
294                    &WalkContext::root(NodeRoot::Package),
295                    IndexedNodeKind::Package,
296                    &library.def,
297                )?;
298                index.v4_definition_package(NodeOwner::OwnPackage, &library.def)?;
299                for (package, spec) in &library.dependencies {
300                    let package = parse_package(package)?;
301                    index.add(
302                        &WalkContext::root(NodeRoot::Dependency(package.clone())),
303                        IndexedNodeKind::Package,
304                        spec,
305                    )?;
306                    index.v4_specification_package(NodeOwner::Dependency(package), spec)?;
307                }
308            }
309            v4::Distribution::Specs(specs) => {
310                index.add(
311                    &WalkContext::root(NodeRoot::Package),
312                    IndexedNodeKind::Package,
313                    &specs.spec,
314                )?;
315                index.v4_specification_package(NodeOwner::OwnPackage, &specs.spec)?;
316                for (package, spec) in &specs.dependencies {
317                    let package = parse_package(package)?;
318                    index.add(
319                        &WalkContext::root(NodeRoot::Dependency(package.clone())),
320                        IndexedNodeKind::Package,
321                        spec,
322                    )?;
323                    index.v4_specification_package(NodeOwner::Dependency(package), spec)?;
324                }
325            }
326            v4::Distribution::Application(application) => {
327                index.add(
328                    &WalkContext::root(NodeRoot::Package),
329                    IndexedNodeKind::Package,
330                    &application.def,
331                )?;
332                index.v4_definition_package(NodeOwner::OwnPackage, &application.def)?;
333                for (package, definition) in &application.dependencies {
334                    let package = parse_package(package)?;
335                    index.add(
336                        &WalkContext::root(NodeRoot::Dependency(package.clone())),
337                        IndexedNodeKind::Package,
338                        definition,
339                    )?;
340                    index.v4_definition_package(NodeOwner::Dependency(package), definition)?;
341                }
342                for (key, entry_point) in &application.entry_points {
343                    index.add(
344                        &WalkContext::root(NodeRoot::EntryPoint(key.clone())),
345                        IndexedNodeKind::EntryPoint,
346                        entry_point,
347                    )?;
348                }
349            }
350        }
351        Ok(index)
352    }
353
354    /// Index one Classic V3 library under an explicit artifact selector.
355    pub fn v3(
356        distribution: &classic::Distribution,
357        artifact: ArtifactSelector,
358    ) -> Result<Self, NodeResolutionError> {
359        let format = match &distribution.distribution {
360            classic::DistributionBody::Library(..) => IrFormatVersion::new(3, 0, 0),
361            classic::DistributionBody::Specs(..) => IrFormatVersion::new(3, 1, 0),
362        };
363        Self::v3_with_format(distribution, artifact, format)
364    }
365
366    /// Index exact Classic V3 JSON, preserving its declared release.
367    pub fn v3_json(bytes: &[u8]) -> Result<Self, NodeResolutionError> {
368        let value: serde_json::Value = serde_json::from_slice(bytes)
369            .map_err(|error| NodeResolutionError::InvalidSnapshot(error.to_string()))?;
370        let declared = value
371            .get("formatVersion")
372            .ok_or_else(|| NodeResolutionError::InvalidSnapshot("missing formatVersion".into()))?;
373        let scalar = ScalarValue::from_json(declared)
374            .map_err(|error| NodeResolutionError::InvalidSnapshot(error.to_string()))?;
375        let normalized = NormalizedFormatVersion::from_scalar(&scalar, &SupportTable::reference())
376            .map_err(|error| NodeResolutionError::InvalidSnapshot(error.to_string()))?;
377        if !normalized.is_supported() {
378            return Err(NodeResolutionError::FormatVersionMismatch);
379        }
380        let distribution: classic::Distribution = serde_json::from_value(value)
381            .map_err(|error| NodeResolutionError::InvalidSnapshot(error.to_string()))?;
382        let package = match &distribution.distribution {
383            classic::DistributionBody::Library(package, _, _)
384            | classic::DistributionBody::Specs(package, _, _) => package,
385        };
386        let selector = ArtifactSelector::Package(PackageName::new(classic_path(package)?));
387        Self::v3_with_format(&distribution, selector, normalized.release)
388    }
389
390    fn v3_with_format(
391        distribution: &classic::Distribution,
392        artifact: ArtifactSelector,
393        format: IrFormatVersion,
394    ) -> Result<Self, NodeResolutionError> {
395        if distribution.format_version != 3 {
396            return Err(NodeResolutionError::FormatVersionMismatch);
397        }
398        if format.major() != 3
399            || matches!(
400                distribution.distribution,
401                classic::DistributionBody::Specs(..)
402            ) && format < IrFormatVersion::new(3, 1, 0)
403        {
404            return Err(NodeResolutionError::FormatVersionMismatch);
405        }
406        let mut index = Self::new(artifact, format);
407        index.add(
408            &WalkContext::root(NodeRoot::Distribution),
409            IndexedNodeKind::Distribution,
410            distribution,
411        )?;
412        let (package_path, dependencies) = match &distribution.distribution {
413            classic::DistributionBody::Library(path, dependencies, _)
414            | classic::DistributionBody::Specs(path, dependencies, _) => (path, dependencies),
415        };
416        if let ArtifactSelector::Package(selected) = &index.artifact
417            && selected.as_path() != &classic_path(package_path)?
418        {
419            return Err(NodeResolutionError::ArtifactMismatch);
420        }
421        match &distribution.distribution {
422            classic::DistributionBody::Library(_, _, package) => {
423                index.add(
424                    &WalkContext::root(NodeRoot::Package),
425                    IndexedNodeKind::Package,
426                    package,
427                )?;
428                index.v3_definition_package(NodeOwner::OwnPackage, package)?;
429            }
430            classic::DistributionBody::Specs(_, _, package) => {
431                index.add(
432                    &WalkContext::root(NodeRoot::Package),
433                    IndexedNodeKind::Package,
434                    package,
435                )?;
436                index.v3_specification_package(NodeOwner::OwnPackage, package)?;
437            }
438        }
439        for (path, specification) in dependencies {
440            let package = PackageName::new(classic_path(path)?);
441            index.add(
442                &WalkContext::root(NodeRoot::Dependency(package.clone())),
443                IndexedNodeKind::Package,
444                specification,
445            )?;
446            index.v3_specification_package(NodeOwner::Dependency(package), specification)?;
447        }
448        Ok(index)
449    }
450
451    fn new(artifact: ArtifactSelector, format: IrFormatVersion) -> Self {
452        Self {
453            artifact,
454            format,
455            nodes: HashMap::new(),
456        }
457    }
458
459    fn add<T: Serialize>(
460        &mut self,
461        context: &WalkContext,
462        kind: IndexedNodeKind,
463        semantic_node: &T,
464    ) -> Result<(), NodeResolutionError> {
465        let address = NodeUri::new(
466            self.artifact.clone(),
467            self.format,
468            context.root.clone(),
469            context.steps.clone(),
470            ArtifactRevision::Current,
471            context.lineage.clone().map(NodeFingerprintBuilder::finish),
472        )
473        .map_err(|error| NodeResolutionError::InvalidName(error.to_string()))?;
474        let key = (context.root.clone(), context.steps.clone());
475        let semantic_value = semantic_json(semantic_node)
476            .map_err(|error| NodeResolutionError::InvalidFingerprint(error.to_string()))?;
477        if self
478            .nodes
479            .insert(
480                key,
481                IndexedNode {
482                    address,
483                    node: ResolvedNode {
484                        kind,
485                        semantic_value,
486                    },
487                },
488            )
489            .is_some()
490        {
491            return Err(NodeResolutionError::AmbiguousTarget);
492        }
493        Ok(())
494    }
495
496    /// Resolve one address in this loaded distribution. Pinned addresses require
497    /// an immutable snapshot resolver and are not silently applied to current.
498    pub fn resolve(&self, address: &NodeUri) -> Result<IndexedNodeKind, NodeResolutionError> {
499        self.resolve_node(address).map(|node| node.kind)
500    }
501
502    pub fn resolve_node(&self, address: &NodeUri) -> Result<&ResolvedNode, NodeResolutionError> {
503        if address.artifact != self.artifact {
504            return Err(NodeResolutionError::ArtifactMismatch);
505        }
506        if address.format != self.format {
507            return Err(NodeResolutionError::FormatVersionMismatch);
508        }
509        if !matches!(address.revision, ArtifactRevision::Current) {
510            return Err(NodeResolutionError::RevisionUnavailable);
511        }
512        let node = self
513            .nodes
514            .get(&(address.root.clone(), address.steps.clone()))
515            .ok_or(NodeResolutionError::StaleTarget)?;
516        if node.address.guard != address.guard {
517            return Err(NodeResolutionError::StaleTarget);
518        }
519        Ok(&node.node)
520    }
521
522    /// Enumerate canonical current addresses in this distribution.
523    pub fn addresses(&self) -> impl Iterator<Item = &NodeUri> {
524        self.nodes.values().map(|node| &node.address)
525    }
526
527    /// Enumerate occurrences with their canonical addresses, including equal
528    /// semantic subtrees at distinct positions.
529    pub fn nodes(&self) -> impl Iterator<Item = (&NodeUri, &ResolvedNode)> {
530        self.nodes.values().map(|node| (&node.address, &node.node))
531    }
532
533    /// Return the canonical current URI for a known typed path, including a
534    /// computed guard when that path enters ordered children.
535    pub fn address_for(
536        &self,
537        root: &NodeRoot,
538        steps: &[NodeStep],
539    ) -> Result<NodeUri, NodeResolutionError> {
540        self.nodes
541            .get(&(root.clone(), steps.to_vec()))
542            .map(|node| node.address.clone())
543            .ok_or(NodeResolutionError::StaleTarget)
544    }
545
546    fn v4_definition_package(
547        &mut self,
548        owner: NodeOwner,
549        package: &v4::PackageDefinition,
550    ) -> Result<(), NodeResolutionError> {
551        for (module_name, controlled) in &package.modules {
552            let module = parse_path(module_name)?;
553            let definition = &controlled.value;
554            self.add(
555                &WalkContext::root(NodeRoot::Module {
556                    owner: owner.clone(),
557                    module: module.clone(),
558                }),
559                IndexedNodeKind::Module,
560                definition,
561            )?;
562            for (name, controlled) in &definition.types {
563                let context = WalkContext::v4_root(
564                    NodeRoot::Type {
565                        owner: owner.clone(),
566                        module: module.clone(),
567                        name: parse_name(name)?,
568                    },
569                    self.format,
570                );
571                self.add(
572                    &context,
573                    IndexedNodeKind::TypeDefinition,
574                    &controlled.value.value,
575                )?;
576                self.v4_type_definition(&context, &controlled.value.value)?;
577            }
578            for (name, controlled) in &definition.values {
579                let context = WalkContext::v4_root(
580                    NodeRoot::Value {
581                        owner: owner.clone(),
582                        module: module.clone(),
583                        name: parse_name(name)?,
584                    },
585                    self.format,
586                );
587                self.add(
588                    &context,
589                    IndexedNodeKind::ValueDefinition,
590                    &controlled.value.value,
591                )?;
592                self.v4_value_definition(&context, &controlled.value.value)?;
593            }
594        }
595        Ok(())
596    }
597
598    fn v4_specification_package(
599        &mut self,
600        owner: NodeOwner,
601        package: &v4::PackageSpecification,
602    ) -> Result<(), NodeResolutionError> {
603        for (module_name, specification) in &package.modules {
604            let module = parse_path(module_name)?;
605            self.add(
606                &WalkContext::root(NodeRoot::Module {
607                    owner: owner.clone(),
608                    module: module.clone(),
609                }),
610                IndexedNodeKind::Module,
611                specification,
612            )?;
613            self.v4_annotations(
614                &WalkContext::v4_root(
615                    NodeRoot::Module {
616                        owner: owner.clone(),
617                        module: module.clone(),
618                    },
619                    self.format,
620                ),
621                &specification.annotations,
622            )?;
623            for (name, documented) in &specification.types {
624                let context = WalkContext::v4_root(
625                    NodeRoot::Type {
626                        owner: owner.clone(),
627                        module: module.clone(),
628                        name: parse_name(name)?,
629                    },
630                    self.format,
631                );
632                self.add(&context, IndexedNodeKind::TypeDefinition, &documented.value)?;
633                self.v4_type_specification(&context, &documented.value)?;
634            }
635            for (name, documented) in &specification.values {
636                let context = WalkContext::v4_root(
637                    NodeRoot::Value {
638                        owner: owner.clone(),
639                        module: module.clone(),
640                        name: parse_name(name)?,
641                    },
642                    self.format,
643                );
644                self.add(
645                    &context,
646                    IndexedNodeKind::ValueDefinition,
647                    &documented.value,
648                )?;
649                self.v4_value_specification(&context, &documented.value)?;
650            }
651        }
652        Ok(())
653    }
654
655    fn v4_type_definition(
656        &mut self,
657        context: &WalkContext,
658        definition: &v4::TypeDefinition,
659    ) -> Result<(), NodeResolutionError> {
660        match definition {
661            v4::TypeDefinition::TypeAliasDefinition { type_expr, .. } => {
662                self.v4_type(&context.named(NodeStep::TypeExpression), type_expr)?
663            }
664            v4::TypeDefinition::CustomTypeDefinition { constructors, .. } => {
665                for constructor in &constructors.value {
666                    let child =
667                        context.named(NodeStep::CustomConstructor(constructor.name.clone()));
668                    self.add(&child, IndexedNodeKind::Constructor, constructor)?;
669                    for (index, argument) in constructor.args.iter().enumerate() {
670                        let argument_context = child
671                            .ordered(NodeStep::ConstructorArgument(index), &argument.arg_type)?;
672                        self.v4_type(&argument_context, &argument.arg_type)?;
673                    }
674                }
675            }
676            v4::TypeDefinition::IncompleteTypeDefinition {
677                incompleteness,
678                partial_type_expr,
679                ..
680            } => {
681                if let Some(ty) = partial_type_expr {
682                    self.v4_type(&context.named(NodeStep::PartialTypeExpression), ty)?;
683                }
684                if let v4::Incompleteness::Hole {
685                    partial_body: Some(ty),
686                    ..
687                } = incompleteness
688                {
689                    self.v4_type(&context.named(NodeStep::HoleExpectedType), ty)?;
690                }
691            }
692        }
693        Ok(())
694    }
695
696    fn v4_type_specification(
697        &mut self,
698        context: &WalkContext,
699        specification: &v4::TypeSpecification,
700    ) -> Result<(), NodeResolutionError> {
701        let annotations = match specification {
702            v4::TypeSpecification::TypeAliasSpecification { annotations, .. }
703            | v4::TypeSpecification::OpaqueTypeSpecification { annotations, .. }
704            | v4::TypeSpecification::CustomTypeSpecification { annotations, .. }
705            | v4::TypeSpecification::DerivedTypeSpecification { annotations, .. } => annotations,
706        };
707        self.v4_annotations(context, annotations)?;
708        match specification {
709            v4::TypeSpecification::TypeAliasSpecification { type_expr, .. } => {
710                self.v4_type(&context.named(NodeStep::TypeExpression), type_expr)?
711            }
712            v4::TypeSpecification::CustomTypeSpecification { constructors, .. } => {
713                for constructor in constructors {
714                    let child =
715                        context.named(NodeStep::CustomConstructor(constructor.name.clone()));
716                    self.add(&child, IndexedNodeKind::Constructor, constructor)?;
717                    for (index, argument) in constructor.args.iter().enumerate() {
718                        let argument_context = child
719                            .ordered(NodeStep::ConstructorArgument(index), &argument.arg_type)?;
720                        self.v4_type(&argument_context, &argument.arg_type)?;
721                    }
722                }
723            }
724            v4::TypeSpecification::DerivedTypeSpecification { base_type, .. } => {
725                self.v4_type(&context.named(NodeStep::DerivedBaseType), base_type)?
726            }
727            v4::TypeSpecification::OpaqueTypeSpecification { .. } => {}
728        }
729        Ok(())
730    }
731
732    fn v4_type(&mut self, context: &WalkContext, ty: &v4::Type) -> Result<(), NodeResolutionError> {
733        self.add(context, IndexedNodeKind::TypeExpression, ty)?;
734        match ty {
735            v4::Type::Record(_, fields) => {
736                for field in fields {
737                    self.v4_type(
738                        &context.named(NodeStep::RecordField(field.name.clone())),
739                        &field.tpe,
740                    )?;
741                }
742            }
743            v4::Type::ExtensibleRecord(_, _, fields) => {
744                for field in fields {
745                    self.v4_type(
746                        &context.named(NodeStep::ExtensibleRecordField(field.name.clone())),
747                        &field.tpe,
748                    )?;
749                }
750            }
751            v4::Type::Function(_, parameter, result) => {
752                self.v4_type(&context.named(NodeStep::TypeFunctionParameter), parameter)?;
753                self.v4_type(&context.named(NodeStep::TypeFunctionResult), result)?;
754            }
755            v4::Type::Reference(_, _, arguments) => {
756                for (index, argument) in arguments.iter().enumerate() {
757                    let child = context.ordered(NodeStep::ReferenceArgument(index), argument)?;
758                    self.v4_type(&child, argument)?;
759                }
760            }
761            v4::Type::Tuple(_, elements) => {
762                for (index, element) in elements.iter().enumerate() {
763                    let child = context.ordered(NodeStep::TupleElement(index), element)?;
764                    self.v4_type(&child, element)?;
765                }
766            }
767            _ => {}
768        }
769        Ok(())
770    }
771
772    fn v4_value_definition(
773        &mut self,
774        context: &WalkContext,
775        definition: &v4::ValueDefinition,
776    ) -> Result<(), NodeResolutionError> {
777        for (name, ty) in &definition.input_types {
778            self.v4_type(
779                &context.named(NodeStep::ValueInputType(parse_name(name)?)),
780                ty,
781            )?;
782        }
783        if let Some(output) = &definition.output_type {
784            self.v4_type(&context.named(NodeStep::ValueOutputType), output)?;
785        }
786        match &definition.body {
787            v4::ValueBody::Expression(body) => {
788                self.v4_value(&context.named(NodeStep::Body), body)?
789            }
790            v4::ValueBody::External {
791                fallback: Some(body),
792                ..
793            } => self.v4_value(&context.named(NodeStep::ExternalFallback), body)?,
794            v4::ValueBody::Incomplete {
795                partial_body,
796                incompleteness,
797            } => {
798                if let Some(body) = partial_body {
799                    self.v4_value(&context.named(NodeStep::IncompletePartialBody), body)?;
800                }
801                if let v4::Incompleteness::Hole {
802                    partial_body: Some(ty),
803                    ..
804                } = incompleteness
805                {
806                    self.v4_type(&context.named(NodeStep::HoleExpectedType), ty)?;
807                }
808            }
809            v4::ValueBody::Native { .. } | v4::ValueBody::External { fallback: None, .. } => {}
810        }
811        Ok(())
812    }
813
814    fn v4_value_specification(
815        &mut self,
816        context: &WalkContext,
817        specification: &v4::ValueSpecification,
818    ) -> Result<(), NodeResolutionError> {
819        self.v4_annotations(context, &specification.annotations)?;
820        for (name, ty) in &specification.inputs {
821            self.v4_type(
822                &context.named(NodeStep::ValueInputType(parse_name(name)?)),
823                ty,
824            )?;
825        }
826        self.v4_type(
827            &context.named(NodeStep::ValueOutputType),
828            &specification.output,
829        )
830    }
831
832    fn v4_annotations(
833        &mut self,
834        context: &WalkContext,
835        annotations: &v4::Annotations,
836    ) -> Result<(), NodeResolutionError> {
837        for (index, entry) in annotations.entries.iter().enumerate() {
838            let entry_context = context.ordered(NodeStep::AnnotationEntry(index), entry)?;
839            let args = match entry {
840                v4::Annotation::Structured { args, .. }
841                | v4::Annotation::LinkedStructured { args, .. }
842                | v4::Annotation::PendingStructured { args, .. } => args,
843                _ => continue,
844            };
845            for (index, arg) in args.iter().enumerate() {
846                let value = match arg {
847                    v4::AnnotationArgument::Positional(value)
848                    | v4::AnnotationArgument::Named { value, .. } => value,
849                };
850                let arg_context =
851                    entry_context.ordered(NodeStep::AnnotationArgument(index), value)?;
852                self.v4_value(&arg_context, value)?;
853            }
854        }
855        Ok(())
856    }
857
858    fn v4_value(
859        &mut self,
860        context: &WalkContext,
861        value: &v4::Value,
862    ) -> Result<(), NodeResolutionError> {
863        self.add(context, IndexedNodeKind::ValueExpression, value)?;
864        if let Some(inferred) = &value.attributes().inferred_type {
865            self.v4_type(&context.named(NodeStep::InferredType), inferred)?;
866        }
867        match value {
868            v4::Value::Apply(_, function, argument) => {
869                self.v4_value(&context.named(NodeStep::ApplyFunction), function)?;
870                self.v4_value(&context.named(NodeStep::ApplyArgument), argument)?;
871            }
872            v4::Value::Field(_, subject, _) => {
873                self.v4_value(&context.named(NodeStep::FieldSubject), subject)?
874            }
875            v4::Value::Destructure(_, pattern, subject, body) => {
876                self.v4_pattern(&context.named(NodeStep::DestructurePattern), pattern)?;
877                self.v4_value(&context.named(NodeStep::DestructureValue), subject)?;
878                self.v4_value(&context.named(NodeStep::DestructureBody), body)?;
879            }
880            v4::Value::IfThenElse(_, condition, then_value, else_value) => {
881                self.v4_value(&context.named(NodeStep::IfCondition), condition)?;
882                self.v4_value(&context.named(NodeStep::IfThen), then_value)?;
883                self.v4_value(&context.named(NodeStep::IfElse), else_value)?;
884            }
885            v4::Value::Lambda(_, pattern, body) => {
886                self.v4_pattern(&context.named(NodeStep::LambdaPattern), pattern)?;
887                self.v4_value(&context.named(NodeStep::LambdaBody), body)?;
888            }
889            v4::Value::LetDefinition(_, name, definition, body) => {
890                let child = context.named(NodeStep::LetDefinition(name.clone()));
891                self.add(
892                    &child,
893                    IndexedNodeKind::ValueDefinition,
894                    definition.as_ref(),
895                )?;
896                self.v4_value_definition(&child, definition)?;
897                self.v4_value(&context.named(NodeStep::LetBody), body)?;
898            }
899            v4::Value::LetRecursion(_, definitions, body) => {
900                for binding in definitions {
901                    let child = context.named(NodeStep::LetDefinition(binding.name().clone()));
902                    self.add(
903                        &child,
904                        IndexedNodeKind::ValueDefinition,
905                        binding.definition(),
906                    )?;
907                    self.v4_value_definition(&child, binding.definition())?;
908                }
909                self.v4_value(&context.named(NodeStep::LetBody), body)?;
910            }
911            v4::Value::List(_, elements) => {
912                for (index, element) in elements.iter().enumerate() {
913                    let child = context.ordered(NodeStep::ListElement(index), element)?;
914                    self.v4_value(&child, element)?;
915                }
916            }
917            v4::Value::Record(_, fields) => {
918                for field in fields {
919                    self.v4_value(
920                        &context.named(NodeStep::RecordField(field.name().clone())),
921                        field.value(),
922                    )?;
923                }
924            }
925            v4::Value::Tuple(_, elements) => {
926                for (index, element) in elements.iter().enumerate() {
927                    let child = context.ordered(NodeStep::TupleElement(index), element)?;
928                    self.v4_value(&child, element)?;
929                }
930            }
931            v4::Value::PatternMatch(_, subject, cases) => {
932                self.v4_value(&context.named(NodeStep::PatternMatchSubject), subject)?;
933                for (index, case) in cases.iter().enumerate() {
934                    let case_content = (case.pattern(), case.body());
935                    let pattern =
936                        context.ordered(NodeStep::PatternMatchCasePattern(index), &case_content)?;
937                    self.v4_pattern(&pattern, case.pattern())?;
938                    let body =
939                        context.ordered(NodeStep::PatternMatchCaseBody(index), &case_content)?;
940                    self.v4_value(&body, case.body())?;
941                }
942            }
943            v4::Value::UpdateRecord(_, subject, fields) => {
944                self.v4_value(&context.named(NodeStep::UpdateSubject), subject)?;
945                for field in fields {
946                    self.v4_value(
947                        &context.named(NodeStep::UpdateField(field.name().clone())),
948                        field.value(),
949                    )?;
950                }
951            }
952            v4::Value::Hole(_, _, Some(expected)) => {
953                self.v4_type(&context.named(NodeStep::HoleExpectedType), expected)?
954            }
955            v4::Value::Literal(_, _)
956            | v4::Value::Constructor(_, _)
957            | v4::Value::Variable(_, _)
958            | v4::Value::Reference(_, _)
959            | v4::Value::FieldFunction(_, _)
960            | v4::Value::Unit(_)
961            | v4::Value::Hole(_, _, None) => {}
962        }
963        Ok(())
964    }
965
966    fn v4_pattern(
967        &mut self,
968        context: &WalkContext,
969        pattern: &v4::Pattern,
970    ) -> Result<(), NodeResolutionError> {
971        self.add(context, IndexedNodeKind::Pattern, pattern)?;
972        if let Some(inferred) = &pattern.attributes().inferred_type {
973            self.v4_type(&context.named(NodeStep::InferredType), inferred)?;
974        }
975        match pattern {
976            v4::Pattern::AsPattern(_, child, _) => {
977                self.v4_pattern(&context.named(NodeStep::AsPatternChild), child)?
978            }
979            v4::Pattern::TuplePattern(_, children) => {
980                for (index, child) in children.iter().enumerate() {
981                    let path = context.ordered(NodeStep::PatternTupleElement(index), child)?;
982                    self.v4_pattern(&path, child)?;
983                }
984            }
985            v4::Pattern::ConstructorPattern(_, _, children) => {
986                for (index, child) in children.iter().enumerate() {
987                    let path =
988                        context.ordered(NodeStep::PatternConstructorArgument(index), child)?;
989                    self.v4_pattern(&path, child)?;
990                }
991            }
992            v4::Pattern::HeadTailPattern(_, head, tail) => {
993                self.v4_pattern(&context.named(NodeStep::HeadTailHead), head)?;
994                self.v4_pattern(&context.named(NodeStep::HeadTailTail), tail)?;
995            }
996            v4::Pattern::WildcardPattern(_)
997            | v4::Pattern::EmptyListPattern(_)
998            | v4::Pattern::LiteralPattern(_, _)
999            | v4::Pattern::UnitPattern(_) => {}
1000        }
1001        Ok(())
1002    }
1003
1004    fn v3_definition_package(
1005        &mut self,
1006        owner: NodeOwner,
1007        package: &classic::PackageDefinition<classic::Attrs, classic::Type<classic::Attrs>>,
1008    ) -> Result<(), NodeResolutionError> {
1009        for entry in &package.modules {
1010            let module = classic_path(&entry.path)?;
1011            self.add(
1012                &WalkContext::root(NodeRoot::Module {
1013                    owner: owner.clone(),
1014                    module: module.clone(),
1015                }),
1016                IndexedNodeKind::Module,
1017                &entry.definition.value,
1018            )?;
1019            for (name, controlled) in &entry.definition.value.types {
1020                let context = WalkContext::root(NodeRoot::Type {
1021                    owner: owner.clone(),
1022                    module: module.clone(),
1023                    name: classic_name(name)?,
1024                });
1025                self.add(
1026                    &context,
1027                    IndexedNodeKind::TypeDefinition,
1028                    &controlled.value.value,
1029                )?;
1030                self.v3_type_definition(&context, &controlled.value.value)?;
1031            }
1032            for (name, controlled) in &entry.definition.value.values {
1033                let context = WalkContext::root(NodeRoot::Value {
1034                    owner: owner.clone(),
1035                    module: module.clone(),
1036                    name: classic_name(name)?,
1037                });
1038                self.add(
1039                    &context,
1040                    IndexedNodeKind::ValueDefinition,
1041                    &controlled.value.value,
1042                )?;
1043                self.v3_value_definition(&context, &controlled.value.value)?;
1044            }
1045        }
1046        Ok(())
1047    }
1048
1049    fn v3_specification_package(
1050        &mut self,
1051        owner: NodeOwner,
1052        package: &classic::PackageSpecification<classic::Attrs>,
1053    ) -> Result<(), NodeResolutionError> {
1054        for entry in &package.modules {
1055            let module = classic_path(&entry.path)?;
1056            self.add(
1057                &WalkContext::root(NodeRoot::Module {
1058                    owner: owner.clone(),
1059                    module: module.clone(),
1060                }),
1061                IndexedNodeKind::Module,
1062                &entry.specification,
1063            )?;
1064            for (name, documented) in &entry.specification.types {
1065                let context = WalkContext::root(NodeRoot::Type {
1066                    owner: owner.clone(),
1067                    module: module.clone(),
1068                    name: classic_name(name)?,
1069                });
1070                self.add(&context, IndexedNodeKind::TypeDefinition, &documented.value)?;
1071                self.v3_type_specification(&context, &documented.value)?;
1072            }
1073            for (name, documented) in &entry.specification.values {
1074                let context = WalkContext::root(NodeRoot::Value {
1075                    owner: owner.clone(),
1076                    module: module.clone(),
1077                    name: classic_name(name)?,
1078                });
1079                self.add(
1080                    &context,
1081                    IndexedNodeKind::ValueDefinition,
1082                    &documented.value,
1083                )?;
1084                for input in &documented.value.inputs {
1085                    self.v3_type(
1086                        &context.named(NodeStep::ValueInputType(classic_name(&input.name)?)),
1087                        &input.ty,
1088                    )?;
1089                }
1090                self.v3_type(
1091                    &context.named(NodeStep::ValueOutputType),
1092                    &documented.value.output,
1093                )?;
1094            }
1095        }
1096        Ok(())
1097    }
1098
1099    fn v3_type_definition(
1100        &mut self,
1101        context: &WalkContext,
1102        definition: &classic::TypeDefinition<classic::Attrs>,
1103    ) -> Result<(), NodeResolutionError> {
1104        match definition {
1105            classic::TypeDefinition::Alias(_, ty) => {
1106                self.v3_type(&context.named(NodeStep::TypeExpression), ty)?
1107            }
1108            classic::TypeDefinition::Custom(_, controlled) => {
1109                self.v3_constructors(context, &controlled.value)?
1110            }
1111        }
1112        Ok(())
1113    }
1114
1115    fn v3_type_specification(
1116        &mut self,
1117        context: &WalkContext,
1118        specification: &classic::TypeSpecification<classic::Attrs>,
1119    ) -> Result<(), NodeResolutionError> {
1120        match specification {
1121            classic::TypeSpecification::Alias(_, ty) => {
1122                self.v3_type(&context.named(NodeStep::TypeExpression), ty)?
1123            }
1124            classic::TypeSpecification::Custom(_, constructors) => {
1125                self.v3_constructors(context, constructors)?
1126            }
1127            classic::TypeSpecification::Derived(_, configuration) => self.v3_type(
1128                &context.named(NodeStep::DerivedBaseType),
1129                &configuration.base_type,
1130            )?,
1131            classic::TypeSpecification::Opaque(_) => {}
1132        }
1133        Ok(())
1134    }
1135
1136    fn v3_constructors(
1137        &mut self,
1138        context: &WalkContext,
1139        constructors: &[classic::Constructor<classic::Attrs>],
1140    ) -> Result<(), NodeResolutionError> {
1141        for constructor in constructors {
1142            let child = context.named(NodeStep::CustomConstructor(classic_name(
1143                &constructor.name,
1144            )?));
1145            self.add(&child, IndexedNodeKind::Constructor, constructor)?;
1146            for (index, (_, ty)) in constructor.args.iter().enumerate() {
1147                let argument = child.ordered(NodeStep::ConstructorArgument(index), ty)?;
1148                self.v3_type(&argument, ty)?;
1149            }
1150        }
1151        Ok(())
1152    }
1153
1154    fn v3_value_definition(
1155        &mut self,
1156        context: &WalkContext,
1157        definition: &classic::ValueDefinition<classic::Attrs, classic::Type<classic::Attrs>>,
1158    ) -> Result<(), NodeResolutionError> {
1159        for input in &definition.input_types {
1160            self.v3_type(
1161                &context.named(NodeStep::ValueInputType(classic_name(&input.name)?)),
1162                &input.ty,
1163            )?;
1164            self.v3_type(
1165                &context.named(NodeStep::ValueInputAnnotation(classic_name(&input.name)?)),
1166                &input.annotation,
1167            )?;
1168        }
1169        self.v3_type(
1170            &context.named(NodeStep::ValueOutputType),
1171            &definition.output_type,
1172        )?;
1173        self.v3_value(&context.named(NodeStep::Body), &definition.body)
1174    }
1175
1176    fn v3_type(
1177        &mut self,
1178        context: &WalkContext,
1179        ty: &classic::Type<classic::Attrs>,
1180    ) -> Result<(), NodeResolutionError> {
1181        self.add(context, IndexedNodeKind::TypeExpression, ty)?;
1182        match ty {
1183            classic::Type::Record(_, fields) => {
1184                for field in fields {
1185                    self.v3_type(
1186                        &context.named(NodeStep::RecordField(classic_name(&field.name)?)),
1187                        &field.ty,
1188                    )?;
1189                }
1190            }
1191            classic::Type::ExtensibleRecord(_, _, fields) => {
1192                for field in fields {
1193                    self.v3_type(
1194                        &context.named(NodeStep::ExtensibleRecordField(classic_name(&field.name)?)),
1195                        &field.ty,
1196                    )?;
1197                }
1198            }
1199            classic::Type::Function(_, parameter, result) => {
1200                self.v3_type(&context.named(NodeStep::TypeFunctionParameter), parameter)?;
1201                self.v3_type(&context.named(NodeStep::TypeFunctionResult), result)?;
1202            }
1203            classic::Type::Reference(_, _, arguments) => {
1204                for (index, argument) in arguments.iter().enumerate() {
1205                    let child = context.ordered(NodeStep::ReferenceArgument(index), argument)?;
1206                    self.v3_type(&child, argument)?;
1207                }
1208            }
1209            classic::Type::Tuple(_, elements) => {
1210                for (index, element) in elements.iter().enumerate() {
1211                    let child = context.ordered(NodeStep::TupleElement(index), element)?;
1212                    self.v3_type(&child, element)?;
1213                }
1214            }
1215            _ => {}
1216        }
1217        Ok(())
1218    }
1219
1220    fn v3_value(
1221        &mut self,
1222        context: &WalkContext,
1223        value: &classic::Value<classic::Attrs, classic::Type<classic::Attrs>>,
1224    ) -> Result<(), NodeResolutionError> {
1225        self.add(context, IndexedNodeKind::ValueExpression, value)?;
1226        match value {
1227            classic::Value::Apply(_, function, argument) => {
1228                self.v3_value(&context.named(NodeStep::ApplyFunction), function)?;
1229                self.v3_value(&context.named(NodeStep::ApplyArgument), argument)?;
1230            }
1231            classic::Value::Field(_, subject, _) => {
1232                self.v3_value(&context.named(NodeStep::FieldSubject), subject)?
1233            }
1234            classic::Value::Destructure(_, pattern, subject, body) => {
1235                self.v3_pattern(&context.named(NodeStep::DestructurePattern), pattern)?;
1236                self.v3_value(&context.named(NodeStep::DestructureValue), subject)?;
1237                self.v3_value(&context.named(NodeStep::DestructureBody), body)?;
1238            }
1239            classic::Value::IfThenElse(_, condition, then_value, else_value) => {
1240                self.v3_value(&context.named(NodeStep::IfCondition), condition)?;
1241                self.v3_value(&context.named(NodeStep::IfThen), then_value)?;
1242                self.v3_value(&context.named(NodeStep::IfElse), else_value)?;
1243            }
1244            classic::Value::Lambda(_, pattern, body) => {
1245                self.v3_pattern(&context.named(NodeStep::LambdaPattern), pattern)?;
1246                self.v3_value(&context.named(NodeStep::LambdaBody), body)?;
1247            }
1248            classic::Value::LetDefinition(_, name, definition, body) => {
1249                let child = context.named(NodeStep::LetDefinition(classic_name(name)?));
1250                self.add(
1251                    &child,
1252                    IndexedNodeKind::ValueDefinition,
1253                    definition.as_ref(),
1254                )?;
1255                self.v3_value_definition(&child, definition)?;
1256                self.v3_value(&context.named(NodeStep::LetBody), body)?;
1257            }
1258            classic::Value::LetRecursion(_, definitions, body) => {
1259                for (name, definition) in definitions {
1260                    let child = context.named(NodeStep::LetDefinition(classic_name(name)?));
1261                    self.add(&child, IndexedNodeKind::ValueDefinition, definition)?;
1262                    self.v3_value_definition(&child, definition)?;
1263                }
1264                self.v3_value(&context.named(NodeStep::LetBody), body)?;
1265            }
1266            classic::Value::List(_, elements) => {
1267                for (index, element) in elements.iter().enumerate() {
1268                    let child = context.ordered(NodeStep::ListElement(index), element)?;
1269                    self.v3_value(&child, element)?;
1270                }
1271            }
1272            classic::Value::Record(_, fields) => {
1273                for (name, value) in fields {
1274                    self.v3_value(
1275                        &context.named(NodeStep::RecordField(classic_name(name)?)),
1276                        value,
1277                    )?;
1278                }
1279            }
1280            classic::Value::Tuple(_, elements) => {
1281                for (index, element) in elements.iter().enumerate() {
1282                    let child = context.ordered(NodeStep::TupleElement(index), element)?;
1283                    self.v3_value(&child, element)?;
1284                }
1285            }
1286            classic::Value::PatternMatch(_, subject, cases) => {
1287                self.v3_value(&context.named(NodeStep::PatternMatchSubject), subject)?;
1288                for (index, (pattern, body)) in cases.iter().enumerate() {
1289                    let pattern_context = context
1290                        .ordered(NodeStep::PatternMatchCasePattern(index), &(pattern, body))?;
1291                    self.v3_pattern(&pattern_context, pattern)?;
1292                    let body_context =
1293                        context.ordered(NodeStep::PatternMatchCaseBody(index), &(pattern, body))?;
1294                    self.v3_value(&body_context, body)?;
1295                }
1296            }
1297            classic::Value::Update(_, subject, fields) => {
1298                self.v3_value(&context.named(NodeStep::UpdateSubject), subject)?;
1299                for (name, value) in fields {
1300                    self.v3_value(
1301                        &context.named(NodeStep::UpdateField(classic_name(name)?)),
1302                        value,
1303                    )?;
1304                }
1305            }
1306            classic::Value::Constructor(_, _)
1307            | classic::Value::FieldFunction(_, _)
1308            | classic::Value::Literal(_, _)
1309            | classic::Value::Unit(_)
1310            | classic::Value::Variable(_, _)
1311            | classic::Value::Reference(_, _) => {}
1312        }
1313        Ok(())
1314    }
1315
1316    fn v3_pattern(
1317        &mut self,
1318        context: &WalkContext,
1319        pattern: &classic::Pattern<classic::Type<classic::Attrs>>,
1320    ) -> Result<(), NodeResolutionError> {
1321        self.add(context, IndexedNodeKind::Pattern, pattern)?;
1322        match pattern {
1323            classic::Pattern::As(_, child, _) => {
1324                self.v3_pattern(&context.named(NodeStep::AsPatternChild), child)?
1325            }
1326            classic::Pattern::Tuple(_, children) => {
1327                for (index, child) in children.iter().enumerate() {
1328                    let path = context.ordered(NodeStep::PatternTupleElement(index), child)?;
1329                    self.v3_pattern(&path, child)?;
1330                }
1331            }
1332            classic::Pattern::Constructor(_, _, children) => {
1333                for (index, child) in children.iter().enumerate() {
1334                    let path =
1335                        context.ordered(NodeStep::PatternConstructorArgument(index), child)?;
1336                    self.v3_pattern(&path, child)?;
1337                }
1338            }
1339            classic::Pattern::HeadTail(_, head, tail) => {
1340                self.v3_pattern(&context.named(NodeStep::HeadTailHead), head)?;
1341                self.v3_pattern(&context.named(NodeStep::HeadTailTail), tail)?;
1342            }
1343            classic::Pattern::Wildcard(_)
1344            | classic::Pattern::EmptyList(_)
1345            | classic::Pattern::Literal(_, _)
1346            | classic::Pattern::Unit(_) => {}
1347        }
1348        Ok(())
1349    }
1350}
1351
1352fn parse_package(text: &str) -> Result<PackageName, NodeResolutionError> {
1353    let package =
1354        PackageName::from_canonical_string(text).map_err(NodeResolutionError::InvalidName)?;
1355    if package.to_canonical_string() != text || package.is_empty() {
1356        return Err(NodeResolutionError::InvalidName(text.to_owned()));
1357    }
1358    Ok(package)
1359}
1360
1361fn parse_path(text: &str) -> Result<Path, NodeResolutionError> {
1362    let path = Path::from_canonical_string(text).map_err(NodeResolutionError::InvalidName)?;
1363    if path.to_canonical_string() != text || path.is_empty() {
1364        return Err(NodeResolutionError::InvalidName(text.to_owned()));
1365    }
1366    Ok(path)
1367}
1368
1369fn parse_name(text: &str) -> Result<Name, NodeResolutionError> {
1370    let name = Name::from_canonical_string(text).map_err(NodeResolutionError::InvalidName)?;
1371    if name.to_canonical_string() != text {
1372        return Err(NodeResolutionError::InvalidName(text.to_owned()));
1373    }
1374    Ok(name)
1375}
1376
1377fn classic_name(name: &classic::Name) -> Result<Name, NodeResolutionError> {
1378    let words = name
1379        .words
1380        .iter()
1381        .map(|word| crate::naming::resolve(*word).to_string())
1382        .collect::<Vec<_>>();
1383    let name = Name::from_words(words);
1384    Name::from_canonical_string(&name.to_canonical_string())
1385        .map_err(NodeResolutionError::InvalidName)
1386}
1387
1388fn classic_path(path: &classic::Path) -> Result<Path, NodeResolutionError> {
1389    Ok(Path {
1390        segments: path
1391            .segments
1392            .iter()
1393            .map(classic_name)
1394            .collect::<Result<Vec<_>, _>>()?,
1395    })
1396}