mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-14 23:53:47 +00:00
IC: don't mutate loaded types in handleGenericInvocation
When a generic's body is computed by a macro (Bar[T, U] = makeBar(T, U)), `newbody` after replaceTypeVarsT can be a type loaded from a dep module - even a builtin like `int` - which is Sealed under IC: - the in-place flag accumulation `newbody.flags = newbody.flags + ...` asserted (and under non-IC silently pollutes the shared type's flags, e.g. the global `int`); compute the flags into a local, skip the in-place store for Sealed types and feed `result.flags` from the local - value-identical for the instance. - `newbody.typeInst = result` likewise; a loaded body keeps whatever its defining module serialized (the field was first-wins anyway). Both changes are no-ops for non-IC (types are never Sealed there). Fixes tmacrogenerics. Macro sweep 93/95 - the two remaining fails are tmacro7 (disabled test, fails identically under non-IC) and tmacrogetimpl (needs a design decision on getImplTransformed sym sharing). tests/ic 5/5, koch boot -d:release and clean koch bootic both reach bit-identical fixed points. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -503,8 +503,14 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
let bbody = last body
|
||||
var newbody = replaceTypeVarsT(cl, bbody, isInstValue = true)
|
||||
cl.skipTypedesc = oldSkipTypedesc
|
||||
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
|
||||
result.flags = result.flags + newbody.flags - tfInstClearedFlags
|
||||
let newbodyFlags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
|
||||
if newbody.state != Sealed:
|
||||
newbody.flags = newbodyFlags
|
||||
# else: `newbody` is a type loaded from a dep module (it can even be a
|
||||
# builtin like `int` when the generic's body is computed by a macro) and is
|
||||
# immutable under IC. Skip the in-place flag accumulation on the shared
|
||||
# type; the instance `result` still receives the flags below.
|
||||
result.flags = result.flags + newbodyFlags - tfInstClearedFlags
|
||||
|
||||
setToPreviousLayer(cl.typeMap)
|
||||
|
||||
@@ -524,8 +530,11 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
# generics *when the type is constructed*:
|
||||
cl.c.graph.setAttachedOp(cl.c.module.position, newbody, attachedDeepCopy,
|
||||
cl.c.instTypeBoundOp(cl.c, dc, result, cl.info, attachedDeepCopy, 1))
|
||||
if newbody.typeInst == nil:
|
||||
if newbody.typeInst == nil and newbody.state != Sealed:
|
||||
# doAssert newbody.typeInst == nil
|
||||
# An IC-loaded (Sealed) `newbody` keeps whatever `typeInst` its defining
|
||||
# module serialized; recording this process's first instantiation on the
|
||||
# shared type is not possible (and was always first-wins anyway).
|
||||
newbody.typeInst = result
|
||||
if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst:
|
||||
# can come here for tyGenericInst too, see tests/metatype/ttypeor.nim
|
||||
|
||||
Reference in New Issue
Block a user