summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorClyybber <darkmine956@gmail.com>2020-09-22 18:24:13 +0200
committerGitHub <noreply@github.com>2020-09-22 18:24:13 +0200
commit4b9eea2fcc5d030393ca9020fbbee33fcb48d41a (patch)
tree4024e3074ebbaf636ee0f00415f9f0861c4bf522 /compiler
parent11c377c1149a23657a7f0dd897866cb550ade8d1 (diff)
downloadNim-4b9eea2fcc5d030393ca9020fbbee33fcb48d41a.tar.gz
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
Diffstat (limited to 'compiler')
-rw-r--r--compiler/lookups.nim12
-rw-r--r--compiler/procfind.nim12
-rw-r--r--compiler/semstmts.nim9
-rw-r--r--compiler/semtempl.nim4
4 files changed, 24 insertions, 13 deletions
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index c0db25950..744f77cf8 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -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):
diff --git a/compiler/procfind.nim b/compiler/procfind.nim
index 1d897758a..0bdb3dae6 100644
--- a/compiler/procfind.nim
+++ b/compiler/procfind.nim
@@ -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
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index e99ce8937..53d381f5d 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -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:
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index a1afd2c6d..1ec8c07b0 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -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)