Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scope based symbol resolution; fixes generic sandwich problem; fix #13747, #17965, #13970: declarations at non-module scope now work with generics #18050

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
54492de
refs #13747
timotheecour May 19, 2021
249969d
PRTEMP
timotheecour May 19, 2021
15eae09
fix test
timotheecour May 19, 2021
4b61304
PRTEMP
timotheecour May 19, 2021
d8bdf8d
works
timotheecour May 20, 2021
0f2d594
cleanup
timotheecour May 20, 2021
2520bf8
fix tests PRTEMP
timotheecour May 20, 2021
ef8fb9f
works
timotheecour May 20, 2021
3dfe097
add tests
timotheecour May 20, 2021
ef6943f
cleanup
timotheecour May 20, 2021
997019c
cleanup
timotheecour May 20, 2021
c6a3361
fixup
timotheecour May 20, 2021
aa6eed7
PRTEMP
timotheecour May 20, 2021
b136208
re-export debugutils + other
timotheecour May 20, 2021
6dc9d57
PRTEMP
timotheecour May 20, 2021
2d325b5
mixin works with declared, even with conditional compilation
timotheecour May 20, 2021
92faeca
PRTEMP
timotheecour May 20, 2021
9e61ff1
fixup
timotheecour May 20, 2021
600de66
works w bootstrap
timotheecour May 20, 2021
ad91aed
cleanup
timotheecour May 20, 2021
8b55b7f
works better w nesting
timotheecour May 20, 2021
52aac79
cleanup
timotheecour May 20, 2021
f7ff447
megatest works
timotheecour May 21, 2021
411792a
D20210520T172430 4 tests fail
timotheecour May 21, 2021
27c1762
PRTEMP
timotheecour May 21, 2021
ea08482
fix D20210521T084751 evaltempl.nim(49, 24) internal error
timotheecour May 21, 2021
6689860
cleanup
timotheecour May 21, 2021
f7f3cfb
fix twrongrefcounting
timotheecour May 21, 2021
5d9d80b
fix D20210521T115234 refs D20210521T130909 {.pushwarning[resultshadow…
timotheecour May 21, 2021
878245d
works better with concept, except for variables defined in concept bo…
timotheecour May 21, 2021
ba54124
concept: pushOwner
timotheecour May 22, 2021
6d8d34e
cleanup
timotheecour May 22, 2021
da4a783
fixup
timotheecour May 22, 2021
04d8bc2
fix {.pragma: myprag, inline.}
timotheecour May 22, 2021
7bdb0e2
PRTEMP
timotheecour May 22, 2021
8789ea8
works better
timotheecour May 22, 2021
537529a
works with `typeof(fn(param))` in result symbol
timotheecour May 22, 2021
62408dc
works at some point except for type section that i am debugging
timotheecour May 23, 2021
b823e5d
semGenericStmtInTypeSection
timotheecour May 23, 2021
e7478bf
cleanup
timotheecour May 23, 2021
df7ad37
fixup
timotheecour May 23, 2021
4a4001c
cleanup
timotheecour May 23, 2021
1569e14
cleanups
timotheecour May 23, 2021
40bbf72
fixup
timotheecour May 26, 2021
3160bb1
make tests green
timotheecour Jun 9, 2021
99be00d
PRTEMP
timotheecour Jun 11, 2021
06ef09e
fix after rebase
timotheecour Jun 21, 2021
2e5f59d
cleanups
timotheecour Jun 22, 2021
ff8b961
remove duplication
timotheecour Jun 22, 2021
a9091bd
cleanups; add tests
timotheecour Jun 22, 2021
4e31108
undisable stint
timotheecour Jul 1, 2021
f9d7411
fix a bug
timotheecour Jul 7, 2021
68a42b6
undisable ggplotnim
timotheecour Jul 7, 2021
1f3158b
undisable zro_functional
timotheecour Jul 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ type
# mean: never)
skPackage, # symbol is a package (used for canonicalization)
skAlias # an alias (needs to be resolved immediately)
skMixin # in `mixin foo`, declares `foo` as skMixin if no other symbols exist
TSymKinds* = set[TSymKind]

const
Expand Down
16 changes: 12 additions & 4 deletions compiler/astalgo.nim
Original file line number Diff line number Diff line change
Expand Up @@ -777,10 +777,18 @@ proc strTableInclReportConflict*(t: var TStrTable, n: PSym;
replaceSlot = h
h = nextTry(h, high(t.data))
if replaceSlot >= 0:
result = t.data[replaceSlot] # found it
if not onConflictKeepOld:
t.data[replaceSlot] = n # overwrite it with newer definition!
return result # but return the old one
# another option would be to keep both but handle conflict resolution by prefering the non-skMixin
# see D20210521T082944
if t.data[replaceSlot].kind == skMixin:
t.data[replaceSlot] = n
return nil # report no conflict
elif n.kind == skMixin:
return nil # report no conflict
else:
result = t.data[replaceSlot] # found it
if not onConflictKeepOld:
t.data[replaceSlot] = n # overwrite it with newer definition!
return result # but return the old one
elif mustRehash(t.data.len, t.counter):
strTableEnlarge(t)
strTableRawInsert(t.data, n)
Expand Down
31 changes: 31 additions & 0 deletions compiler/debugutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ useful debugging flags:
## future work
* expose and improve astalgo.debug, replacing it by std/prettyprints,
refs https://github.com/nim-lang/RFCs/issues/385

## examples:
{.define(nimCompilerDebug).}
code
{.undef(nimCompilerDebug).}

when defined(nimDebugUtils):
if isCompilerDebug():
dbg t, ?.t.sym, ?.t.sym.owner, cl.owner
]#

import options
Expand Down Expand Up @@ -54,3 +63,25 @@ proc isCompilerDebug*(): bool =
{.undef(nimCompilerDebug).}
echo 'x'
conf0.isDefined("nimCompilerDebug")

template debugScopesIf* =
if isCompilerDebug():
# TODO: callSite?
const infom1 = instantiationInfo(-1, true)
dbg(info = infom1)
debugScopes(c, limit = 100)

template debugScopes2* =
# TODO: callSite?
const infom1 = instantiationInfo(-1, true)
dbg(info = infom1)
debugScopes(c, limit = 100)

template dbgIf*(args: varargs[untyped]) =
if isCompilerDebug():
const infom1 = instantiationInfo(-1, true)
when varargsLen(args) > 0:
dbg(info = infom1, args)
else:
# otherwise info is wrong (points to here)
dbg(info = infom1)
2 changes: 1 addition & 1 deletion compiler/evaltempl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam):
handleParam actual[s.owner.typ.len + s.position - 1]
else:
internalAssert c.config, sfGenSym in s.flags or s.kind == skType
internalAssert c.config, sfGenSym in s.flags or s.kind in {skType, skMixin}
var x = PSym(idTableGet(c.mapping, s))
if x == nil:
x = copySym(s, nextSymId(c.idgen))
Expand Down
43 changes: 41 additions & 2 deletions compiler/lookups.nim
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,45 @@ proc someSymFromImportTable*(c: PContext; name: PIdent; ambiguous: var bool): PS
ambiguous = true

proc searchInScopes*(c: PContext, s: PIdent; ambiguous: var bool): PSym =
#[
This is the key algorithm to solve the generic sandwich problem:
Inside generics, we stop the search at c.genericInstStack[^1] unless we found
a mixin; this means:

# module m1:
proc bar1()=discard
proc fn*[T] =
mixin bar3
proc bar2() = discard
bar1() # ok, this is resolved as a symbol during generic prepass
bar2() # ok, ditto
bar3() # ok, this is resolved as a skMixin symbol during generic prepass
bar4() # error, this is not visible
bar5() # error, ditto, even if bar5 is at module scope in m2

# module m2:
import m1
proc bar5() = discard
proc main =
proc bar3() = discard
proc bar4() = discard
fn[int]()
]#
var foundMixin = false
for scope in allScopes(c.currentScope):
result = strTableGet(scope.symbols, s)
if result != nil: return result
if result != nil:
if result.kind == skMixin:
foundMixin = true
continue
if c.inGenericInst > 0 and not foundMixin:
timotheecour marked this conversation as resolved.
Show resolved Hide resolved
var parent = result.owner
while true:
if parent == c.genericInstStack[^1]: break
if parent != nil: parent = parent.owner
else: return nil
return result
if c.inGenericInst > 0 and not foundMixin: return nil
result = someSymFromImportTable(c, s, ambiguous)

