big compiler refactoring; avoid globals for multi method dispatcher generation

This commit is contained in:
Andreas Rumpf 2017-02-22 16:27:52 +01:00
commit 46efaf294b
29 changed files with 225 additions and 215 deletions

View file

@ -35,7 +35,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
x.info = n.info
incl(s.flags, sfUsed)
n.sons[0] = x
suggestSym(x.info, s)
suggestSym(x.info, s, c.graph.usageSym)
styleCheckUse(x.info, s)
else:
localError(n.info, errInvalidControlFlowX, s.name.s)
@ -366,11 +366,13 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
if isTopLevel(c):
result = semIdentWithPragma(c, kind, n, {sfExported})
incl(result.flags, sfGlobal)
#if kind in {skVar, skLet}:
# echo "global variable here ", n.info, " ", result.name.s
else:
result = semIdentWithPragma(c, kind, n, {})
if result.owner.kind == skModule:
incl(result.flags, sfGlobal)
suggestSym(n.info, result)
suggestSym(n.info, result, c.graph.usageSym)
styleCheckDef(result)
proc checkNilable(v: PSym) =
@ -621,7 +623,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
if iter.kind != tyTuple or length == 3:
if length == 3:
var v = symForVar(c, n.sons[0])
if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
# BUGFIX: don't use `iter` here as that would strip away
# the ``tyGenericInst``! See ``tests/compile/tgeneric.nim``
# for an example:
@ -635,7 +637,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
else:
for i in countup(0, length - 3):
var v = symForVar(c, n.sons[i])
if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
v.typ = iter.sons[i]
n.sons[i] = newSymNode(v)
if sfGenSym notin v.flags and not isDiscardUnderscore(v):
@ -745,7 +747,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
# We have a generic type declaration here. In generic types,
# symbol lookup needs to be done here.
openScope(c)
pushOwner(s)
pushOwner(c, s)
if s.magic == mNone: s.typ.kind = tyGenericBody
# XXX for generic type aliases this is not correct! We need the
# underlying Id really:
@ -769,11 +771,11 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
body.sym = s
body.size = -1 # could not be computed properly
s.typ.sons[sonsLen(s.typ) - 1] = body
popOwner()
popOwner(c)
closeScope(c)
elif a.sons[2].kind != nkEmpty:
# process the type's body:
pushOwner(s)
pushOwner(c, s)
var t = semTypeNode(c, a.sons[2], s.typ)
if s.typ == nil:
s.typ = t
@ -782,7 +784,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
assignType(s.typ, t)
#debug s.typ
s.ast = a
popOwner()
popOwner(c)
let aa = a.sons[2]
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
aa.sons[0].kind == nkObjectTy:
@ -793,7 +795,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
internalAssert st.lastSon.sym == nil
incl st.flags, tfRefsAnonObj
let obj = newSym(skType, getIdent(s.name.s & ":ObjectType"),
getCurrOwner(), s.info)
getCurrOwner(c), s.info)
obj.typ = st.lastSon
st.lastSon.sym = obj
@ -927,7 +929,7 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
if t != nil:
var s = newSym(skResult, getIdent"result", getCurrOwner(), info)
var s = newSym(skResult, getIdent"result", getCurrOwner(c), info)
s.typ = t
incl(s.flags, sfUsed)
addParamOrResult(c, s, owner)
@ -1002,12 +1004,12 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
checkSonsLen(n, bodyPos + 1)
var s: PSym
if n[namePos].kind != nkSym:
s = newSym(skProc, c.cache.idAnon, getCurrOwner(), n.info)
s = newSym(skProc, c.cache.idAnon, getCurrOwner(c), n.info)
s.ast = n
n.sons[namePos] = newSymNode(s)
else:
s = n[namePos].sym
pushOwner(s)
pushOwner(c, s)
openScope(c)
var gp: PNode
if n.sons[genericParamsPos].kind != nkEmpty:
@ -1047,7 +1049,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
else:
localError(n.info, errImplOfXexpected, s.name.s)
closeScope(c) # close scope for parameters
popOwner()
popOwner(c)
result.typ = s.typ
proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
@ -1081,7 +1083,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
params[i].sym.name.s)
#params[i].sym.owner = s
openScope(c)
pushOwner(s)
pushOwner(c, s)
addParams(c, params, skProc)
pushProcCon(c, s)
addResult(c, n.typ.sons[0], n.info, skProc)
@ -1089,7 +1091,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, s)
popProcCon(c)
popOwner()
popOwner(c)
closeScope(c)
# alternative variant (not quite working):
@ -1193,6 +1195,42 @@ type
import compilerlog
proc hasObjParam(s: PSym): bool =
var t = s.typ
for col in countup(1, sonsLen(t)-1):
if skipTypes(t.sons[col], skipPtrs).kind == tyObject:
return true
proc finishMethod(c: PContext, s: PSym) =
if hasObjParam(s):
methodDef(c.graph, s, false)
proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
if isGenericRoutine(s):
let tt = s.typ
var foundObj = false
# we start at 1 for now so that tparsecombnum continues to compile.
# XXX Revisit this problem later.
for col in countup(1, sonsLen(tt)-1):
let t = tt.sons[col]
if t != nil and t.kind == tyGenericInvocation:
var x = skipTypes(t.sons[0], {tyVar, tyPtr, tyRef, tyGenericInst,
tyGenericInvocation, tyGenericBody,
tyAlias})
if x.kind == tyObject and t.len-1 == n.sons[genericParamsPos].len:
foundObj = true
x.methods.safeAdd((col,s))
if not foundObj:
message(n.info, warnDeprecated, "generic method not attachable to object type")
else:
# why check for the body? bug #2400 has none. Checking for sfForward makes
# no sense either.
# and result.sons[bodyPos].kind != nkEmpty:
if hasObjParam(s):
methodDef(c.graph, s, fromCache=false)
else:
localError(n.info, errXNeedsParamObjectType, "method")
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
validPragmas: TSpecialWords,
phase = stepRegisterSymbol): PNode =
@ -1207,7 +1245,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
assert phase == stepRegisterSymbol
if n[namePos].kind == nkEmpty:
s = newSym(kind, c.cache.idAnon, getCurrOwner(), n.info)
s = newSym(kind, c.cache.idAnon, getCurrOwner(c), n.info)
incl(s.flags, sfUsed)
isAnon = true
else:
@ -1224,7 +1262,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
return
else:
s = n[namePos].sym
s.owner = getCurrOwner()
s.owner = getCurrOwner(c)
typeIsDetermined = s.typ == nil
s.ast = n
#s.scope = c.currentScope
@ -1233,7 +1271,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# where the proc was declared
let oldScope = c.currentScope
#c.currentScope = s.scope
pushOwner(s)
pushOwner(c, s)
openScope(c)
var gp: PNode
if n.sons[genericParamsPos].kind != nkEmpty:
@ -1299,8 +1337,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if importantComments() and not isNil(proto.ast.comment):
n.comment = proto.ast.comment
proto.ast = n # needed for code generation
popOwner()
pushOwner(s)
popOwner(c)
pushOwner(c, s)
s.options = gOptions
if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
if s.name.s[0] in {'.', '('}:
@ -1317,6 +1355,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if not usePseudoGenerics and gIdeCmd in {ideSug, ideCon} and not
cursorInProc(n.sons[bodyPos]):
discard "speed up nimsuggest"
if s.kind == skMethod: semMethodPrototype(c, s, n)
else:
pushProcCon(c, s)
if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics:
@ -1324,6 +1363,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
c.p.wasForwarded = proto != nil
maybeAddResult(c, s, n)
if s.kind == skMethod: semMethodPrototype(c, s, n)
if lfDynamicLib notin s.loc.flags:
# no semantic checking for importc:
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
@ -1333,15 +1374,18 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
else:
if s.typ.sons[0] != nil and kind != skIterator:
addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info))
openScope(c)
n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos])
closeScope(c)
fixupInstantiatedSymbols(c, s)
if s.kind == skMethod: semMethodPrototype(c, s, n)
if sfImportc in s.flags:
# so we just ignore the body after semantic checking for importc:
n.sons[bodyPos] = ast.emptyNode
popProcCon(c)
else:
if s.kind == skMethod: semMethodPrototype(c, s, n)
if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
incl(s.flags, sfForward)
@ -1349,7 +1393,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
sideEffectsCheck(c, s)
closeScope(c) # close scope for parameters
# c.currentScope = oldScope
popOwner()
popOwner(c)
if n.sons[patternPos].kind != nkEmpty:
c.patterns.add(s)
if isAnon: result.typ = s.typ
@ -1368,7 +1412,7 @@ proc semIterator(c: PContext, n: PNode): PNode =
let isAnon = n[namePos].kind == nkEmpty
if n[namePos].kind == nkSym:
# gensym'ed iterators might need to become closure iterators:
n[namePos].sym.owner = getCurrOwner()
n[namePos].sym.owner = getCurrOwner(c)
n[namePos].sym.kind = skIterator
result = semProcAux(c, n, skIterator, iteratorPragmas)
var s = result.sons[namePos].sym
@ -1395,46 +1439,9 @@ proc semIterator(c: PContext, n: PNode): PNode =
proc semProc(c: PContext, n: PNode): PNode =
result = semProcAux(c, n, skProc, procPragmas)
proc hasObjParam(s: PSym): bool =
var t = s.typ
for col in countup(1, sonsLen(t)-1):
if skipTypes(t.sons[col], skipPtrs).kind == tyObject:
return true
proc finishMethod(c: PContext, s: PSym) =
if hasObjParam(s):
methodDef(s, false)
proc semMethod(c: PContext, n: PNode): PNode =
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
result = semProcAux(c, n, skMethod, methodPragmas)
# macros can transform methods to nothing:
if namePos >= result.safeLen: return result
var s = result.sons[namePos].sym
if isGenericRoutine(s):
let tt = s.typ
var foundObj = false
# we start at 1 for now so that tparsecombnum continues to compile.
# XXX Revisit this problem later.
for col in countup(1, sonsLen(tt)-1):
let t = tt.sons[col]
if t != nil and t.kind == tyGenericInvocation:
var x = skipTypes(t.sons[0], {tyVar, tyPtr, tyRef, tyGenericInst,
tyGenericInvocation, tyGenericBody,
tyAlias})
if x.kind == tyObject and t.len-1 == result.sons[genericParamsPos].len:
foundObj = true
x.methods.safeAdd((col,s))
if not foundObj:
message(n.info, warnDeprecated, "generic method not attachable to object type")
else:
# why check for the body? bug #2400 has none. Checking for sfForward makes
# no sense either.
# and result.sons[bodyPos].kind != nkEmpty:
if hasObjParam(s):
methodDef(s, fromCache=false)
else:
localError(n.info, errXNeedsParamObjectType, "method")
proc semConverterDef(c: PContext, n: PNode): PNode =
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")