fixes #22479; WIP [backport]

This commit is contained in:
Araq
2024-06-13 16:18:30 +02:00
parent 0b5a938f57
commit 9172d26870
3 changed files with 45 additions and 32 deletions

View File

@@ -251,11 +251,11 @@ proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode
c.genOp(op, dest)
proc genDestroy(c: var Con; dest: PNode): PNode =
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
let t = dest.typ.skipTypes({tyAlias, tySink})
result = c.genOp(t, attachedDestructor, dest, nil)
proc canBeMoved(c: Con; t: PType): bool {.inline.} =
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
let t = t.skipTypes({tyAlias, tySink})
if optOwnedRefs in c.graph.config.globalOptions:
result = t.kind != tyRef and getAttachedOp(c.graph, t, attachedSink) != nil
else:
@@ -281,7 +281,7 @@ proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFla
# optimize sink call into a bitwise memcopy
result = newTree(nkFastAsgn, dest, ri)
else:
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
let t = dest.typ.skipTypes({tyAlias, tySink})
if getAttachedOp(c.graph, t, attachedSink) != nil:
result = c.genOp(t, attachedSink, dest, ri)
result.add ri
@@ -335,7 +335,7 @@ proc genMarkCyclic(c: var Con; result, dest: PNode) =
result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, xenv)
proc genCopyNoCheck(c: var Con; dest, ri: PNode; a: TTypeAttachedOp): PNode =
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
let t = dest.typ.skipTypes({tyAlias, tySink})
result = c.genOp(t, a, dest, ri)
assert ri.typ != nil
@@ -391,7 +391,7 @@ It is best to factor out piece of object that needs custom destructor into separ
result.add newTree(nkFastAsgn, le, tmp)
proc genWasMoved(c: var Con, n: PNode): PNode =
let typ = n.typ.skipTypes({tyGenericInst, tyAlias, tySink})
let typ = n.typ.skipTypes({tyAlias, tySink})
let op = getAttachedOp(c.graph, n.typ, attachedWasMoved)
if op != nil:
if sfError in op.flags:
@@ -449,7 +449,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
let nTyp = n.typ.skipTypes(tyUserTypeClasses)
let tmp = c.getTemp(s, nTyp, n.info)
if hasDestructor(c, nTyp):
let typ = nTyp.skipTypes({tyGenericInst, tyAlias, tySink})
let typ = nTyp.skipTypes({tyAlias, tySink})
let op = getAttachedOp(c.graph, typ, attachedDup)
if op != nil and tfHasOwned notin typ.flags:
if sfError in op.flags:

View File

@@ -38,7 +38,7 @@ template assignment*(t: PType): PSym = getAttachedOp(c.g, t, attachedAsgn)
template dup*(t: PType): PSym = getAttachedOp(c.g, t, attachedDup)
template asink*(t: PType): PSym = getAttachedOp(c.g, t, attachedSink)
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode)
proc fillBody(c: var TLiftCtx; orig: PType; body, x, y: PNode)
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator; isDistinct = false): PSym
@@ -363,7 +363,7 @@ proc instantiateGeneric(c: var TLiftCtx; op: PSym; t, typeInst: PType): PSym =
"cannot generate destructor for generic type: " & typeToString(t))
result = nil
proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
proc considerAsgnOrSink(c: var TLiftCtx; orig, t: PType; body, x, y: PNode;
field: var PSym): bool =
if optSeqDestructors in c.g.config.globalOptions:
var op = field
@@ -403,7 +403,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
onUse(c.info, op)
# We also now do generic instantiations in the destructor lifting pass:
if op.ast.isGenericRoutine:
op = instantiateGeneric(c, op, t, t.typeInst)
op = instantiateGeneric(c, op, t, orig)
field = op
#echo "trying to use ", op.ast
#echo "for ", op.name.s, " "
@@ -422,8 +422,8 @@ proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
if op != nil and sfOverridden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
op = instantiateGeneric(c, op, t, t.typeInst)
setAttachedOp(c.g, c.idgen.module, t, attachedDestructor, op)
op = instantiateGeneric(c, op, t, orig)
setAttachedOp(c.g, c.idgen.module, orig, attachedDestructor, op)
if op == nil and (useNoGc(c, t) or requiresDestructor(c, t)):
op = produceSym(c.g, c.c, t, attachedDestructor, c.info, c.idgen)
@@ -438,7 +438,7 @@ proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
internalError(c.g.config, c.info,
"type-bound operator could not be resolved")
proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
proc considerUserDefinedOp(c: var TLiftCtx; orig, t: PType; body, x, y: PNode): bool =
case c.kind
of attachedDestructor:
var op = t.destructor
@@ -446,8 +446,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
if op.ast.isGenericRoutine:
# patch generic destructor:
op = instantiateGeneric(c, op, t, t.typeInst)
setAttachedOp(c.g, c.idgen.module, t, attachedDestructor, op)
op = instantiateGeneric(c, op, t, orig)
setAttachedOp(c.g, c.idgen.module, orig, attachedDestructor, op)
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op)
@@ -461,10 +461,10 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
if op != nil and sfOverridden in op.flags:
if op.ast.isGenericRoutine:
# patch generic =trace:
op = instantiateGeneric(c, op, t, t.typeInst)
op = instantiateGeneric(c, op, t, orig)
setAttachedOp(c.g, c.idgen.module, t, c.kind, op)
result = considerAsgnOrSink(c, t, body, x, y, op)
result = considerAsgnOrSink(c, orig, t, body, x, y, op)
if op != nil:
setAttachedOp(c.g, c.idgen.module, t, c.kind, op)
@@ -484,7 +484,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
if op.ast.isGenericRoutine:
# patch generic destructor:
op = instantiateGeneric(c, op, t, t.typeInst)
op = instantiateGeneric(c, op, t, orig)
setAttachedOp(c.g, c.idgen.module, t, attachedWasMoved, op)
#markUsed(c.g.config, c.info, op, c.g.usageSym)
@@ -500,7 +500,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
if op.ast.isGenericRoutine:
# patch generic destructor:
op = instantiateGeneric(c, op, t, t.typeInst)
op = instantiateGeneric(c, op, t, orig)
setAttachedOp(c.g, c.idgen.module, t, attachedDup, op)
#markUsed(c.g.config, c.info, op, c.g.usageSym)
@@ -948,7 +948,8 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
proc fillBody(c: var TLiftCtx; orig: PType; body, x, y: PNode) =
let t = orig.skipTypes({tyGenericInst, tyAlias})
case t.kind
of tyNone, tyEmpty, tyVoid: discard
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCstring,
@@ -994,7 +995,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
elif optSeqDestructors in c.g.config.globalOptions:
# note that tfHasAsgn is propagated so we need the check on
# 'selectedGC' here to determine if we have the new runtime.
discard considerUserDefinedOp(c, t, body, x, y)
discard considerUserDefinedOp(c, orig, t, body, x, y)
elif tfHasAsgn in t.flags:
if c.kind in {attachedAsgn, attachedSink, attachedDeepCopy}:
body.add newSeqCall(c, x, y)
@@ -1005,11 +1006,11 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if useNoGc(c, t):
useSeqOrStrOp(c, t, body, x, y)
elif tfHasAsgn in t.flags:
discard considerUserDefinedOp(c, t, body, x, y)
discard considerUserDefinedOp(c, orig, t, body, x, y)
else:
defaultOp(c, t, body, x, y)
of tyObject:
if not considerUserDefinedOp(c, t, body, x, y):
if not considerUserDefinedOp(c, orig, t, body, x, y):
if t.sym != nil and sfImportc in t.sym.flags:
case c.kind
of {attachedAsgn, attachedSink, attachedDup}:
@@ -1030,7 +1031,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
else:
fillBodyObjT(c, t, body, x, y)
of tyDistinct:
if not considerUserDefinedOp(c, t, body, x, y):
if not considerUserDefinedOp(c, orig, t, body, x, y):
fillBody(c, t.elementType, body, x, y)
of tyTuple:
fillBodyTup(c, t, body, x, y)
@@ -1046,10 +1047,9 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
tyTypeDesc, tyGenericInvocation, tyForward, tyStatic:
#internalError(c.g.config, c.info, "assignment requested for type: " & typeToString(t))
discard
of tyOrdinal, tyRange, tyInferred,
tyGenericInst, tyAlias, tySink:
of tyOrdinal, tyRange, tyInferred, tySink:
fillBody(c, skipModifier(t), body, x, y)
of tyConcept, tyIterable: raiseAssert "unreachable"
of tyConcept, tyIterable, tyAlias, tyGenericInst: raiseAssert "unreachable"
proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
kind: TTypeAttachedOp; info: TLineInfo;
@@ -1247,13 +1247,13 @@ proc patchBody(g: ModuleGraph; c: PContext; n: PNode; info: TLineInfo; idgen: Id
n[0] = newSymNode(op)
for x in n: patchBody(g, c, x, info, idgen)
proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: IdGenerator;
proc inst(g: ModuleGraph; c: PContext; orig, t: PType; kind: TTypeAttachedOp; idgen: IdGenerator;
info: TLineInfo) =
let op = getAttachedOp(g, t, kind)
if op != nil and op.ast != nil and op.ast.isGenericRoutine:
if t.typeInst != nil:
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, idgen: idgen)
let opInst = instantiateGeneric(a, op, t, t.typeInst)
let opInst = instantiateGeneric(a, op, t, orig)
if opInst.ast != nil:
patchBody(g, c, opInst.ast, info, a.idgen)
setAttachedOp(g, idgen.module, t, kind, opInst)
@@ -1271,11 +1271,13 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
if orig == nil or {tfCheckedForDestructor, tfHasMeta} * orig.flags != {}: return
incl orig.flags, tfCheckedForDestructor
let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink})
let skipped = orig.skipTypes({tyAlias, tySink})
if isEmptyContainer(skipped) or skipped.kind == tyStatic: return
let h = sighashes.hashType(skipped, g.config, {CoType, CoConsiderOwned, CoDistinct})
var canon = g.canonTypes.getOrDefault(h)
#echo "NOW FOR ", typeToString(skipped), " ", canon == nil
if canon == nil:
g.canonTypes[h] = skipped
canon = skipped
@@ -1295,7 +1297,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
# bug #15122: We need to produce all prototypes before entering the
# mind boggling recursion. Hacks like these imply we should rewrite
# this module.
var generics: array[attachedWasMoved..attachedTrace, bool] = default(array[attachedWasMoved..attachedTrace, bool])
var generics = default(array[attachedWasMoved..attachedTrace, bool])
for k in attachedWasMoved..lastAttached:
generics[k] = getAttachedOp(g, canon, k) != nil
if not generics[k]:
@@ -1307,7 +1309,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
if not generics[k]:
discard produceSym(g, c, canon, k, info, idgen)
else:
inst(g, c, canon, k, idgen, info)
inst(g, c, canon, canon, k, idgen, info)
if canon != orig:
setAttachedOp(g, idgen.module, orig, k, getAttachedOp(g, canon, k))

View File

@@ -97,6 +97,17 @@ proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]; conf: Confi
else:
for i in 0..<n.len: hashTree(c, n[i], flags, conf)
#import renderer
proc hasEmptyBody(t: PType): bool =
case t.kind
of tyObject:
result = t.n.safeLen == 0
of tyTuple:
result = t.kidsLen == 0
else:
result = false
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: ConfigRef) =
if t == nil:
c &= "\254"
@@ -116,7 +127,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
else:
c.hashSym(t.sym)
of tyGenericInst:
if sfInfixCall in t.base.sym.flags:
if sfInfixCall in t.base.sym.flags or CoConsiderOwned in flags: # hasEmptyBody(t.base):
# This is an imported C++ generic type.
# We cannot trust the `lastSon` to hold a properly populated and unique
# value for each instantiation, so we hash the generic parameters here: