diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index a2f3c94cde..15c60363f8 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -592,10 +592,12 @@ proc setLenStrCall(c: var TLiftCtx; x, y: PNode): PNode = result = genBuiltin(c, mSetLengthStr, "setLen", x) # genAddr(g, x)) result.add lenCall -proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode = +proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode; noinit = false): PNode = let lenCall = genBuiltin(c, mLengthSeq, "len", y) lenCall.typ = getSysType(c.g, x.info, tyInt) - var op = getSysMagic(c.g, x.info, "setLen", mSetLengthSeq) + let name = if noinit: "setLenUninit" else: "setLen" + let magic = if noinit: mSetLengthSeqUninit else: mSetLengthSeq + var op = getSysMagic(c.g, x.info, name, magic) op = instantiateGeneric(c, op, t, t) result = newTree(nkCall, newSymNode(op, x.info), x, lenCall) @@ -643,8 +645,9 @@ proc genBulkCopySeq(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind of attachedDup: - body.add setLenSeqCall(c, t, x, y) - if supportsCopyMem(t.elementType): + let bulkCopy = supportsCopyMem(t.elementType) + body.add setLenSeqCall(c, t, x, y, noinit = bulkCopy) + if bulkCopy: genBulkCopySeq(c, t, body, x, y) else: forallElements(c, t, body, x, y) @@ -658,8 +661,9 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # This is usually more efficient than a destroy/create pair. # For trivially copyable types, use bulk copyMem instead of element loop. checkSelfAssignment(c, t, body, x, y) - body.add setLenSeqCall(c, t, x, y) - if supportsCopyMem(t.elementType): + let bulkCopy = supportsCopyMem(t.elementType) + body.add setLenSeqCall(c, t, x, y, noinit = bulkCopy) + if bulkCopy: genBulkCopySeq(c, t, body, x, y) else: forallElements(c, t, body, x, y) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index e2f91587ff..93be5d56de 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1693,6 +1693,22 @@ proc containsGenericInvocationWithForward(n: PNode): bool = return true return false +proc containsRecWhen(n: PNode): bool = + if n == nil: + return false + case n.kind + of nkRecWhen: + return true + else: + for i in 0.. 2 and + containsRecWhen(n.sym.ast[2]) + proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = if s.typ == nil: localError(c.config, n.info, "cannot instantiate the '$1' $2" % @@ -1772,11 +1788,16 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = # XXX: What kind of error is this? is it still relevant? localError(c.config, n.info, errCannotInstantiateX % s.name.s) result = newOrPrevType(tyError, prev, c) - elif containsGenericInvocationWithForward(n[0]) or hasForwardTypeParam: - # isConcrete == false means this generic type is not instanciated here because it invoked with generic parameters. - # Even if isConcrete == true, don't instanciate it now if there are any `tyForward` type params. - # Such `tyForward` type params will be semchecked later and we can instanciate this next time. - # Some generic types like std/options.Option[T] needs a type kinds of the given type argument. + elif containsGenericInvocationWithForward(n[0]) or + (hasForwardTypeParam and requiresForwardTypeDelay(n[0])): + # isConcrete == false means this generic type is not instanciated here because + # it invoked with generic parameters. + # Even if isConcrete == true, don't instanciate it now if the type + # shape depends on unresolved `tyForward` type params. + # Such `tyForward` type params will be semchecked later and we can + # instanciate this next time. + # Some generic types like std/options.Option[T] need the kind of the + # given type argument before their fields can be resolved. # return `tyForward` instead of `tyGenericInvocation` because: # ```nim diff --git a/compiler/transf.nim b/compiler/transf.nim index 049ed4fa5b..e85ecd3e07 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -118,6 +118,24 @@ proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PNode; isFirstWrite le.flags.incl nfFirstWrite result[1] = ri +proc resolveBorrowedRoutineSym(c: PTransf; s: PSym; info: TLineInfo): PSym = + # Follow borrow aliases to the underlying implementation symbol. + var s = s + while true: + # Skips over all borrowed procs getting the last proc symbol without an implementation + let body = getBody(c.graph, s) + if body.kind == nkSym and sfBorrow in body.sym.flags and getBody(c.graph, body.sym).kind == nkSym: + s = body.sym + else: + break + + let body = getBody(c.graph, s) + if body.kind == nkSym: + result = body.sym + else: + result = nil + internalError(c.graph.config, info, "wrong AST for borrowed symbol") + proc transformSymAux(c: PTransf, n: PNode): PNode = let s = n.sym if s.typ != nil and s.typ.callConv == ccClosure: @@ -136,17 +154,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = var tc = c.transCon if sfBorrow in s.flags and s.kind in routineKinds: # simply exchange the symbol: - var s = s - while true: - # Skips over all borrowed procs getting the last proc symbol without an implementation - let body = getBody(c.graph, s) - if body.kind == nkSym and sfBorrow in body.sym.flags and getBody(c.graph, body.sym).kind == nkSym: - s = body.sym - else: - break - b = getBody(c.graph, s) - if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol") - b = newSymNode(b.sym, n.info) + b = newSymNode(resolveBorrowedRoutineSym(c, s, n.info), n.info) elif c.inlining > 0: # see bug #13596: we use ref-based equality in the DFA for destruction # injections so we need to ensure unique nodes after iterator inlining @@ -785,7 +793,9 @@ proc transformFor(c: PTransf, n: PNode): PNode = discard c.breakSyms.pop - let iter = call[0].sym + var iter = call[0].sym + if sfBorrow in iter.flags and iter.kind in routineKinds: + iter = resolveBorrowedRoutineSym(c, iter, n.info) var v = newNodeI(nkVarSection, n.info) for i in 0..