fixes #14900
This commit is contained in:
parent
cdce245a23
commit
ecf8cbbbe0
2 changed files with 62 additions and 38 deletions
|
|
@ -41,6 +41,30 @@ type
|
||||||
# means that 'x' escapes. We then destroy it
|
# means that 'x' escapes. We then destroy it
|
||||||
# in the parent's scope (and also allocate it there).
|
# in the parent's scope (and also allocate it there).
|
||||||
|
|
||||||
|
type
|
||||||
|
Con = object
|
||||||
|
owner: PSym
|
||||||
|
g: ControlFlowGraph
|
||||||
|
jumpTargets: IntSet
|
||||||
|
destroys, topLevelVars: PNode
|
||||||
|
graph: ModuleGraph
|
||||||
|
emptyNode: PNode
|
||||||
|
otherRead: PNode
|
||||||
|
inLoop, inSpawn: int
|
||||||
|
uninit: IntSet # set of uninit'ed vars
|
||||||
|
uninitComputed: bool
|
||||||
|
|
||||||
|
ProcessMode = enum
|
||||||
|
normal
|
||||||
|
consumed
|
||||||
|
sinkArg
|
||||||
|
|
||||||
|
proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
|
||||||
|
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info)
|
||||||
|
sym.typ = typ
|
||||||
|
s.vars.add(sym)
|
||||||
|
result = newSymNode(sym)
|
||||||
|
|
||||||
proc nestedScope(parent: var Scope): Scope =
|
proc nestedScope(parent: var Scope): Scope =
|
||||||
Scope(vars: @[], wasMoved: @[], final: @[], needsTry: false, parent: addr(parent))
|
Scope(vars: @[], wasMoved: @[], final: @[], needsTry: false, parent: addr(parent))
|
||||||
|
|
||||||
|
|
@ -99,7 +123,7 @@ type
|
||||||
onlyCareAboutVars,
|
onlyCareAboutVars,
|
||||||
producesValue
|
producesValue
|
||||||
|
|
||||||
proc toTree(s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode =
|
proc toTree(c: var Con; s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode =
|
||||||
if not s.needsTry: optimize(s)
|
if not s.needsTry: optimize(s)
|
||||||
assert ret != nil
|
assert ret != nil
|
||||||
if s.vars.len == 0 and s.final.len == 0 and s.wasMoved.len == 0:
|
if s.vars.len == 0 and s.final.len == 0 and s.wasMoved.len == 0:
|
||||||
|
|
@ -107,8 +131,11 @@ proc toTree(s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode =
|
||||||
result = ret
|
result = ret
|
||||||
else:
|
else:
|
||||||
let isExpr = producesValue in flags and not isEmptyType(ret.typ)
|
let isExpr = producesValue in flags and not isEmptyType(ret.typ)
|
||||||
|
var r = PNode(nil)
|
||||||
if isExpr:
|
if isExpr:
|
||||||
result = newNodeIT(nkStmtListExpr, ret.info, ret.typ)
|
result = newNodeIT(nkStmtListExpr, ret.info, ret.typ)
|
||||||
|
if ret.kind == nkStmtListExpr:
|
||||||
|
r = getTemp(c, s, ret.typ, ret.info)
|
||||||
else:
|
else:
|
||||||
result = newNodeI(nkStmtList, ret.info)
|
result = newNodeI(nkStmtList, ret.info)
|
||||||
|
|
||||||
|
|
@ -126,32 +153,15 @@ proc toTree(s: var Scope; ret: PNode; flags: set[ToTreeFlag]): PNode =
|
||||||
for m in s.wasMoved: finSection.add m
|
for m in s.wasMoved: finSection.add m
|
||||||
for i in countdown(s.final.high, 0): finSection.add s.final[i]
|
for i in countdown(s.final.high, 0): finSection.add s.final[i]
|
||||||
result.add newTryFinally(ret, finSection)
|
result.add newTryFinally(ret, finSection)
|
||||||
elif isExpr:
|
else:
|
||||||
for m in s.wasMoved: result.add m
|
if r != nil:
|
||||||
for i in countdown(s.final.high, 0): result.add s.final[i]
|
result.add newTree(nkFastAsgn, r, ret)
|
||||||
result.add ret
|
|
||||||
else:
|
else:
|
||||||
result.add ret
|
result.add ret
|
||||||
for m in s.wasMoved: result.add m
|
for m in s.wasMoved: result.add m
|
||||||
for i in countdown(s.final.high, 0): result.add s.final[i]
|
for i in countdown(s.final.high, 0): result.add s.final[i]
|
||||||
|
if r != nil:
|
||||||
type
|
result.add r
|
||||||
Con = object
|
|
||||||
owner: PSym
|
|
||||||
g: ControlFlowGraph
|
|
||||||
jumpTargets: IntSet
|
|
||||||
destroys, topLevelVars: PNode
|
|
||||||
graph: ModuleGraph
|
|
||||||
emptyNode: PNode
|
|
||||||
otherRead: PNode
|
|
||||||
inLoop, inSpawn: int
|
|
||||||
uninit: IntSet # set of uninit'ed vars
|
|
||||||
uninitComputed: bool
|
|
||||||
|
|
||||||
ProcessMode = enum
|
|
||||||
normal
|
|
||||||
consumed
|
|
||||||
sinkArg
|
|
||||||
|
|
||||||
|
|
||||||
const toDebug {.strdefine.} = ""
|
const toDebug {.strdefine.} = ""
|
||||||
|
|
@ -409,12 +419,6 @@ proc addTopVar(c: var Con; s: var Scope; v: PNode): ptr Scope =
|
||||||
result = result.parent
|
result = result.parent
|
||||||
result[].vars.add v.sym
|
result[].vars.add v.sym
|
||||||
|
|
||||||
proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
|
|
||||||
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info)
|
|
||||||
sym.typ = typ
|
|
||||||
s.vars.add(sym)
|
|
||||||
result = newSymNode(sym)
|
|
||||||
|
|
||||||
proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode =
|
proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode =
|
||||||
# discriminator is ordinal value that doesn't need sink destroy
|
# discriminator is ordinal value that doesn't need sink destroy
|
||||||
# but fields within active case branch might need destruction
|
# but fields within active case branch might need destruction
|
||||||
|
|
@ -661,7 +665,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
|
||||||
var ofScope = nestedScope(s)
|
var ofScope = nestedScope(s)
|
||||||
markEscapingVars(it[^1], ofScope)
|
markEscapingVars(it[^1], ofScope)
|
||||||
let ofResult = maybeVoid(it[^1], ofScope)
|
let ofResult = maybeVoid(it[^1], ofScope)
|
||||||
branch[^1] = toTree(ofScope, ofResult, treeFlags)
|
branch[^1] = toTree(c, ofScope, ofResult, treeFlags)
|
||||||
result.add branch
|
result.add branch
|
||||||
rememberParent(s, ofScope)
|
rememberParent(s, ofScope)
|
||||||
|
|
||||||
|
|
@ -671,7 +675,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
|
||||||
result.add p(n[0], c, s, normal)
|
result.add p(n[0], c, s, normal)
|
||||||
var bodyScope = nestedScope(s)
|
var bodyScope = nestedScope(s)
|
||||||
let bodyResult = p(n[1], c, bodyScope, normal)
|
let bodyResult = p(n[1], c, bodyScope, normal)
|
||||||
result.add toTree(bodyScope, bodyResult, treeFlags)
|
result.add toTree(c, bodyScope, bodyResult, treeFlags)
|
||||||
rememberParent(s, bodyScope)
|
rememberParent(s, bodyScope)
|
||||||
dec c.inLoop
|
dec c.inLoop
|
||||||
|
|
||||||
|
|
@ -682,7 +686,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
|
||||||
var bodyScope = nestedScope(s)
|
var bodyScope = nestedScope(s)
|
||||||
markEscapingVars(n[1], bodyScope)
|
markEscapingVars(n[1], bodyScope)
|
||||||
let bodyResult = processCall(n[1], bodyScope)
|
let bodyResult = processCall(n[1], bodyScope)
|
||||||
result.add toTree(bodyScope, bodyResult, treeFlags)
|
result.add toTree(c, bodyScope, bodyResult, treeFlags)
|
||||||
rememberParent(s, bodyScope)
|
rememberParent(s, bodyScope)
|
||||||
|
|
||||||
of nkIfStmt, nkIfExpr:
|
of nkIfStmt, nkIfExpr:
|
||||||
|
|
@ -695,12 +699,12 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
|
||||||
branchScope.parent = nil
|
branchScope.parent = nil
|
||||||
if it.kind in {nkElifBranch, nkElifExpr}:
|
if it.kind in {nkElifBranch, nkElifExpr}:
|
||||||
let cond = p(it[0], c, branchScope, normal)
|
let cond = p(it[0], c, branchScope, normal)
|
||||||
branch[0] = toTree(branchScope, cond, {producesValue, onlyCareAboutVars})
|
branch[0] = toTree(c, branchScope, cond, {producesValue, onlyCareAboutVars})
|
||||||
|
|
||||||
branchScope.parent = addr(s)
|
branchScope.parent = addr(s)
|
||||||
markEscapingVars(it[^1], branchScope)
|
markEscapingVars(it[^1], branchScope)
|
||||||
var branchResult = processCall(it[^1], branchScope)
|
var branchResult = processCall(it[^1], branchScope)
|
||||||
branch[^1] = toTree(branchScope, branchResult, treeFlags)
|
branch[^1] = toTree(c, branchScope, branchResult, treeFlags)
|
||||||
result.add branch
|
result.add branch
|
||||||
rememberParent(s, branchScope)
|
rememberParent(s, branchScope)
|
||||||
|
|
||||||
|
|
@ -710,7 +714,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
|
||||||
var tryScope = nestedScope(s)
|
var tryScope = nestedScope(s)
|
||||||
markEscapingVars(n[0], tryScope)
|
markEscapingVars(n[0], tryScope)
|
||||||
var tryResult = maybeVoid(n[0], tryScope)
|
var tryResult = maybeVoid(n[0], tryScope)
|
||||||
result.add toTree(tryScope, tryResult, treeFlags)
|
result.add toTree(c, tryScope, tryResult, treeFlags)
|
||||||
rememberParent(s, tryScope)
|
rememberParent(s, tryScope)
|
||||||
|
|
||||||
for i in 1..<n.len:
|
for i in 1..<n.len:
|
||||||
|
|
@ -719,7 +723,7 @@ template handleNestedTempl(n, processCall: untyped; alwaysStmt: bool) =
|
||||||
var branchScope = nestedScope(s)
|
var branchScope = nestedScope(s)
|
||||||
var branchResult = if it.kind == nkFinally: p(it[^1], c, branchScope, normal)
|
var branchResult = if it.kind == nkFinally: p(it[^1], c, branchScope, normal)
|
||||||
else: processCall(it[^1], branchScope)
|
else: processCall(it[^1], branchScope)
|
||||||
branch[^1] = toTree(branchScope, branchResult, treeFlags)
|
branch[^1] = toTree(c, branchScope, branchResult, treeFlags)
|
||||||
result.add branch
|
result.add branch
|
||||||
rememberParent(s, branchScope)
|
rememberParent(s, branchScope)
|
||||||
|
|
||||||
|
|
@ -1120,7 +1124,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
|
||||||
scope.final.add genDestroy(c, params[i])
|
scope.final.add genDestroy(c, params[i])
|
||||||
#if optNimV2 in c.graph.config.globalOptions:
|
#if optNimV2 in c.graph.config.globalOptions:
|
||||||
# injectDefaultCalls(n, c)
|
# injectDefaultCalls(n, c)
|
||||||
result = toTree(scope, body, {})
|
result = toTree(c, scope, body, {})
|
||||||
dbg:
|
dbg:
|
||||||
echo ">---------transformed-to--------->"
|
echo ">---------transformed-to--------->"
|
||||||
echo renderTree(result, {renderIds})
|
echo renderTree(result, {renderIds})
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ if
|
||||||
end true
|
end true
|
||||||
7
|
7
|
||||||
##index 2 not in 0 .. 1##
|
##index 2 not in 0 .. 1##
|
||||||
|
true
|
||||||
'''
|
'''
|
||||||
cmd: "nim c --gc:arc -d:danger $file"
|
cmd: "nim c --gc:arc -d:danger $file"
|
||||||
"""
|
"""
|
||||||
|
|
@ -102,3 +103,22 @@ proc escapeCheck =
|
||||||
clItems(toSeq())
|
clItems(toSeq())
|
||||||
|
|
||||||
escapeCheck()
|
escapeCheck()
|
||||||
|
|
||||||
|
# bug #14900
|
||||||
|
template sortedByIt(seq1): untyped =
|
||||||
|
var result = seq1
|
||||||
|
result
|
||||||
|
|
||||||
|
proc seqsEqual(seq1, seq2: seq[string]): bool =
|
||||||
|
# works as a normal proc (if we would assign result inside)
|
||||||
|
# doesn't work as an expression
|
||||||
|
result = if false: # needed
|
||||||
|
false
|
||||||
|
else:
|
||||||
|
let a1 = seq1.sortedByIt()
|
||||||
|
let a2 = seq2.sortedByIt()
|
||||||
|
# echo a1 - works if you uncomment any of these
|
||||||
|
# echo a2
|
||||||
|
a1 == a2
|
||||||
|
|
||||||
|
echo seqsEqual(@["a", "b", "c"], @["a", "b", "c"])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue