From b72affa1a1755d9b7c8f5c528c3bcfb22214b014 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 10 Jun 2026 14:53:16 +0200 Subject: [PATCH] fix arraymancer regression: gate handleGenericInvocation's copy on Sealed The early IC fix made the else branch (concrete generic args) copy the invocation type unconditionally before propagateToOwner. Besides avoiding the in-place mutation, the copy flips `header != t` for all-concrete invocations, which activates the searchInstTypes/sameFlags cached-instance return path that devel skipped - a cached, meta-flagged instance could be returned where a fresh one was expected. Arraymancer's build then failed with "cannot cast to a non concrete type: 'ptr NimSeqV2[Node[Tensor[float32]]]'" in seqs_v2.setLen. Copy only when the invocation type is actually immutable (IC-loaded/Sealed); non-IC behavior is devel's again, the IC assert stays fixed. Verified: arraymancer tests_cpu.nim builds and links (its test-suite SIGSEGV in io_npy is pre-existing - a devel-built compiler produces the identical 226-tests-then-crash). Macro sweep 93/95, tests/ic 5/5, koch boot -d:release and clean koch bootic reach bit-identical fixed points. Co-Authored-By: Claude Fable 5 --- compiler/semtypinst.nim | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 1680f38127..cf1539cf65 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -446,12 +446,13 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = header[i] = x propagateToOwner(header, x) else: - # Honor the same copy-before-mutate invariant as the branch above: never - # mutate the original invocation type `t` in place. Besides being cleaner, - # under IC `t` may be a loaded dep type (Sealed/immutable), and mutating it - # would assert. The flags propagated here end up on `header`, which is what - # is used downstream (`result.flags = header.flags`). - if header == t: header = instCopyType(cl, t) + # Under IC `t` may be a loaded dep type (Sealed/immutable); mutating it + # would assert, so propagate into a copy. For non-Sealed types keep + # devel's in-place propagation: unconditionally copying here changes + # `header != t` and with it the cached-instance lookup below, which + # regressed non-IC generic instantiations (arraymancer: a cached + # NimSeqV2 instance with stale flags was returned for a cast target). + if header == t and t.state == Sealed: header = instCopyType(cl, t) propagateToOwner(header, x) if header != t: