Fix forward declarations in shadow scope contexts (#15386)

* Fix forward declarations in shadow scope contexts

* Add testcase for #15385

* Less empty lines

* Fix tests

* Inline isShadowScope

* Add original testcase (with reduced amount of iterations)

* Add testcase without forward decl
This commit is contained in:
Clyybber
2020-09-22 18:24:13 +02:00
committed by GitHub
parent 11c377c114
commit 4b9eea2fcc
5 changed files with 101 additions and 13 deletions

View File

@@ -91,13 +91,15 @@ proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym =
message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " &
s.name.s & " is deprecated")
proc isShadowScope*(s: PScope): bool {.inline.} = s.parent != nil and s.parent.depthLevel == s.depthLevel
proc localSearchInScope*(c: PContext, s: PIdent): PSym =
result = strTableGet(c.currentScope.symbols, s)
var shadow = c.currentScope
while result == nil and shadow.parent != nil and shadow.depthLevel == shadow.parent.depthLevel:
var scope = c.currentScope
result = strTableGet(scope.symbols, s)
while result == nil and scope.isShadowScope:
# We are in a shadow scope, check in the parent too
result = strTableGet(shadow.parent.symbols, s)
shadow = shadow.parent
scope = scope.parent
result = strTableGet(scope.symbols, s)
proc searchInScopes*(c: PContext, s: PIdent): PSym =
for scope in walkScopes(c.currentScope):

View File

@@ -11,7 +11,7 @@
# This is needed for proper handling of forward declarations.
import
ast, astalgo, msgs, semdata, types, trees, strutils
ast, astalgo, msgs, semdata, types, trees, strutils, lookups
proc equalGenericParams(procA, procB: PNode): bool =
if procA.len != procB.len: return false
@@ -28,7 +28,7 @@ proc equalGenericParams(procA, procB: PNode): bool =
if not exprStructuralEquivalent(a.ast, b.ast): return
result = true
proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
proc searchForProcAux(c: PContext, scope: PScope, fn: PSym): PSym =
const flags = {ExactGenericParams, ExactTypeDescValues,
ExactConstraints, IgnoreCC}
var it: TIdentIter
@@ -50,6 +50,14 @@ proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
discard
result = nextIdentIter(it, scope.symbols)
proc searchForProc*(c: PContext, scope: PScope, fn: PSym): tuple[proto: PSym, comesFromShadowScope: bool] =
var scope = scope
result.proto = searchForProcAux(c, scope, fn)
while result.proto == nil and scope.isShadowScope:
scope = scope.parent
result.proto = searchForProcAux(c, scope, fn)
result.comesFromShadowScope = true
when false:
proc paramsFitBorrow(child, parent: PNode): bool =
result = false

View File

@@ -1898,8 +1898,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
elif s.kind == skFunc:
incl(s.flags, sfNoSideEffect)
incl(s.typ.flags, tfNoSideEffect)
var proto: PSym = if isAnon: nil
else: searchForProc(c, oldScope, s)
var (proto, comesFromShadowScope) = if isAnon: (nil, false)
else: searchForProc(c, oldScope, s)
if proto == nil and sfForward in s.flags:
#This is a definition that shares its sym with its forward declaration (generated by a macro),
#if the symbol is also gensymmed we won't find it with searchForProc, so we check here
@@ -1941,8 +1941,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
onDefResolveForward(n[namePos].info, proto)
if sfForward notin proto.flags and proto.magic == mNone:
wrongRedefinition(c, n.info, proto.name.s, proto.info)
excl(proto.flags, sfForward)
incl(proto.flags, sfWasForwarded)
if not comesFromShadowScope:
excl(proto.flags, sfForward)
incl(proto.flags, sfWasForwarded)
closeScope(c) # close scope with wrong parameter symbols
openScope(c) # open scope for old (correct) parameter symbols
if proto.ast[genericParamsPos].kind != nkEmpty:

View File

@@ -662,10 +662,10 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s)
elif n[bodyPos].kind == nkEmpty:
localError(c.config, n.info, "implementation of '$1' expected" % s.name.s)
var proto = searchForProc(c, c.currentScope, s)
var (proto, comesFromShadowscope) = searchForProc(c, c.currentScope, s)
if proto == nil:
addInterfaceOverloadableSymAt(c, c.currentScope, s)
else:
elif not comesFromShadowscope:
symTabReplace(c.currentScope.symbols, proto, s)
if n[patternPos].kind != nkEmpty:
c.patterns.add(s)