proc debugScopes*(c: PContext; limit=0, max = int.high) {.deprecated.} =
Expand All @@ -200,7 +236,8 @@ proc debugScopes*(c: PContext; limit=0, max = int.high) {.deprecated.} =
for h in 0..high(scope.symbols.data):
if scope.symbols.data[h] != nil:
if count >= max: return
echo count, ": ", scope.symbols.data[h].name.s
let sym = scope.symbols.data[h]
echo count, ": ", sym, " owner:", sym.owner
count.inc
if i == limit: return
inc i
Expand All @@ -213,6 +250,8 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy
while candidate != nil:
if candidate.kind in filter:
if result.len == 0:
# xxx check whether we need similar logic as in `searchInScopes`
# (`inGenericInst` etc)
result.add candidate
candidate = nextIdentIter(ti, scope.symbols)

Expand Down
6 changes: 6 additions & 0 deletions compiler/sem.nim
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import
lowerings, plugins/active, lineinfos, strtabs, int128,
isolation_check, typeallowed, modulegraphs, enumtostr, concepts, astmsgs

when defined(nimCompilerStackraceHints):
import std/stackframes

when defined(nimfix):
import nimfix/prettybase

Expand Down Expand Up @@ -496,6 +499,7 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode =

proc semGenericStmt(c: PContext, n: PNode): PNode
proc semConceptBody(c: PContext, n: PNode): PNode
proc semGenericStmtInTypeSection(c: PContext, n: PNode): PNode

