Skip to content

Commit

Permalink
fixes #11225; generic sandwich problems; [backport:1.2] (#17255)
Browse files Browse the repository at this point in the history
* fixes #11225; generic sandwich problems; [backport:1.2]
* progress
* delegating these symbols must be done via 'bind'

(cherry picked from commit 2f213db)
  • Loading branch information
Araq authored and narimiran committed Mar 18, 2021
1 parent d7eca5b commit d557008
Show file tree
Hide file tree
Showing 23 changed files with 128 additions and 18 deletions.
1 change: 1 addition & 0 deletions compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2852,6 +2852,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
inc p.splitDecls
genGotoState(p, n)
of nkBreakState: genBreakState(p, n, d)
of nkMixinStmt, nkBindStmt: discard
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")

proc genNamedConstExpr(p: BProc, n: PNode; isConst: bool): Rope =
Expand Down
3 changes: 2 additions & 1 deletion compiler/cgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,8 @@ proc containsResult(n: PNode): bool =
for i in 0..<n.safeLen:
if containsResult(n[i]): return true

const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef, nkMacroDef} +
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef,
nkMacroDef, nkMixinStmt, nkBindStmt} +
declarativeDefs

proc easyResultAsgn(n: PNode): PNode =
Expand Down
2 changes: 1 addition & 1 deletion compiler/closureiters.nim
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ type

const
nkSkip = {nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt,
nkCommentStmt} + procDefs
nkCommentStmt, nkMixinStmt, nkBindStmt} + procDefs

proc newStateAccess(ctx: var Ctx): PNode =
if ctx.stateVarSym.isNil:
Expand Down
3 changes: 2 additions & 1 deletion compiler/injectdestructors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,8 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr:
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
result = n

of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock:
Expand Down
3 changes: 2 additions & 1 deletion compiler/jsgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2588,7 +2588,8 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkRaiseStmt: genRaiseStmt(p, n)
of nkTypeSection, nkCommentStmt, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: discard
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt,
nkMixinStmt, nkBindStmt: discard
of nkIteratorDef:
if n[0].sym.typ.callConv == TCallingConvention.ccClosure:
globalError(p.config, n.info, "Closure iterators are not supported by JS backend!")
Expand Down
5 changes: 3 additions & 2 deletions compiler/lambdalifting.nim
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
w = up
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit,
nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef,
nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt, nkTypeOfExpr:
nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt,
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
discard
of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
Expand Down Expand Up @@ -750,7 +751,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
result = accessViaEnvVar(n, owner, d, c)
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom,
nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef, nkConverterDef,
nkMacroDef, nkFuncDef:
nkMacroDef, nkFuncDef, nkMixinStmt, nkBindStmt:
discard
of nkClosure:
if n[1].kind == nkNilLit:
Expand Down
2 changes: 1 addition & 1 deletion compiler/liftlocals.nim
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ proc liftLocals(n: PNode; i: int; c: var Ctx) =
of nkSym:
if interestingVar(it.sym):
n[i] = lookupOrAdd(c, it.sym, it.info)
of procDefs, nkTypeSection: discard
of procDefs, nkTypeSection, nkMixinStmt, nkBindStmt: discard
else:
for i in 0..<it.safeLen:
liftLocals(it, i, c)
Expand Down
6 changes: 4 additions & 2 deletions compiler/optimizer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) =
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr:
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
discard "do not follow the construct"

of nkAsgn, nkFastAsgn:
Expand Down Expand Up @@ -249,7 +250,8 @@ proc opt(c: Con; n, parent: PNode; parentPos: int) =
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr:
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr,
nkMixinStmt, nkBindStmt:
parent[parentPos] = n

else:
Expand Down
1 change: 1 addition & 0 deletions compiler/reorder.nim
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev
decl(a[1])
else:
for i in 0..<n.safeLen: deps(n[i])
of nkMixinStmt, nkBindStmt: discard
else:
for i in 0..<n.safeLen: deps(n[i])

Expand Down
1 change: 1 addition & 0 deletions compiler/semdata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type
mappingExists*: bool
mapping*: TIdTable
caseContext*: seq[tuple[n: PNode, idx: int]]
localBindStmts*: seq[PNode]

TMatchedConcept* = object
candidateType*: PType
Expand Down
7 changes: 7 additions & 0 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2901,6 +2901,13 @@ 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 nkBindStmt:
if c.p != nil:
c.p.localBindStmts.add n
else:
localError(c.config, n.info, "invalid context for 'bind' statement: " &
renderTree(n, {renderNoComments}))
else:
localError(c.config, n.info, "invalid expression: " &
renderTree(n, {renderNoComments}))
Expand Down
13 changes: 13 additions & 0 deletions compiler/seminst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,14 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
prc.typ = result
popInfoContext(c.config)

proc fillMixinScope(c: PContext) =
var p = c.p
while p != nil:
for bnd in p.localBindStmts:
for n in bnd:
addSym(c.currentScope, n.sym)
p = p.next

proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym {.nosinks.} =
## Generates a new instance of a generic procedure.
Expand All @@ -345,6 +353,10 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
result.ast = n
pushOwner(c, result)

# mixin scope:
openScope(c)
fillMixinScope(c)

