* fixes #11225; generic sandwich problems; [backport:1.2] * progress * delegating these symbols must be done via 'bind'
This commit is contained in:
parent
083eeda085
commit
2f213db7ee
24 changed files with 132 additions and 21 deletions
|
|
@ -2909,6 +2909,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
inc p.splitDecls
|
inc p.splitDecls
|
||||||
genGotoState(p, n)
|
genGotoState(p, n)
|
||||||
of nkBreakState: genBreakState(p, n, d)
|
of nkBreakState: genBreakState(p, n, d)
|
||||||
|
of nkMixinStmt, nkBindStmt: discard
|
||||||
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
|
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
|
||||||
|
|
||||||
proc genNamedConstExpr(p: BProc, n: PNode; isConst: bool): Rope =
|
proc genNamedConstExpr(p: BProc, n: PNode; isConst: bool): Rope =
|
||||||
|
|
|
||||||
|
|
@ -860,7 +860,8 @@ proc containsResult(n: PNode): bool =
|
||||||
for i in 0..<n.safeLen:
|
for i in 0..<n.safeLen:
|
||||||
if containsResult(n[i]): return true
|
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
|
declarativeDefs
|
||||||
|
|
||||||
proc easyResultAsgn(n: PNode): PNode =
|
proc easyResultAsgn(n: PNode): PNode =
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ type
|
||||||
|
|
||||||
const
|
const
|
||||||
nkSkip = {nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt,
|
nkSkip = {nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt,
|
||||||
nkCommentStmt} + procDefs
|
nkCommentStmt, nkMixinStmt, nkBindStmt} + procDefs
|
||||||
|
|
||||||
proc newStateAccess(ctx: var Ctx): PNode =
|
proc newStateAccess(ctx: var Ctx): PNode =
|
||||||
if ctx.stateVarSym.isNil:
|
if ctx.stateVarSym.isNil:
|
||||||
|
|
|
||||||
|
|
@ -884,7 +884,8 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
|
||||||
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
||||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr:
|
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
|
||||||
|
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock:
|
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock:
|
||||||
|
|
|
||||||
|
|
@ -2626,7 +2626,8 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of nkRaiseStmt: genRaiseStmt(p, n)
|
of nkRaiseStmt: genRaiseStmt(p, n)
|
||||||
of nkTypeSection, nkCommentStmt, nkIncludeStmt,
|
of nkTypeSection, nkCommentStmt, nkIncludeStmt,
|
||||||
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
||||||
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: discard
|
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt,
|
||||||
|
nkMixinStmt, nkBindStmt: discard
|
||||||
of nkIteratorDef:
|
of nkIteratorDef:
|
||||||
if n[0].sym.typ.callConv == TCallingConvention.ccClosure:
|
if n[0].sym.typ.callConv == TCallingConvention.ccClosure:
|
||||||
globalError(p.config, n.info, "Closure iterators are not supported by JS backend!")
|
globalError(p.config, n.info, "Closure iterators are not supported by JS backend!")
|
||||||
|
|
|
||||||
|
|
@ -497,7 +497,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||||
w = up
|
w = up
|
||||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit,
|
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit,
|
||||||
nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef,
|
nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef,
|
||||||
nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt, nkTypeOfExpr:
|
nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt,
|
||||||
|
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
|
||||||
discard
|
discard
|
||||||
of nkLambdaKinds, nkIteratorDef:
|
of nkLambdaKinds, nkIteratorDef:
|
||||||
if n.typ != nil:
|
if n.typ != nil:
|
||||||
|
|
@ -752,7 +753,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
|
||||||
result = accessViaEnvVar(n, owner, d, c)
|
result = accessViaEnvVar(n, owner, d, c)
|
||||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom,
|
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom,
|
||||||
nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef, nkConverterDef,
|
nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef, nkConverterDef,
|
||||||
nkMacroDef, nkFuncDef:
|
nkMacroDef, nkFuncDef, nkMixinStmt, nkBindStmt:
|
||||||
discard
|
discard
|
||||||
of nkClosure:
|
of nkClosure:
|
||||||
if n[1].kind == nkNilLit:
|
if n[1].kind == nkNilLit:
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ proc liftLocals(n: PNode; i: int; c: var Ctx) =
|
||||||
of nkSym:
|
of nkSym:
|
||||||
if interestingVar(it.sym):
|
if interestingVar(it.sym):
|
||||||
n[i] = lookupOrAdd(c, it.sym, it.info)
|
n[i] = lookupOrAdd(c, it.sym, it.info)
|
||||||
of procDefs, nkTypeSection: discard
|
of procDefs, nkTypeSection, nkMixinStmt, nkBindStmt: discard
|
||||||
else:
|
else:
|
||||||
for i in 0..<it.safeLen:
|
for i in 0..<it.safeLen:
|
||||||
liftLocals(it, i, c)
|
liftLocals(it, i, c)
|
||||||
|
|
|
||||||
|
|
@ -1260,7 +1260,8 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check =
|
||||||
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
||||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
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"
|
discard "don't follow this : same as varpartitions"
|
||||||
result = Check(nilability: Nil, map: map)
|
result = Check(nilability: Nil, map: map)
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,8 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) =
|
||||||
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
||||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr:
|
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
|
||||||
|
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
|
||||||
discard "do not follow the construct"
|
discard "do not follow the construct"
|
||||||
|
|
||||||
of nkAsgn, nkFastAsgn:
|
of nkAsgn, nkFastAsgn:
|
||||||
|
|
@ -249,7 +250,8 @@ proc opt(c: Con; n, parent: PNode; parentPos: int) =
|
||||||
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
||||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
||||||
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr:
|
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr,
|
||||||
|
nkMixinStmt, nkBindStmt:
|
||||||
parent[parentPos] = n
|
parent[parentPos] = n
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev
|
||||||
decl(a[1])
|
decl(a[1])
|
||||||
else:
|
else:
|
||||||
for i in 0..<n.safeLen: deps(n[i])
|
for i in 0..<n.safeLen: deps(n[i])
|
||||||
|
of nkMixinStmt, nkBindStmt: discard
|
||||||
else:
|
else:
|
||||||
for i in 0..<n.safeLen: deps(n[i])
|
for i in 0..<n.safeLen: deps(n[i])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ type
|
||||||
mappingExists*: bool
|
mappingExists*: bool
|
||||||
mapping*: TIdTable
|
mapping*: TIdTable
|
||||||
caseContext*: seq[tuple[n: PNode, idx: int]]
|
caseContext*: seq[tuple[n: PNode, idx: int]]
|
||||||
|
localBindStmts*: seq[PNode]
|
||||||
|
|
||||||
TMatchedConcept* = object
|
TMatchedConcept* = object
|
||||||
candidateType*: PType
|
candidateType*: PType
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# bug #12741, redundant error messages are the lesser evil here:
|
# bug #12741, redundant error messages are the lesser evil here:
|
||||||
localError(c.config, n.info, errExprXHasNoType %
|
localError(c.config, n.info, errExprXHasNoType %
|
||||||
renderTree(result, {renderNoComments}))
|
renderTree(result, {renderNoComments}))
|
||||||
|
|
||||||
if isEmpty:
|
if isEmpty:
|
||||||
# do not produce another redundant error message:
|
# do not produce another redundant error message:
|
||||||
result = errorNode(c, n)
|
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)
|
n = newIdentNode(getIdent(c.cache, $quotes.len), n.info)
|
||||||
ids.add n
|
ids.add n
|
||||||
return
|
return
|
||||||
|
|
||||||
template handlePrefixOp(prefixed) =
|
template handlePrefixOp(prefixed) =
|
||||||
if prefixed[0].kind == nkIdent:
|
if prefixed[0].kind == nkIdent:
|
||||||
let examinedOp = prefixed[0].ident.s
|
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:
|
for i in 0..<n.len:
|
||||||
n[i] = semExpr(c, n[i])
|
n[i] = semExpr(c, n[i])
|
||||||
of nkComesFrom: discard "ignore the comes from information for now"
|
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:
|
else:
|
||||||
localError(c.config, n.info, "invalid expression: " &
|
localError(c.config, n.info, "invalid expression: " &
|
||||||
renderTree(n, {renderNoComments}))
|
renderTree(n, {renderNoComments}))
|
||||||
|
|
|
||||||
|
|
@ -318,6 +318,14 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||||
prc.typ = result
|
prc.typ = result
|
||||||
popInfoContext(c.config)
|
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,
|
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
info: TLineInfo): PSym {.nosinks.} =
|
info: TLineInfo): PSym {.nosinks.} =
|
||||||
## Generates a new instance of a generic procedure.
|
## Generates a new instance of a generic procedure.
|
||||||
|
|
@ -344,6 +352,10 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
result.ast = n
|
result.ast = n
|
||||||
pushOwner(c, result)
|
pushOwner(c, result)
|
||||||
|
|
||||||
|
# mixin scope:
|
||||||
|
openScope(c)
|
||||||
|
fillMixinScope(c)
|
||||||
|
|
||||||
openScope(c)
|
openScope(c)
|
||||||
let gp = n[genericParamsPos]
|
let gp = n[genericParamsPos]
|
||||||
internalAssert c.config, gp.kind != nkEmpty
|
internalAssert c.config, gp.kind != nkEmpty
|
||||||
|
|
@ -394,6 +406,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
popProcCon(c)
|
popProcCon(c)
|
||||||
popInfoContext(c.config)
|
popInfoContext(c.config)
|
||||||
closeScope(c) # close scope for parameters
|
closeScope(c) # close scope for parameters
|
||||||
|
closeScope(c) # close scope for 'mixin' declarations
|
||||||
popOwner(c)
|
popOwner(c)
|
||||||
c.currentScope = oldScope
|
c.currentScope = oldScope
|
||||||
discard c.friendModules.pop()
|
discard c.friendModules.pop()
|
||||||
|
|
|
||||||
|
|
@ -391,7 +391,8 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
|
||||||
addFactNeg(c.guards, canon(n[0], c.graph.operators))
|
addFactNeg(c.guards, canon(n[0], c.graph.operators))
|
||||||
dec c.inLoop
|
dec c.inLoop
|
||||||
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
|
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
|
||||||
nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef:
|
nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef,
|
||||||
|
nkMixinStmt, nkBindStmt, nkExportStmt:
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
analyseSons(c, n)
|
analyseSons(c, n)
|
||||||
|
|
|
||||||
|
|
@ -1823,8 +1823,8 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
|
||||||
let t = tt[col]
|
let t = tt[col]
|
||||||
if t != nil and t.kind == tyGenericInvocation:
|
if t != nil and t.kind == tyGenericInvocation:
|
||||||
var x = skipTypes(t[0], {tyVar, tyLent, tyPtr, tyRef, tyGenericInst,
|
var x = skipTypes(t[0], {tyVar, tyLent, tyPtr, tyRef, tyGenericInst,
|
||||||
tyGenericInvocation, tyGenericBody,
|
tyGenericInvocation, tyGenericBody,
|
||||||
tyAlias, tySink, tyOwned})
|
tyAlias, tySink, tyOwned})
|
||||||
if x.kind == tyObject and t.len-1 == n[genericParamsPos].len:
|
if x.kind == tyObject and t.len-1 == n[genericParamsPos].len:
|
||||||
foundObj = true
|
foundObj = true
|
||||||
addMethodToGeneric(c.graph, c.module.position, x, col, s)
|
addMethodToGeneric(c.graph, c.module.position, x, col, s)
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
|
||||||
a = nextOverloadIter(o, c, n)
|
a = nextOverloadIter(o, c, n)
|
||||||
|
|
||||||
proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
|
proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
|
||||||
|
result = copyNode(n)
|
||||||
for i in 0..<n.len:
|
for i in 0..<n.len:
|
||||||
var a = n[i]
|
var a = n[i]
|
||||||
# If 'a' is an overloaded symbol, we used to use the first symbol
|
# 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)
|
let sc = symChoice(c, n, s, scClosed)
|
||||||
if sc.kind == nkSym:
|
if sc.kind == nkSym:
|
||||||
toBind.incl(sc.sym.id)
|
toBind.incl(sc.sym.id)
|
||||||
|
result.add sc
|
||||||
else:
|
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:
|
else:
|
||||||
illFormedAst(a, c.config)
|
illFormedAst(a, c.config)
|
||||||
result = newNodeI(nkEmpty, n.info)
|
|
||||||
|
|
||||||
proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
|
proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
|
||||||
|
result = copyNode(n)
|
||||||
for i in 0..<n.len:
|
for i in 0..<n.len:
|
||||||
toMixin.incl(considerQuotedIdent(c, n[i]).id)
|
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) =
|
proc replaceIdentBySym(c: PContext; n: var PNode, s: PNode) =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
|
||||||
|
|
@ -971,7 +971,7 @@ proc transform(c: PTransf, n: PNode): PNode =
|
||||||
of nkConstSection:
|
of nkConstSection:
|
||||||
# do not replace ``const c = 3`` with ``const 3 = 3``
|
# do not replace ``const c = 3`` with ``const 3 = 3``
|
||||||
return transformConstSection(c, n)
|
return transformConstSection(c, n)
|
||||||
of nkTypeSection, nkTypeOfExpr:
|
of nkTypeSection, nkTypeOfExpr, nkMixinStmt, nkBindStmt:
|
||||||
# no need to transform type sections:
|
# no need to transform type sections:
|
||||||
return n
|
return n
|
||||||
of nkVarSection, nkLetSection:
|
of nkVarSection, nkLetSection:
|
||||||
|
|
|
||||||
|
|
@ -631,7 +631,8 @@ const
|
||||||
nkTypeSection, nkProcDef, nkConverterDef,
|
nkTypeSection, nkProcDef, nkConverterDef,
|
||||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||||
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
|
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) =
|
proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) =
|
||||||
if constParameters in c.goals and tfNoSideEffect in callee.flags:
|
if constParameters in c.goals and tfNoSideEffect in callee.flags:
|
||||||
|
|
|
||||||
|
|
@ -2118,7 +2118,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||||
else:
|
else:
|
||||||
dest = tmp0
|
dest = tmp0
|
||||||
of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
|
of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
|
||||||
nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt:
|
nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt,
|
||||||
|
nkMixinStmt, nkBindStmt:
|
||||||
unused(c, n, dest)
|
unused(c, n, dest)
|
||||||
of nkStringToCString, nkCStringToString:
|
of nkStringToCString, nkCStringToString:
|
||||||
gen(c, n[0], dest)
|
gen(c, n[0], dest)
|
||||||
|
|
|
||||||
|
|
@ -5118,6 +5118,50 @@ scope is the default.
|
||||||
``bind`` statements only make sense in templates and generics.
|
``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
|
Templates
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
|
|
||||||
6
tests/sandwich/generic_library.nim
Normal file
6
tests/sandwich/generic_library.nim
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
proc libraryFunc*[T](x: T) =
|
||||||
|
mixin mixedIn, indirectlyMixedIn
|
||||||
|
echo mixedIn()
|
||||||
|
echo indirectlyMixedIn()
|
||||||
|
|
||||||
3
tests/sandwich/helper_module.nim
Normal file
3
tests/sandwich/helper_module.nim
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
proc indirectlyMixedIn*: int =
|
||||||
|
200
|
||||||
12
tests/sandwich/module_using_generic_library.nim
Normal file
12
tests/sandwich/module_using_generic_library.nim
Normal file
|
|
@ -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
tests/sandwich/tmain.nim
Normal file
9
tests/sandwich/tmain.nim
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
discard """
|
||||||
|
output: '''100
|
||||||
|
200'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import
|
||||||
|
module_using_generic_library
|
||||||
|
|
||||||
|
makeUseOfLibrary "test"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue