new gensym handling (#11985)

* new .gensym implementation
* make astspec test green again
* introduce a --useVersion switch to group compatibility switches
* fixes #10180
* fixes #11494 
* fixes #11483
* object constructor fields and named parameters are also not gensym'ed
* disabled broken package
This commit is contained in:
Andreas Rumpf 2019-08-23 16:15:02 +02:00 • committed by GitHub
commit b07694cd90
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 346 additions and 114 deletions

View file

@ -788,6 +788,15 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "expandmacro":
expectArg(conf, switch, arg, pass, info)
conf.macrosToExpand[arg] = "T"
of "useversion":
expectArg(conf, switch, arg, pass, info)
case arg
of "0.19":
conf.globalOptions.incl optNimV019
of "1.0":
discard "the default"
else:
localError(conf, info, "unknown Nim version; currently supported values are: {0.19, 1.0}")
of "":
conf.projectName = "-"
else:

View file

@ -10,7 +10,7 @@
## Template evaluation engine. Now hygienic.
import
strutils, options, ast, astalgo, msgs, renderer, lineinfos
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents
type
TemplCtx = object
@ -20,6 +20,7 @@ type
mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
# new symbol
config: ConfigRef
ic: IdentCache
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
result = copyNode(a)
@ -52,7 +53,11 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
#if x.kind == skParam and x.owner.kind == skModule:
# internalAssert c.config, false
idTablePut(c.mapping, s, x)
result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
if sfGenSym in s.flags and optNimV019 notin c.config.globalOptions:
result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $x.id),
if c.instLines: actual.info else: templ.info)
else:
result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
else:
result.add copyNode(c, templ, actual)
of nkNone..nkIdent, nkType..nkNilLit: # atom
@ -160,7 +165,9 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
result.typ = res.typ
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
conf: ConfigRef; fromHlo=false): PNode =
conf: ConfigRef;
ic: IdentCache;
fromHlo=false): PNode =
inc(conf.evalTemplateCounter)
if conf.evalTemplateCounter > evalTemplateLimit:
globalError(conf, n.info, errTemplateInstantiationTooNested)
@ -172,6 +179,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
ctx.owner = tmpl
ctx.genSymOwner = genSymOwner
ctx.config = conf
ctx.ic = ic
initIdTable(ctx.mapping)
let body = tmpl.getBody

View file

@ -18,7 +18,7 @@ import
sem, idents, passes, extccomp,
cgen, json, nversion,
platform, nimconf, passaux, depends, vm, idgen,
parser, modules,
modules,
modulegraphs, tables, rod, lineinfos, pathutils
when not defined(leanCompiler):

View file

@ -84,6 +84,7 @@ type # please make sure we have under 32 options
optDynlibOverrideAll
optNimV2
optMultiMethods
optNimV019
TGlobalOptions* = set[TGlobalOption]

View file

@ -30,7 +30,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
# Note: This is n.info on purpose. It prevents template from creating an info
# context when called from an another template
pushInfoContext(c.config, n.info, s.detailedInfo)
result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags)
result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache, efFromHlo in flags)
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
popInfoContext(c.config)
@ -1236,6 +1236,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
result = newSymNode(s, n.info)
else:
let info = getCallLineInfo(n)
#if efInCall notin flags:
markUsed(c, info, s)
onUse(info, s)
result = newSymNode(s, info)

View file

