fixes #4555
This commit is contained in:
parent
24b72cebe7
commit
de6198c747
8 changed files with 38 additions and 14 deletions
|
|
@ -99,8 +99,11 @@ proc debugScopes*(c: PContext; limit=0) {.deprecated.} =
|
||||||
|
|
||||||
proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
|
proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
|
||||||
for scope in walkScopes(c.currentScope):
|
for scope in walkScopes(c.currentScope):
|
||||||
result = strTableGet(scope.symbols, s)
|
var ti: TIdentIter
|
||||||
if result != nil and result.kind in filter: return
|
var candidate = initIdentIter(ti, scope.symbols, s)
|
||||||
|
while candidate != nil:
|
||||||
|
if candidate.kind in filter: return candidate
|
||||||
|
candidate = nextIdentIter(ti, scope.symbols)
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
proc errorSym*(c: PContext, n: PNode): PSym =
|
proc errorSym*(c: PContext, n: PNode): PSym =
|
||||||
|
|
@ -266,13 +269,17 @@ proc lookUp*(c: PContext, n: PNode): PSym =
|
||||||
|
|
||||||
type
|
type
|
||||||
TLookupFlag* = enum
|
TLookupFlag* = enum
|
||||||
checkAmbiguity, checkUndeclared
|
checkAmbiguity, checkUndeclared, checkModule
|
||||||
|
|
||||||
proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
|
||||||
|
const allExceptModule = {low(TSymKind)..high(TSymKind)}-{skModule,skPackage}
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkIdent, nkAccQuoted:
|
of nkIdent, nkAccQuoted:
|
||||||
var ident = considerQuotedIdent(n)
|
var ident = considerQuotedIdent(n)
|
||||||
result = searchInScopes(c, ident).skipAlias(n)
|
if checkModule in flags:
|
||||||
|
result = searchInScopes(c, ident).skipAlias(n)
|
||||||
|
else:
|
||||||
|
result = searchInScopes(c, ident, allExceptModule).skipAlias(n)
|
||||||
if result == nil and checkUndeclared in flags:
|
if result == nil and checkUndeclared in flags:
|
||||||
fixSpelling(n, ident, searchInScopes)
|
fixSpelling(n, ident, searchInScopes)
|
||||||
localError(n.info, errUndeclaredIdentifier, ident.s)
|
localError(n.info, errUndeclaredIdentifier, ident.s)
|
||||||
|
|
@ -286,7 +293,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||||
errorUseQualifier(c, n.info, n.sym)
|
errorUseQualifier(c, n.info, n.sym)
|
||||||
of nkDotExpr:
|
of nkDotExpr:
|
||||||
result = nil
|
result = nil
|
||||||
var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
|
var m = qualifiedLookUp(c, n.sons[0], (flags*{checkUndeclared})+{checkModule})
|
||||||
if m != nil and m.kind == skModule:
|
if m != nil and m.kind == skModule:
|
||||||
var ident: PIdent = nil
|
var ident: PIdent = nil
|
||||||
if n.sons[1].kind == nkIdent:
|
if n.sons[1].kind == nkIdent:
|
||||||
|
|
@ -331,7 +338,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||||
o.mode = oimDone
|
o.mode = oimDone
|
||||||
of nkDotExpr:
|
of nkDotExpr:
|
||||||
o.mode = oimOtherModule
|
o.mode = oimOtherModule
|
||||||
o.m = qualifiedLookUp(c, n.sons[0])
|
o.m = qualifiedLookUp(c, n.sons[0], {checkUndeclared, checkModule})
|
||||||
if o.m != nil and o.m.kind == skModule:
|
if o.m != nil and o.m.kind == skModule:
|
||||||
var ident: PIdent = nil
|
var ident: PIdent = nil
|
||||||
if n.sons[1].kind == nkIdent:
|
if n.sons[1].kind == nkIdent:
|
||||||
|
|
|
||||||
|
|
@ -569,7 +569,7 @@ proc deprecatedStmt(c: PContext; pragma: PNode) =
|
||||||
localError(pragma.info, "list of key:value pairs expected"); return
|
localError(pragma.info, "list of key:value pairs expected"); return
|
||||||
for n in pragma:
|
for n in pragma:
|
||||||
if n.kind in {nkExprColonExpr, nkExprEqExpr}:
|
if n.kind in {nkExprColonExpr, nkExprEqExpr}:
|
||||||
let dest = qualifiedLookUp(c, n[1])
|
let dest = qualifiedLookUp(c, n[1], {checkUndeclared})
|
||||||
let src = considerQuotedIdent(n[0])
|
let src = considerQuotedIdent(n[0])
|
||||||
let alias = newSym(skAlias, src, dest, n[0].info)
|
let alias = newSym(skAlias, src, dest, n[0].info)
|
||||||
incl(alias.flags, sfExported)
|
incl(alias.flags, sfExported)
|
||||||
|
|
@ -594,7 +594,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
|
||||||
# and perform the lookup on demand instead.
|
# and perform the lookup on demand instead.
|
||||||
result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info)
|
result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info)
|
||||||
else:
|
else:
|
||||||
result = qualifiedLookUp(c, n)
|
result = qualifiedLookUp(c, n, {checkUndeclared})
|
||||||
|
|
||||||
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
validPragmas: TSpecialWords): bool =
|
validPragmas: TSpecialWords): bool =
|
||||||
|
|
|
||||||
|
|
@ -1107,7 +1107,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# here at all!
|
# here at all!
|
||||||
#if isSymChoice(n.sons[1]): return
|
#if isSymChoice(n.sons[1]): return
|
||||||
|
|
||||||
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
|
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule})
|
||||||
if s != nil:
|
if s != nil:
|
||||||
if s.kind in OverloadableSyms:
|
if s.kind in OverloadableSyms:
|
||||||
result = symChoice(c, n, s, scClosed)
|
result = symChoice(c, n, s, scClosed)
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
assert n.kind == nkDotExpr
|
assert n.kind == nkDotExpr
|
||||||
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
|
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
|
||||||
|
|
||||||
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
|
let luf = if withinMixin notin flags: {checkUndeclared, checkModule} else: {checkModule}
|
||||||
|
|
||||||
var s = qualifiedLookUp(c, n, luf)
|
var s = qualifiedLookUp(c, n, luf)
|
||||||
if s != nil:
|
if s != nil:
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ proc semBindSym(c: PContext, n: PNode): PNode =
|
||||||
return errorNode(c, n)
|
return errorNode(c, n)
|
||||||
|
|
||||||
let id = newIdentNode(getIdent(sl.strVal), n.info)
|
let id = newIdentNode(getIdent(sl.strVal), n.info)
|
||||||
let s = qualifiedLookUp(c, id)
|
let s = qualifiedLookUp(c, id, {checkUndeclared})
|
||||||
if s != nil:
|
if s != nil:
|
||||||
# we need to mark all symbols:
|
# we need to mark all symbols:
|
||||||
var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
|
var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
|
||||||
|
|
|
||||||
|
|
@ -675,7 +675,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
||||||
let name = a.sons[0]
|
let name = a.sons[0]
|
||||||
var s: PSym
|
var s: PSym
|
||||||
if name.kind == nkDotExpr:
|
if name.kind == nkDotExpr:
|
||||||
s = qualifiedLookUp(c, name)
|
s = qualifiedLookUp(c, name, {checkUndeclared, checkModule})
|
||||||
if s.kind != skType or s.typ.skipTypes(abstractPtrs).kind != tyObject or tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
|
if s.kind != skType or s.typ.skipTypes(abstractPtrs).kind != tyObject or tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
|
||||||
localError(name.info, "only .partial objects can be extended")
|
localError(name.info, "only .partial objects can be extended")
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
|
||||||
# the same symbol!
|
# the same symbol!
|
||||||
# This is however not true anymore for hygienic templates as semantic
|
# This is however not true anymore for hygienic templates as semantic
|
||||||
# processing for them changes the symbol table...
|
# processing for them changes the symbol table...
|
||||||
let s = qualifiedLookUp(c, a)
|
let s = qualifiedLookUp(c, a, {checkUndeclared})
|
||||||
if s != nil:
|
if s != nil:
|
||||||
# we need to mark all symbols:
|
# we need to mark all symbols:
|
||||||
let sc = symChoice(c, n, s, scClosed)
|
let sc = symChoice(c, n, s, scClosed)
|
||||||
|
|
|
||||||
17
tests/lookups/test.nim
Normal file
17
tests/lookups/test.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# This file needs to be called 'test' nim to provoke a clash
|
||||||
|
# with the unittest.test name. Issue #
|
||||||
|
|
||||||
|
import unittest, macros
|
||||||
|
|
||||||
|
# bug #4555
|
||||||
|
|
||||||
|
macro memo(n: untyped): typed =
|
||||||
|
result = n
|
||||||
|
|
||||||
|
proc fastFib(n: int): int {.memo.} = 40
|
||||||
|
proc fib(n: int): int = 40
|
||||||
|
|
||||||
|
suite "memoization":
|
||||||
|
test "recursive function memoization":
|
||||||
|
check fastFib(40) == fib(40)
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue