Skip to content

Conversation

lsrcz
Copy link
Collaborator

@lsrcz lsrcz commented Sep 1, 2025

Depends on #2975.

This pull request enhances the CloneReplacer interface by adding:

  • A pointer to the target module
  • A reference to the old_to_new mapping.

These contexts are necessary to ensure that the newly created AST nodes are associated with the correct module.

After the changes, I temporarily inserted VerifyClone after most call sites of the cloning APIs. All of them passed except for this one: https://github.com/xlsynth/xlsynth/blob/0d83df265de1dd4391cc5f30b2a232b7209da302/xls/dslx/type_system_v2/inference_table.cc#L629-L631.

This failure would happen even without this PR. I wonder if it is acceptable to create a malformed module solely for type checking, or should we fix this case as well.

@lsrcz lsrcz force-pushed the siruilu-20250830-rewriter-context branch from 0d83df2 to cf625a8 Compare September 1, 2025 20:10
@lsrcz lsrcz force-pushed the siruilu-20250830-rewriter-context branch from cf625a8 to 8c72089 Compare September 1, 2025 20:35
absl::AnyInvocable<absl::StatusOr<std::optional<AstNode*>>(const AstNode*)>;
absl::AnyInvocable<absl::StatusOr<std::optional<AstNode*>>(
const AstNode*, Module*,
const absl::flat_hash_map<const AstNode*, AstNode*>&)>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a replacer somewhere that actually wants to use the old_to_new argument?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am going to implement one using this. Basically, when we want to create a new node with some name ref, we want the reference points to something that is in the new module instead of the old one. I would love to use this mapping to resolve it.

@lsrcz
Copy link
Collaborator Author

lsrcz commented Sep 8, 2025

Update

Do not clone non-owned nodes

The core issue is that the cloner should not clone non‑owned subnodes. This has led to problems like the one addressed in #2978. I added commits that consistently avoid cloning non‑owned nodes. Concretely, for references, we either rebind to a cloned target if one exists or preserve the original pointer.

With this in place, we can remove PreserveTypeDefinitionsReplacer and most uses of ChainCloneReplacers. I realize there are cases where we may want transitive cloning of referenced nodes without cloning an entire module; please take a look and share feedback on those scenarios.

Chaining of the replacers

The new commits also refine replacer chaining. ChainCloneReplacers applies two replacers sequentially; when both fire, the “home” module for intermediate nodes is ambiguous. I found two well‑defined cases we can support safely:

  • When the two replacers are guaranteed to be mutually exclusive (only one can fire).
  • When both replacers clone into the source module rather than a distinct target module.

These cover all the remaining usages after removing PreserveTypeDefinitionsReplacer.

Threading old_to_new mapping

Previously, only the top‑level replacement was added to old_to_new, and any subnodes created inside a replacer were not recorded. I added threading of the old_to_new map so replacers can register all nodes they synthesize, enabling downstream reuse and preserving sharing.

This isn’t strictly required (DSLX ASTs are mostly trees), but it makes replacers more robust and predictable. Feedback welcome.

Alternative Design

We recognize the ownership subtleties and, in some cases, the desire for transitive cloning. If the stricter “don’t clone non‑owned nodes” policy feels too limiting, another option is to let the replacer decide case‑by‑case, potentially using extra context (e.g., type inference). One approach would be a replacer object with two callables: one for replacement and one predicate for whether a node should be cloned. Alternatively, we can keep the current “optional replacement” interface and encode that choice in the replacer’s logic. Happy to explore this further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants