diff options
-rw-r--r-- | compiler/ccgexprs.nim | 1 | ||||
-rw-r--r-- | compiler/cgen.nim | 3 | ||||
-rw-r--r-- | compiler/closureiters.nim | 2 | ||||
-rw-r--r-- | compiler/injectdestructors.nim | 3 | ||||
-rw-r--r-- | compiler/jsgen.nim | 3 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 5 | ||||
-rw-r--r-- | compiler/liftlocals.nim | 2 | ||||
-rw-r--r-- | compiler/nilcheck.nim | 3 | ||||
-rw-r--r-- | compiler/optimizer.nim | 6 | ||||
-rw-r--r-- | compiler/reorder.nim | 1 | ||||
-rw-r--r-- | compiler/semdata.nim | 1 | ||||
-rw-r--r-- | compiler/semexprs.nim | 11 | ||||
-rw-r--r-- | compiler/seminst.nim | 13 | ||||
-rw-r--r-- | compiler/semparallel.nim | 3 | ||||
-rw-r--r-- | compiler/semstmts.nim | 4 | ||||
-rw-r--r-- | compiler/semtempl.nim | 10 | ||||
-rw-r--r-- | compiler/transf.nim | 2 | ||||
-rw-r--r-- | compiler/varpartitions.nim | 3 | ||||
-rw-r--r-- | compiler/vmgen.nim | 3 | ||||
-rw-r--r-- | doc/manual.rst | 44 | ||||
-rw-r--r-- | tests/sandwich/generic_library.nim | 6 | ||||
-rw-r--r-- | tests/sandwich/helper_module.nim | 3 | ||||
-rw-r--r-- | tests/sandwich/module_using_generic_library.nim | 12 | ||||
-rw-r--r-- | tests/sandwich/tmain.nim | 9 |
24 files changed, 132 insertions, 21 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index e30397107..2a8af5c41 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2909,6 +2909,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 = diff --git a/compiler/cgen.nim b/compiler/cgen.nim index f87082866..5de23649f 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -860,7 +860,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 = diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 2270797ea..e474e5ba2 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -157,7 +157,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: diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 8cfd14cc4..6010ba43d 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -884,7 +884,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: diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 0e71162d7..3fc7708bf 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2626,7 +2626,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!") diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 8eaa9e1e2..6f43649a1 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -497,7 +497,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: @@ -752,7 +753,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var 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: diff --git a/compiler/liftlocals.nim b/compiler/liftlocals.nim index 0b46c73a2..7ca46ab1b 100644 --- a/compiler/liftlocals.nim +++ b/compiler/liftlocals.nim @@ -43,7 +43,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) diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim index d0ef45d04..b779830d6 100644 --- a/compiler/nilcheck.nim +++ b/compiler/nilcheck.nim @@ -1260,7 +1260,8 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = 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 "don't follow this : same as varpartitions" result = Check(nilability: Nil, map: map) diff --git a/compiler/optimizer.nim b/compiler/optimizer.nim index 5d1139bfd..744c82ab5 100644 --- a/compiler/optimizer.nim +++ b/compiler/optimizer.nim @@ -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: @@ -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: diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 3eb47941e..d2b89f392 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -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]) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 174d6a0b2..8c65939d4 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -42,6 +42,7 @@ type mappingExists*: bool mapping*: TIdTable caseContext*: seq[tuple[n: PNode, idx: int]] + localBindStmts*: seq[PNode] TMatchedConcept* = object candidateType*: PType diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 41f0ef48a..a7cc235c0 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -75,7 +75,7 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode = # bug #12741, redundant error messages are the lesser evil here: localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) - + if isEmpty: # do not produce another redundant error message: result = errorNode(c, n) @@ -2021,7 +2021,7 @@ proc processQuotations(c: PContext; n: var PNode, op: string, n = newIdentNode(getIdent(c.cache, $quotes.len), n.info) ids.add n return - + template handlePrefixOp(prefixed) = if prefixed[0].kind == nkIdent: let examinedOp = prefixed[0].ident.s @@ -2954,6 +2954,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})) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 845929648..62cbdbcc1 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -318,6 +318,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. @@ -344,6 +352,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 @@ -394,6 +406,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() diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index d0fc329a0..1dc9a1dfd 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -391,7 +391,8 @@ proc analyse(c: var AnalysisCtx; n: PNode) = addFactNeg(c.guards, canon(n[0], c.graph.operators)) 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) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 47d9061e6..1fe540a65 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1823,8 +1823,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 addMethodToGeneric(c.graph, c.module.position, x, col, s) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 1e6cd88b7..2f87fb8f2 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -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 @@ -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 diff --git a/compiler/transf.nim b/compiler/transf.nim index 4e83ec1df..d2d9156aa 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -971,7 +971,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: diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 3093fb38f..7bb626c0a 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -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: diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index a1fcf5a8a..392fe9737 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -2118,7 +2118,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) diff --git a/doc/manual.rst b/doc/manual.rst index 4884db0e1..ba7ef5059 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -5118,6 +5118,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 ========= diff --git a/tests/sandwich/generic_library.nim b/tests/sandwich/generic_library.nim new file mode 100644 index 000000000..43e7bd65f --- /dev/null +++ b/tests/sandwich/generic_library.nim @@ -0,0 +1,6 @@ + +proc libraryFunc*[T](x: T) = + mixin mixedIn, indirectlyMixedIn + echo mixedIn() + echo indirectlyMixedIn() + diff --git a/tests/sandwich/helper_module.nim b/tests/sandwich/helper_module.nim new file mode 100644 index 000000000..d003bf044 --- /dev/null +++ b/tests/sandwich/helper_module.nim @@ -0,0 +1,3 @@ + +proc indirectlyMixedIn*: int = + 200 diff --git a/tests/sandwich/module_using_generic_library.nim b/tests/sandwich/module_using_generic_library.nim new file mode 100644 index 000000000..bbb0d92a4 --- /dev/null +++ b/tests/sandwich/module_using_generic_library.nim @@ -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" diff --git a/tests/sandwich/tmain.nim b/tests/sandwich/tmain.nim new file mode 100644 index 000000000..aa50bfb04 --- /dev/null +++ b/tests/sandwich/tmain.nim @@ -0,0 +1,9 @@ +discard """ + output: '''100 +200''' +""" + +import + module_using_generic_library + +makeUseOfLibrary "test" |