diff --git a/src/ir/component/concrete.rs b/src/ir/component/concrete.rs index 49120dca..bdc35636 100644 --- a/src/ir/component/concrete.rs +++ b/src/ir/component/concrete.rs @@ -188,20 +188,20 @@ impl<'a> Component<'a> { // Internal concretization logic // ============================================================ -/// Follow an `Outer` alias and return the resolved item plus a `cx` -/// re-anchored at the target's owning component, so depth=0 refs inside -/// the resolved type's body dispatch into the right index space rather -/// than the inner type-body scope `cx` was sitting in. +/// Follow an `Outer` alias once and return the resolved item plus a +/// `cx` re-anchored by this alias's depth, so depth=0 refs inside the +/// resolved item's body dispatch into the right index space. fn follow_outer_alias<'a>( alias: &ComponentAlias<'_>, cx: &VisitCtx<'a>, ) -> (ResolvedItem<'a, 'a>, VisitCtx<'a>) { let alias_ref = alias.get_item_ref().ref_; let resolved = cx.resolve(&alias_ref); - let owning_comp_uid = *cx.inner.comp_at(alias_ref.depth); - let owning_comp = cx.inner.comp_store.get(&owning_comp_uid); - let mut inner = VisitCtxInner::new(owning_comp); - inner.push_component(owning_comp); + let inner = if alias_ref.depth.val() == 0 { + cx.inner.clone() + } else { + cx.inner.at_outer_depth(alias_ref.depth) + }; (resolved, VisitCtx { inner }) } diff --git a/src/ir/component/visitor/utils.rs b/src/ir/component/visitor/utils.rs index 9f4f7bf8..667792b6 100644 --- a/src/ir/component/visitor/utils.rs +++ b/src/ir/component/visitor/utils.rs @@ -188,19 +188,19 @@ impl<'a> VisitCtxInner<'a> { debug_assert_eq!(scope_id, exited_from); } - pub(crate) fn comp_at(&self, depth: Depth) -> &CompUniqueId { - // `depth` is relative to the scope_stack (which includes both component scopes and - // type scopes), but component_stack only tracks component scopes. Subtract the number - // of type-scope levels that sit above the current component on scope_stack so that the - // index into component_stack is correct. + fn comp_idx_at(&self, depth: Depth) -> usize { let comp_depth = depth.val().saturating_sub(self.type_scope_nesting); - let idx = self.component_stack.len() - comp_depth - 1; + self.component_stack.len() - comp_depth - 1 + } + + pub(crate) fn comp_at(&self, depth: Depth) -> &CompUniqueId { + let idx = self.comp_idx_at(depth); self.component_stack.get(idx).unwrap_or_else(|| { panic!( "Internal error: couldn't find component at depth {} \ - (adjusted from scope depth {}, type_scope_nesting={}); stack: {:?}", - comp_depth, + (idx={}, type_scope_nesting={}); stack: {:?}", depth.val(), + idx, self.type_scope_nesting, self.component_stack ) @@ -214,6 +214,31 @@ impl<'a> VisitCtxInner<'a> { pub(crate) fn pop_type_body(&mut self) { self.type_body_stack.pop(); } + + /// Build a fresh inner that represents the scope `depth` levels + /// outer from the current position. + pub(crate) fn at_outer_depth(&self, depth: Depth) -> Self { + let mut new = self.clone(); + new.type_body_stack.clear(); + new.current_section_idx = None; + + for _ in 0..depth.val() { + let popped = new.scope_stack.exit_scope(); + new.node_has_nested_scope.pop(); + let popped_is_comp = new + .component_stack + .last() + .and_then(|uid| new.registry.borrow().scope_of_comp(*uid)) + == Some(popped); + if popped_is_comp { + new.component_stack.pop(); + new.section_tracker_stack.pop(); + } else { + new.type_scope_nesting = new.type_scope_nesting.saturating_sub(1); + } + } + new + } } // ===============================================