@ -47,7 +47,8 @@ type
TSymChoiceRule = enum
scClosed, scOpen, scForceOpen
proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
isField = false): PNode =
var
a: PSym
o: TOverloadIter
@ -63,9 +64,12 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
# XXX this makes more sense but breaks bootstrapping for now:
# (s.kind notin routineKinds or s.magic != mNone):
# for instance 'nextTry' is both in tables.nim and astalgo.nim ...
result = newSymNode(s, info)
markUsed(c, info, s)
onUse(info, s)
if not isField or sfGenSym notin s.flags:
result = newSymNode(s, info)
markUsed(c, info, s)
onUse(info, s)
else:
result = n
else:
# semantic checking requires a type; ``fitNode`` deals with it
# appropriately
@ -74,7 +78,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
result = newNodeIT(kind, info, newTypeS(tyNone, c))
a = initOverloadIter(o, c, n)
while a != nil:
if a.kind != skModule:
if a.kind != skModule and (not isField or sfGenSym notin s.flags):
incl(a.flags, sfUsed)
addSon(result, newSymNode(a, info))
onUse(info, a)
@ -119,6 +123,7 @@ type
owner: PSym
cursorInBody: bool # only for nimsuggest
scopeN: int
noGenSym: int
template withBracketExpr(ctx, x, body: untyped) =
body
@ -228,7 +233,7 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
else:
replaceIdentBySym(c.c, n, ident)
proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode =
incl(s.flags, sfUsed)
# we do not call onUse here, as the identifier is not really
# resolved here. We will fixup the used identifiers later.
@ -237,15 +242,18 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
# Introduced in this pass! Leave it as an identifier.
result = n
of OverloadableSyms:
result = symChoice(c, n, s, scOpen)
result = symChoice(c, n, s, scOpen, isField)
of skGenericParam:
result = newSymNodeTypeDesc(s, n.info)
if isField: result = n
else: result = newSymNodeTypeDesc(s, n.info)
of skParam:
result = n
of skType:
result = newSymNodeTypeDesc(s, n.info)
if isField: result = n
else: result = newSymNodeTypeDesc(s, n.info)
else:
result = newSymNode(s, n.info)
if isField: result = n
else: result = newSymNode(s, n.info)
proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
result = n
@ -322,22 +330,23 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
if n.ident.id in c.toInject: return n
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and s.kind == skParam:
if s.owner == c.owner and s.kind == skParam and
(sfGenSym notin s.flags or c.noGenSym == 0):
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
onUse(n.info, s)
elif contains(c.toBind, s.id):
result = symChoice(c.c, n, s, scClosed)
result = symChoice(c.c, n, s, scClosed, c.noGenSym > 0)
elif contains(c.toMixin, s.name.id):
result = symChoice(c.c, n, s, scForceOpen)
elif s.owner == c.owner and sfGenSym in s.flags:
result = symChoice(c.c, n, s, scForceOpen, c.noGenSym > 0)
elif s.owner == c.owner and sfGenSym in s.flags and c.noGenSym == 0:
# template tmp[T](x: var seq[T]) =
# var yz: T
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
onUse(n.info, s)
else:
result = semTemplSymbol(c.c, n, s)
result = semTemplSymbol(c.c, n, s, c.noGenSym > 0)
of nkBind:
result = semTemplBody(c, n.sons[0])
of nkBindStmt:
@ -524,12 +533,27 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
onUse(n.info, s)
return newSymNode(s, n.info)
elif contains(c.toBind, s.id):
return symChoice(c.c, n, s, scClosed)
return symChoice(c.c, n, s, scClosed, c.noGenSym > 0)
elif contains(c.toMixin, s.name.id):
return symChoice(c.c, n, s, scForceOpen)
return symChoice(c.c, n, s, scForceOpen, c.noGenSym > 0)
else:
return symChoice(c.c, n, s, scOpen)
result = semTemplBodySons(c, n)
return symChoice(c.c, n, s, scOpen, c.noGenSym > 0)
if n.kind == nkDotExpr:
result = n
result.sons[0] = semTemplBody(c, n.sons[0])
inc c.noGenSym
result.sons[1] = semTemplBody(c, n.sons[1])
dec c.noGenSym
else:
result = semTemplBodySons(c, n)
of nkExprColonExpr, nkExprEqExpr:
if n.len == 2:
inc c.noGenSym
result.sons[0] = semTemplBody(c, n.sons[0])
dec c.noGenSym
result.sons[1] = semTemplBody(c, n.sons[1])
else:
result = semTemplBodySons(c, n)
else:
result = semTemplBodySons(c, n)

View file

@ -261,15 +261,15 @@ proc getQuality(s: PSym): range[0..100] =
if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: return 50
return 100
template wholeSymTab(cond, section: untyped) =
template wholeSymTab(cond, section: untyped) {.dirty.} =
var isLocal = true
var scopeN = 0
for scope in walkScopes(c.currentScope):
if scope == c.topLevelScope: isLocal = false
dec scopeN
for item in scope.symbols:
let it {.inject.} = item
var pm {.inject.}: PrefixMatch
let it = item
var pm: PrefixMatch
if cond:
outputs.add(symToSuggest(c.config, it, isLocal = isLocal, section, info, getQuality(it),
pm, c.inTypeContext > 0, scopeN))

View file

@ -1137,7 +1137,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let node = regs[rb+i].regToNode
node.info = c.debug[pc]
macroCall.add(node)
var a = evalTemplate(macroCall, prc, genSymOwner, c.config)
var a = evalTemplate(macroCall, prc, genSymOwner, c.config, c.cache)
if a.kind == nkStmtList and a.len == 1: a = a[0]
a.recSetFlagIsRef
ensureKind(rkNode)