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 Dec 7, 2021
1 parent 79f95a2 commit a34845b
Show file tree
Hide file tree
Showing 21 changed files with 120 additions and 14 deletions.
1 change: 1 addition & 0 deletions compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2741,6 +2741,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 @@ -838,7 +838,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 @@ -945,7 +945,8 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState:
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkMixinStmt, nkBindStmt:
result = n
of nkBreakStmt:
inc c.hasUnstructuredCf
Expand Down
3 changes: 2 additions & 1 deletion compiler/jsgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2479,7 +2479,8 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkRaiseStmt: genRaiseStmt(p, n)
of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: discard
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt,
nkMixinStmt, nkBindStmt: discard
of nkPragma: genPragma(p, n)
of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
var s = n[namePos].sym
Expand Down
5 changes: 3 additions & 2 deletions compiler/lambdalifting.nim
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,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 @@ -747,7 +748,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
1 change: 1 addition & 0 deletions compiler/reorder.nim
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,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 @@ -2833,6 +2833,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 =
## 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 @@ -1828,8 +1828,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
7 changes: 5 additions & 2 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,11 +100,13 @@ 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)
Expand Down
2 changes: 1 addition & 1 deletion compiler/transf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,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/vmgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2106,7 +2106,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 @@ -4789,6 +4789,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 a34845b

Please sign in to comment.