openScope(c)
let gp = n[genericParamsPos]
internalAssert c.config, gp.kind != nkEmpty
Expand Down Expand Up @@ -395,6 +407,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
popProcCon(c)
popInfoContext(c.config)
closeScope(c) # close scope for parameters
closeScope(c) # close scope for 'mixin' declarations
popOwner(c)
c.currentScope = oldScope
discard c.friendModules.pop()
Expand Down
3 changes: 2 additions & 1 deletion compiler/semparallel.nim
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,8 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
addFactNeg(c.guards, canon(n[0], c.guards.o))
dec c.inLoop
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef:
nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef,
nkMixinStmt, nkBindStmt, nkExportStmt:
discard
else:
analyseSons(c, n)
Expand Down
4 changes: 2 additions & 2 deletions compiler/semstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1822,8 +1822,8 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
let t = tt[col]
if t != nil and t.kind == tyGenericInvocation:
var x = skipTypes(t[0], {tyVar, tyLent, tyPtr, tyRef, tyGenericInst,
tyGenericInvocation, tyGenericBody,
tyAlias, tySink, tyOwned})
tyGenericInvocation, tyGenericBody,
tyAlias, tySink, tyOwned})
if x.kind == tyObject and t.len-1 == n[genericParamsPos].len:
foundObj = true
x.methods.add((col,s))
Expand Down
10 changes: 7 additions & 3 deletions compiler/semtempl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
a = nextOverloadIter(o, c, n)

proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
result = copyNode(n)
for i in 0..<n.len:
var a = n[i]
# If 'a' is an overloaded symbol, we used to use the first symbol
Expand All @@ -99,16 +100,19 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
let sc = symChoice(c, n, s, scClosed)
if sc.kind == nkSym:
toBind.incl(sc.sym.id)
result.add sc
else:
for x in items(sc): toBind.incl(x.sym.id)
for x in items(sc):
toBind.incl(x.sym.id)
result.add x
else:
illFormedAst(a, c.config)
result = newNodeI(nkEmpty, n.info)

proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
result = copyNode(n)
for i in 0..<n.len:
toMixin.incl(considerQuotedIdent(c, n[i]).id)
result = newNodeI(nkEmpty, n.info)
result.add symChoice(c, n[i], nil, scForceOpen)

proc replaceIdentBySym(c: PContext; n: var PNode, s: PNode) =
case n.kind
Expand Down
2 changes: 1 addition & 1 deletion compiler/transf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ proc transform(c: PTransf, n: PNode): PNode =
of nkConstSection:
# do not replace ``const c = 3`` with ``const 3 = 3``
return transformConstSection(c, n)
of nkTypeSection, nkTypeOfExpr:
of nkTypeSection, nkTypeOfExpr, nkMixinStmt, nkBindStmt:
# no need to transform type sections:
return n
of nkVarSection, nkLetSection:
Expand Down
3 changes: 2 additions & 1 deletion compiler/varpartitions.nim
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,8 @@ const
nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr}
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt}

proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) =
if constParameters in c.goals and tfNoSideEffect in callee.flags:
Expand Down
3 changes: 2 additions & 1 deletion compiler/vmgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2103,7 +2103,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
else:
dest = tmp0
of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt:
nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt,
nkMixinStmt, nkBindStmt:
unused(c, n, dest)
of nkStringToCString, nkCStringToString:
gen(c, n[0], dest)
Expand Down
44 changes: 44 additions & 0 deletions doc/manual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5029,6 +5029,50 @@ scope is the default.
``bind`` statements only make sense in templates and generics.


Delegating bind statements
--------------------------

The following example outlines a problem that can arise when generic
instantiations cross multiple different modules:

.. code-block:: nim
# module A
proc genericA*[T](x: T) =
mixin init
init(x)
.. code-block:: nim
import C
# module B
proc genericB*[T](x: T) =
# Without the `bind init` statement C's init proc is
# not available when `genericB` is instantiated:
bind init
genericA(x)
.. code-block:: nim
# module C
type O = object
proc init*(x: var O) = discard
.. code-block:: nim
# module main
import B, C
genericB O()
In module B has an `init` proc from module C in its scope that is not
taken into account when `genericB` is instantiated which leads to the
instantiation of `genericA`. The solution is to `forward`:idx these
symbols by a `bind` statement inside `genericB`.


Templates
=========

Expand Down
6 changes: 6 additions & 0 deletions tests/sandwich/generic_library.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

proc libraryFunc*[T](x: T) =
mixin mixedIn, indirectlyMixedIn
echo mixedIn()
echo indirectlyMixedIn()

3 changes: 3 additions & 0 deletions tests/sandwich/helper_module.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

proc indirectlyMixedIn*: int =
200
12 changes: 12 additions & 0 deletions tests/sandwich/module_using_generic_library.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

import
generic_library, helper_module

proc mixedIn: int = 100

proc makeUseOfLibrary*[T](x: T) =
bind mixedIn, indirectlyMixedIn
libraryFunc(x)

when isMainModule:
makeUseOfLibrary "test"
9 changes: 9 additions & 0 deletions tests/sandwich/tmain.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
discard """
output: '''100
200'''
"""

import
module_using_generic_library

makeUseOfLibrary "test"

0 comments on commit d557008

Please sign in to comment.