up references work

This commit is contained in:
Andreas Rumpf 2015-12-28 23:46:19 +01:00
commit 57149a4794

View file

@ -197,15 +197,6 @@ proc isInnerProc(s: PSym): bool =
if s.kind in {skProc, skMethod, skConverter, skIterator} and s.magic == mNone: if s.kind in {skProc, skMethod, skConverter, skIterator} and s.magic == mNone:
result = s.skipGenericOwner.kind in routineKinds result = s.skipGenericOwner.kind in routineKinds
proc createUpField(obj, fieldType: PType): PSym =
let pos = obj.n.len
result = newSym(skField, getIdent(upName), obj.owner, obj.owner.info)
result.typ = newType(tyRef, obj.owner)
result.position = pos
rawAddSon(result.typ, fieldType)
#rawAddField(obj, result)
addField(obj, result)
proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode = proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
# Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would # Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
# mean to be able to capture string literals which have no GC header. # mean to be able to capture string literals which have no GC header.
@ -254,15 +245,6 @@ proc liftIterSym(n: PNode; owner: PSym): PNode =
# ------------------ new stuff ------------------------------------------- # ------------------ new stuff -------------------------------------------
proc createUpField(dest, dep: PSym) =
let obj = getHiddenParam(dest).typ.lastSon
let fieldType = getHiddenParam(dep).typ
let pos = obj.n.len
let result = newSym(skField, getIdent(upName), obj.owner, obj.owner.info)
result.typ = fieldType
result.position = pos
addField(obj, result)
proc markAsClosure(owner: PSym; n: PNode) = proc markAsClosure(owner: PSym; n: PNode) =
owner.typ.callConv = ccClosure owner.typ.callConv = ccClosure
incl(owner.typ.flags, tfCapturesEnv) incl(owner.typ.flags, tfCapturesEnv)
@ -300,13 +282,34 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym): PType =
rawAddSon(result, obj) rawAddSon(result, obj)
c.ownerToType[owner.id] = result c.ownerToType[owner.id] = result
proc addClosureParam(c: var DetectionPass; fn, owner: PSym) = proc createUpField(c: var DetectionPass; dest, dep: PSym) =
let refObj = c.getEnvTypeForOwner(dest) # getHiddenParam(dest).typ
let obj = refObj.lastSon
let fieldType = c.getEnvTypeForOwner(dep) #getHiddenParam(dep).typ
if refObj == fieldType:
localError(dep.info, "internal error: invald up reference computed")
let upIdent = getIdent(upName)
let upField = lookupInRecord(obj.n, upIdent)
if upField != nil:
if upField.typ != fieldType:
localError(dep.info, "internal error: up references do not agree")
else:
let result = newSym(skField, upIdent, obj.owner, obj.owner.info)
result.typ = fieldType
rawAddField(obj, result)
proc addClosureParam(c: var DetectionPass; fn: PSym) =
var cp = getEnvParam(fn) var cp = getEnvParam(fn)
let owner = fn.skipGenericOwner
let t = c.getEnvTypeForOwner(owner)
if cp == nil: if cp == nil:
cp = newSym(skParam, getIdent(paramName), fn, fn.info) cp = newSym(skParam, getIdent(paramName), fn, fn.info)
incl(cp.flags, sfFromGeneric) incl(cp.flags, sfFromGeneric)
cp.typ = c.getEnvTypeForOwner(owner) cp.typ = t
addHiddenParam(fn, cp) addHiddenParam(fn, cp)
elif cp.typ != t:
localError(fn.info, "internal error: inconsistent environment type")
proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
case n.kind case n.kind
@ -322,6 +325,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
c.somethingToDo = true c.somethingToDo = true
if not c.capturedVars.containsOrIncl(s.id): if not c.capturedVars.containsOrIncl(s.id):
let obj = getHiddenParam(owner).typ.lastSon let obj = getHiddenParam(owner).typ.lastSon
#let obj = c.getEnvTypeForOwner(s.owner).lastSon
addField(obj, s) addField(obj, s)
# but always return because the rest of the proc is only relevant when # but always return because the rest of the proc is only relevant when
# ow != owner: # ow != owner:
@ -336,25 +340,21 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
echo x echo x
innerInner() innerInner()
inner() inner()
# inner() takes a closure too! # inner() takes a closure too!
""" """
# mark 'owner' as taking a closure: # mark 'owner' as taking a closure:
c.somethingToDo = true c.somethingToDo = true
markAsClosure(owner, n) markAsClosure(owner, n)
addClosureParam(c, owner, ow) addClosureParam(c, owner)
# variable 's' is actually captured: # variable 's' is actually captured:
if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id): if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id):
let obj = getHiddenParam(owner).typ.lastSon let obj = c.getEnvTypeForOwner(ow).lastSon
#getHiddenParam(owner).typ.lastSon
addField(obj, s) addField(obj, s)
# create required upFields: # create required upFields:
var w = ow.skipGenericOwner var w = owner.skipGenericOwner
if w != owner: if isInnerProc(w):
var up = ow while w != nil and w.kind != skModule and ow != w:
while w != nil and w.kind != skModule:
w = w.skipGenericOwner
markAsClosure(w, n)
discard """ discard """
proc outer = proc outer =
var a, b: int var a, b: int
@ -364,10 +364,12 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
# --> make outerB of calling convention .closure and # --> make outerB of calling convention .closure and
# give it the same env type that outer's env var gets: # give it the same env type that outer's env var gets:
""" """
addClosureParam(c, w, ow) let up = w.skipGenericOwner
createUpField(w, up) #echo "up for ", w.name.s, " up ", up.name.s
if w == owner: break markAsClosure(w, n)
up = w addClosureParam(c, w) # , ow
createUpField(c, w, up)
w = up
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure, of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure,
nkTemplateDef, nkTypeSection: nkTemplateDef, nkTypeSection:
discard discard
@ -398,6 +400,7 @@ proc accessViaEnvParam(n: PNode; owner: PSym): PNode =
var access = newSymNode(envParam) var access = newSymNode(envParam)
while true: while true:
let obj = access.typ.sons[0] let obj = access.typ.sons[0]
assert obj.kind == tyObject
let field = getFieldFromObj(obj, s) let field = getFieldFromObj(obj, s)
if field != nil: if field != nil:
return rawIndirectAccess(access, field, n.info) return rawIndirectAccess(access, field, n.info)
@ -429,7 +432,7 @@ proc rawClosureCreation(env: PNode; owner: PSym;
if upField != nil: if upField != nil:
let param = getHiddenParam(owner) let param = getHiddenParam(owner)
if upField.typ == param.typ: if upField.typ == param.typ:
result.add(newAsgnStmt(indirectAccess(env, upField, env.info), result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
newSymNode(param), env.info)) newSymNode(param), env.info))
else: else:
localError(env.info, "internal error: cannot create up reference") localError(env.info, "internal error: cannot create up reference")