include semtypes

Expand Down Expand Up @@ -637,11 +641,13 @@ proc myProcess(context: PPassContext, n: PNode): PNode {.nosinks.} =
else:
let oldContextLen = msgs.getInfoContextLen(c.config)
let oldInGenericInst = c.inGenericInst
let oldgenericInstStackLen = c.genericInstStack.len
try:
result = semStmtAndGenerateGenerics(c, n)
except ERecoverableError, ESuggestDone:
recoverContext(c)
c.inGenericInst = oldInGenericInst
c.genericInstStack.setLen oldgenericInstStackLen
msgs.setInfoContextLen(c.config, oldContextLen)
if getCurrentException() of ESuggestDone:
c.suggestionsMade = true
Expand Down
1 change: 1 addition & 0 deletions compiler/semdata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ type
compilesContextId*: int # > 0 if we are in a ``compiles`` magic
compilesContextIdGenerator*: int
inGenericInst*: int # > 0 if we are instantiating a generic
genericInstStack*: seq[PSym] #
converters*: seq[PSym]
patterns*: seq[PSym] # sequence of pattern matchers
optionStack*: seq[POptionEntry]
Expand Down
11 changes: 9 additions & 2 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2149,6 +2149,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
let oldInGenericContext = c.inGenericContext
let oldInUnrolledContext = c.inUnrolledContext
let oldInGenericInst = c.inGenericInst
let oldgenericInstStackLen = c.genericInstStack.len
let oldInStaticContext = c.inStaticContext
let oldProcCon = c.p
c.generics = @[]
Expand All @@ -2167,6 +2168,10 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
c.inGenericContext = oldInGenericContext
c.inUnrolledContext = oldInUnrolledContext
c.inGenericInst = oldInGenericInst

assert c.genericInstStack.len >= oldgenericInstStackLen
c.genericInstStack.setLen oldgenericInstStackLen

c.inStaticContext = oldInStaticContext
c.p = oldProcCon
msgs.setInfoContextLen(c.config, oldContextLen)
Expand Down Expand Up @@ -2723,7 +2728,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
defer:
if isCompilerDebug():
echo ("<", c.config$n.info, n, ?.result.typ)

result = n
if c.config.cmd == cmdIdeTools: suggestExpr(c, n)
if nfSem in n.flags: return
Expand Down Expand Up @@ -3005,7 +3009,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
for i in 0..<n.len:
n[i] = semExpr(c, n[i])
of nkComesFrom: discard "ignore the comes from information for now"
of nkMixinStmt: discard
of nkMixinStmt:
for ni in n:
if ni.kind == nkOpenSymChoice and ni.len == 1 and ni[0].sym.kind == skMixin:
addDecl(c, ni[0].sym)
of nkBindStmt:
if c.p != nil:
if n.len > 0 and n[0].kind == nkSym:
Expand Down
30 changes: 20 additions & 10 deletions compiler/semgnrc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -178,14 +178,16 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =

proc semGenericStmt(c: PContext, n: PNode,
flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
when defined(nimCompilerStackraceHints):
setFrameMsg c.config$n.info & " " & $n.kind

result = n

when defined(nimsuggest):
if withinTypeDesc in flags: inc c.inTypeContext

#if conf.cmd == cmdIdeTools: suggestStmt(c, n)
semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)

case n.kind
of nkIdent, nkAccQuoted:
result = lookup(c, n, flags, ctx)
Expand Down Expand Up @@ -488,7 +490,15 @@ proc semGenericStmt(c: PContext, n: PNode,
else: body = n[bodyPos]
n[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
closeScope(c)
of nkPragma, nkPragmaExpr: discard
of nkPragma, nkPragmaExpr:
# similar to treatment in `semTemplBody`
for i in 0..<n.len:
if n[i].kind == nkExprColonExpr:
if n[i][0].kind == nkIdent and getIdent(c.cache, $wPragma) == n[i][0].ident:
# handles: `{.pragma: myprag, inline.}`, where `myprag` shouldn't be passed through `semGenericStmt`
discard
else:
result[i][1] = semGenericStmt(c, n[i][1], flags, ctx)
of nkExprColonExpr, nkExprEqExpr:
checkMinSonsLen(n, 2, c.config)
result[1] = semGenericStmt(c, n[1], flags, ctx)
Expand All @@ -499,17 +509,17 @@ proc semGenericStmt(c: PContext, n: PNode,
when defined(nimsuggest):
if withinTypeDesc in flags: dec c.inTypeContext

proc semGenericStmt(c: PContext, n: PNode): PNode =
proc semGenericStmtImpl(c: PContext, n: PNode, flags: TSemGenericFlags): PNode {.inline.} =
var ctx: GenericCtx
ctx.toMixin = initIntSet()
ctx.toBind = initIntSet()
result = semGenericStmt(c, n, {}, ctx)
result = semGenericStmt(c, n, flags, ctx)
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)

proc semConceptBody(c: PContext, n: PNode): PNode =
var ctx: GenericCtx
ctx.toMixin = initIntSet()
ctx.toBind = initIntSet()
result = semGenericStmt(c, n, {withinConcept}, ctx)
semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
proc semGenericStmt(c: PContext, n: PNode): PNode = semGenericStmtImpl(c, n, {})

proc semGenericStmtInTypeSection(c: PContext, n: PNode): PNode =
# xxx consider merging with `semGenericStmt`
result = semGenericStmt(c, n)

proc semConceptBody(c: PContext, n: PNode): PNode = semGenericStmtImpl(c, n, {withinConcept})
Loading