Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
commit
a8c8a85135
27 changed files with 652 additions and 326 deletions
|
|
@ -366,12 +366,8 @@ type
|
||||||
tfFromGeneric, # type is an instantiation of a generic; this is needed
|
tfFromGeneric, # type is an instantiation of a generic; this is needed
|
||||||
# because for instantiations of objects, structural
|
# because for instantiations of objects, structural
|
||||||
# type equality has to be used
|
# type equality has to be used
|
||||||
tfInstantiated, # XXX: used to mark generic params after instantiation.
|
tfUnresolved, # marks unresolved typedesc params: e.g.
|
||||||
# if the concrete type happens to be an implicit generic
|
# proc foo(T: typedesc, list: seq[T]): var T
|
||||||
# this can lead to invalid proc signatures in the second
|
|
||||||
# pass of semProcTypeNode performed after instantiation.
|
|
||||||
# this won't be needed if we don't perform this redundant
|
|
||||||
# second pass (stay tuned).
|
|
||||||
tfRetType, # marks return types in proc (used to detect type classes
|
tfRetType, # marks return types in proc (used to detect type classes
|
||||||
# used as return types for return type inference)
|
# used as return types for return type inference)
|
||||||
tfAll, # type class requires all constraints to be met (default)
|
tfAll, # type class requires all constraints to be met (default)
|
||||||
|
|
@ -690,6 +686,8 @@ type
|
||||||
# for record types a nkRecord node
|
# for record types a nkRecord node
|
||||||
# for enum types a list of symbols
|
# for enum types a list of symbols
|
||||||
# for tyInt it can be the int literal
|
# for tyInt it can be the int literal
|
||||||
|
# for procs and tyGenericBody, it's the
|
||||||
|
# formal param list
|
||||||
# else: unused
|
# else: unused
|
||||||
destructor*: PSym # destructor. warning: nil here may not necessary
|
destructor*: PSym # destructor. warning: nil here may not necessary
|
||||||
# mean that there is no destructor.
|
# mean that there is no destructor.
|
||||||
|
|
@ -794,6 +792,7 @@ const
|
||||||
nkStrKinds* = {nkStrLit..nkTripleStrLit}
|
nkStrKinds* = {nkStrLit..nkTripleStrLit}
|
||||||
|
|
||||||
skLocalVars* = {skVar, skLet, skForVar, skParam, skResult}
|
skLocalVars* = {skVar, skLet, skForVar, skParam, skResult}
|
||||||
|
skProcKinds* = {skProc, skTemplate, skMacro, skIterator, skMethod, skConverter}
|
||||||
|
|
||||||
lfFullExternalName* = lfParamCopy # \
|
lfFullExternalName* = lfParamCopy # \
|
||||||
# only used when 'gCmd == cmdPretty': Indicates that the symbol has been
|
# only used when 'gCmd == cmdPretty': Indicates that the symbol has been
|
||||||
|
|
@ -1091,7 +1090,6 @@ proc copyType(t: PType, owner: PSym, keepId: bool): PType =
|
||||||
if keepId:
|
if keepId:
|
||||||
result.id = t.id
|
result.id = t.id
|
||||||
else:
|
else:
|
||||||
result.id = getID()
|
|
||||||
when debugIds: RegisterId(result)
|
when debugIds: RegisterId(result)
|
||||||
result.sym = t.sym # backend-info should not be copied
|
result.sym = t.sym # backend-info should not be copied
|
||||||
|
|
||||||
|
|
@ -1361,10 +1359,19 @@ proc getStrOrChar*(a: PNode): string =
|
||||||
|
|
||||||
proc isGenericRoutine*(s: PSym): bool =
|
proc isGenericRoutine*(s: PSym): bool =
|
||||||
case s.kind
|
case s.kind
|
||||||
of skProc, skTemplate, skMacro, skIterator, skMethod, skConverter:
|
of skProcKinds:
|
||||||
result = s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty
|
result = sfFromGeneric in s.flags or
|
||||||
|
(s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty)
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
|
proc skipGenericOwner*(s: PSym): PSym =
|
||||||
|
InternalAssert s.kind in skProcKinds
|
||||||
|
## Generic instantiations are owned by their originating generic
|
||||||
|
## symbol. This proc skips such owners and goes straigh to the owner
|
||||||
|
## of the generic itself (the module or the enclosing proc).
|
||||||
|
result = if sfFromGeneric in s.flags: s.owner.owner
|
||||||
|
else: s.owner
|
||||||
|
|
||||||
proc isRoutine*(s: PSym): bool {.inline.} =
|
proc isRoutine*(s: PSym): bool {.inline.} =
|
||||||
result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod,
|
result = s.kind in {skProc, skTemplate, skMacro, skIterator, skMethod,
|
||||||
skConverter}
|
skConverter}
|
||||||
|
|
|
||||||
|
|
@ -1937,7 +1937,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
# due to a bug/limitation in the lambda lifting, unused inner procs
|
# due to a bug/limitation in the lambda lifting, unused inner procs
|
||||||
# are not transformed correctly. We work around this issue (#411) here
|
# are not transformed correctly. We work around this issue (#411) here
|
||||||
# by ensuring it's no inner proc (owner is a module):
|
# by ensuring it's no inner proc (owner is a module):
|
||||||
if prc.owner.kind == skModule:
|
if prc.skipGenericOwner.kind == skModule:
|
||||||
if (optDeadCodeElim notin gGlobalOptions and
|
if (optDeadCodeElim notin gGlobalOptions and
|
||||||
sfDeadCodeElim notin getModule(prc).flags) or
|
sfDeadCodeElim notin getModule(prc).flags) or
|
||||||
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||||
var immediateAsgn = a.sons[2].kind != nkEmpty
|
var immediateAsgn = a.sons[2].kind != nkEmpty
|
||||||
if sfGlobal in v.flags:
|
if sfGlobal in v.flags:
|
||||||
if v.owner.kind != skModule:
|
if v.owner.kind != skModule:
|
||||||
targetProc = p.module.preInitProc
|
targetProc = p.module.postInitProc
|
||||||
assignGlobalVar(targetProc, v)
|
assignGlobalVar(targetProc, v)
|
||||||
# XXX: be careful here.
|
# XXX: be careful here.
|
||||||
# Global variables should not be zeromem-ed within loops
|
# Global variables should not be zeromem-ed within loops
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,10 @@
|
||||||
|
|
||||||
# included from cgen.nim
|
# included from cgen.nim
|
||||||
|
|
||||||
proc emulatedThreadVars(): bool {.inline.} =
|
proc emulatedThreadVars(): bool =
|
||||||
result = {optThreads, optTlsEmulation} <= gGlobalOptions
|
result = {optThreads, optTlsEmulation} <= gGlobalOptions
|
||||||
|
|
||||||
proc AccessThreadLocalVar(p: BProc, s: PSym) =
|
proc accessThreadLocalVar(p: BProc, s: PSym) =
|
||||||
if emulatedThreadVars() and not p.ThreadVarAccessed:
|
if emulatedThreadVars() and not p.ThreadVarAccessed:
|
||||||
p.ThreadVarAccessed = true
|
p.ThreadVarAccessed = true
|
||||||
p.module.usesThreadVars = true
|
p.module.usesThreadVars = true
|
||||||
|
|
|
||||||
|
|
@ -127,18 +127,22 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
|
||||||
m.s[cfsProcHeaders].appf("$1;$n", header)
|
m.s[cfsProcHeaders].appf("$1;$n", header)
|
||||||
m.s[cfsProcs].app(generatedProc)
|
m.s[cfsProcs].app(generatedProc)
|
||||||
|
|
||||||
|
|
||||||
proc genTraverseProcForGlobal(m: BModule, s: PSym): PRope =
|
proc genTraverseProcForGlobal(m: BModule, s: PSym): PRope =
|
||||||
discard genTypeInfo(m, s.loc.t)
|
discard genTypeInfo(m, s.loc.t)
|
||||||
|
|
||||||
var c: TTraversalClosure
|
var c: TTraversalClosure
|
||||||
var p = newProc(nil, m)
|
var p = newProc(nil, m)
|
||||||
|
var sLoc = s.loc.r
|
||||||
result = getGlobalTempName()
|
result = getGlobalTempName()
|
||||||
|
|
||||||
|
if sfThread in s.flags and emulatedThreadVars():
|
||||||
|
accessThreadLocalVar(p, s)
|
||||||
|
sLoc = con("NimTV->", sLoc)
|
||||||
|
|
||||||
c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
|
c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
|
||||||
c.p = p
|
c.p = p
|
||||||
let header = ropef("N_NIMCALL(void, $1)()", result)
|
let header = ropef("N_NIMCALL(void, $1)()", result)
|
||||||
genTraverseProc(c, s.loc.r, s.loc.t)
|
genTraverseProc(c, sLoc, s.loc.t)
|
||||||
|
|
||||||
let generatedProc = ropef("$1 {$n$2$3$4}$n",
|
let generatedProc = ropef("$1 {$n$2$3$4}$n",
|
||||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
|
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
|
||||||
|
|
|
||||||
|
|
@ -439,6 +439,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||||
appf(result, "} $1;$n", [uname])
|
appf(result, "} $1;$n", [uname])
|
||||||
of nkSym:
|
of nkSym:
|
||||||
field = n.sym
|
field = n.sym
|
||||||
|
if field.typ.kind == tyEmpty: return
|
||||||
#assert(field.ast == nil)
|
#assert(field.ast == nil)
|
||||||
sname = mangleRecFieldName(field, rectype)
|
sname = mangleRecFieldName(field, rectype)
|
||||||
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
|
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,9 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||||
linefmt(p, cpsStmts, "nimln($1, $2);$n",
|
linefmt(p, cpsStmts, "nimln($1, $2);$n",
|
||||||
line.toRope, t.info.quotedFilename)
|
line.toRope, t.info.quotedFilename)
|
||||||
|
|
||||||
|
proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||||
|
proc emulatedThreadVars(): bool {.inline.}
|
||||||
|
|
||||||
include "ccgtypes.nim"
|
include "ccgtypes.nim"
|
||||||
|
|
||||||
# ------------------------------ Manager of temporaries ------------------
|
# ------------------------------ Manager of temporaries ------------------
|
||||||
|
|
@ -858,7 +861,7 @@ proc isActivated(prc: PSym): bool = prc.typ != nil
|
||||||
proc genProc(m: BModule, prc: PSym) =
|
proc genProc(m: BModule, prc: PSym) =
|
||||||
if sfBorrow in prc.flags or not isActivated(prc): return
|
if sfBorrow in prc.flags or not isActivated(prc): return
|
||||||
fillProcLoc(prc)
|
fillProcLoc(prc)
|
||||||
if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc)
|
if sfForward in prc.flags: addForwardedProc(m, prc)
|
||||||
else:
|
else:
|
||||||
genProcNoForward(m, prc)
|
genProcNoForward(m, prc)
|
||||||
if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
|
if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
|
||||||
|
|
@ -1028,8 +1031,9 @@ proc genInitCode(m: BModule) =
|
||||||
app(prc, initGCFrame(m.initProc))
|
app(prc, initGCFrame(m.initProc))
|
||||||
|
|
||||||
app(prc, genSectionStart(cpsLocals))
|
app(prc, genSectionStart(cpsLocals))
|
||||||
app(prc, m.initProc.s(cpsLocals))
|
|
||||||
app(prc, m.preInitProc.s(cpsLocals))
|
app(prc, m.preInitProc.s(cpsLocals))
|
||||||
|
app(prc, m.initProc.s(cpsLocals))
|
||||||
|
app(prc, m.postInitProc.s(cpsLocals))
|
||||||
app(prc, genSectionEnd(cpsLocals))
|
app(prc, genSectionEnd(cpsLocals))
|
||||||
|
|
||||||
if optStackTrace in m.initProc.options and not m.FrameDeclared:
|
if optStackTrace in m.initProc.options and not m.FrameDeclared:
|
||||||
|
|
@ -1045,11 +1049,13 @@ proc genInitCode(m: BModule) =
|
||||||
app(prc, genSectionStart(cpsInit))
|
app(prc, genSectionStart(cpsInit))
|
||||||
app(prc, m.preInitProc.s(cpsInit))
|
app(prc, m.preInitProc.s(cpsInit))
|
||||||
app(prc, m.initProc.s(cpsInit))
|
app(prc, m.initProc.s(cpsInit))
|
||||||
|
app(prc, m.postInitProc.s(cpsInit))
|
||||||
app(prc, genSectionEnd(cpsInit))
|
app(prc, genSectionEnd(cpsInit))
|
||||||
|
|
||||||
app(prc, genSectionStart(cpsStmts))
|
app(prc, genSectionStart(cpsStmts))
|
||||||
app(prc, m.preInitProc.s(cpsStmts))
|
app(prc, m.preInitProc.s(cpsStmts))
|
||||||
app(prc, m.initProc.s(cpsStmts))
|
app(prc, m.initProc.s(cpsStmts))
|
||||||
|
app(prc, m.postInitProc.s(cpsStmts))
|
||||||
app(prc, genSectionEnd(cpsStmts))
|
app(prc, genSectionEnd(cpsStmts))
|
||||||
if optStackTrace in m.initProc.options and not m.PreventStackTrace:
|
if optStackTrace in m.initProc.options and not m.PreventStackTrace:
|
||||||
app(prc, deinitFrame(m.initProc))
|
app(prc, deinitFrame(m.initProc))
|
||||||
|
|
@ -1094,6 +1100,11 @@ proc newPreInitProc(m: BModule): BProc =
|
||||||
# little hack so that unique temporaries are generated:
|
# little hack so that unique temporaries are generated:
|
||||||
result.labels = 100_000
|
result.labels = 100_000
|
||||||
|
|
||||||
|
proc newPostInitProc(m: BModule): BProc =
|
||||||
|
result = newProc(nil, m)
|
||||||
|
# little hack so that unique temporaries are generated:
|
||||||
|
result.labels = 200_000
|
||||||
|
|
||||||
proc rawNewModule(module: PSym, filename: string): BModule =
|
proc rawNewModule(module: PSym, filename: string): BModule =
|
||||||
new(result)
|
new(result)
|
||||||
InitLinkedList(result.headerFiles)
|
InitLinkedList(result.headerFiles)
|
||||||
|
|
@ -1108,6 +1119,7 @@ proc rawNewModule(module: PSym, filename: string): BModule =
|
||||||
result.initProc = newProc(nil, result)
|
result.initProc = newProc(nil, result)
|
||||||
result.initProc.options = gOptions
|
result.initProc.options = gOptions
|
||||||
result.preInitProc = newPreInitProc(result)
|
result.preInitProc = newPreInitProc(result)
|
||||||
|
result.postInitProc = newPostInitProc(result)
|
||||||
initNodeTable(result.dataCache)
|
initNodeTable(result.dataCache)
|
||||||
result.typeStack = @[]
|
result.typeStack = @[]
|
||||||
result.forwardedProcs = @[]
|
result.forwardedProcs = @[]
|
||||||
|
|
@ -1128,6 +1140,7 @@ proc resetModule*(m: var BModule) =
|
||||||
m.initProc = newProc(nil, m)
|
m.initProc = newProc(nil, m)
|
||||||
m.initProc.options = gOptions
|
m.initProc.options = gOptions
|
||||||
m.preInitProc = newPreInitProc(m)
|
m.preInitProc = newPreInitProc(m)
|
||||||
|
m.postInitProc = newPostInitProc(m)
|
||||||
initNodeTable(m.dataCache)
|
initNodeTable(m.dataCache)
|
||||||
m.typeStack = @[]
|
m.typeStack = @[]
|
||||||
m.forwardedProcs = @[]
|
m.forwardedProcs = @[]
|
||||||
|
|
|
||||||
|
|
@ -100,10 +100,8 @@ type
|
||||||
headerFiles*: TLinkedList # needed headers to include
|
headerFiles*: TLinkedList # needed headers to include
|
||||||
typeInfoMarker*: TIntSet # needed for generating type information
|
typeInfoMarker*: TIntSet # needed for generating type information
|
||||||
initProc*: BProc # code for init procedure
|
initProc*: BProc # code for init procedure
|
||||||
|
postInitProc*: BProc # code to be executed after the init proc
|
||||||
preInitProc*: BProc # code executed before the init proc
|
preInitProc*: BProc # code executed before the init proc
|
||||||
# used for initialization code for
|
|
||||||
# .global. variables
|
|
||||||
# (or instantiated generic variables)
|
|
||||||
typeStack*: TTypeSeq # used for type generation
|
typeStack*: TTypeSeq # used for type generation
|
||||||
dataCache*: TNodeTable
|
dataCache*: TNodeTable
|
||||||
forwardedProcs*: TSymSeq # keep forwarded procs here
|
forwardedProcs*: TSymSeq # keep forwarded procs here
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ proc getHiddenParam(routine: PSym): PSym =
|
||||||
|
|
||||||
proc isInnerProc(s, outerProc: PSym): bool {.inline.} =
|
proc isInnerProc(s, outerProc: PSym): bool {.inline.} =
|
||||||
result = s.kind in {skProc, skMethod, skConverter} and
|
result = s.kind in {skProc, skMethod, skConverter} and
|
||||||
s.owner == outerProc and not isGenericRoutine(s)
|
s.skipGenericOwner == outerProc
|
||||||
#s.typ.callConv == ccClosure
|
#s.typ.callConv == ccClosure
|
||||||
|
|
||||||
proc addClosureParam(i: PInnerContext, e: PEnv) =
|
proc addClosureParam(i: PInnerContext, e: PEnv) =
|
||||||
|
|
@ -288,6 +288,9 @@ proc interestingVar(s: PSym): bool {.inline.} =
|
||||||
proc semCaptureSym*(s, owner: PSym) =
|
proc semCaptureSym*(s, owner: PSym) =
|
||||||
if interestingVar(s) and owner.id != s.owner.id and s.kind != skResult:
|
if interestingVar(s) and owner.id != s.owner.id and s.kind != skResult:
|
||||||
if owner.typ != nil and not isGenericRoutine(owner):
|
if owner.typ != nil and not isGenericRoutine(owner):
|
||||||
|
# XXX: is this really safe?
|
||||||
|
# if we capture a var from another generic routine,
|
||||||
|
# it won't be consider captured.
|
||||||
owner.typ.callConv = ccClosure
|
owner.typ.callConv = ccClosure
|
||||||
#echo "semCaptureSym ", owner.name.s, owner.id, " ", s.name.s, s.id
|
#echo "semCaptureSym ", owner.name.s, owner.id, " ", s.name.s, s.id
|
||||||
# since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
|
# since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
|
||||||
|
|
|
||||||
|
|
@ -627,6 +627,13 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
|
||||||
getTok(p) # we must consume a token here to prevend endless loops!
|
getTok(p) # we must consume a token here to prevend endless loops!
|
||||||
result = ast.emptyNode
|
result = ast.emptyNode
|
||||||
|
|
||||||
|
proc namedParams(p: var TParser, callee: PNode,
|
||||||
|
kind: TNodeKind, endTok: TTokType): PNode =
|
||||||
|
let a = callee
|
||||||
|
result = newNodeP(kind, p)
|
||||||
|
addSon(result, a)
|
||||||
|
exprColonEqExprListAux(p, endTok, result)
|
||||||
|
|
||||||
proc primarySuffix(p: var TParser, r: PNode): PNode =
|
proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||||
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
||||||
#| | doBlocks
|
#| | doBlocks
|
||||||
|
|
@ -637,10 +644,7 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||||
while p.tok.indent < 0:
|
while p.tok.indent < 0:
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
of tkParLe:
|
of tkParLe:
|
||||||
var a = result
|
result = namedParams(p, result, nkCall, tkParRi)
|
||||||
result = newNodeP(nkCall, p)
|
|
||||||
addSon(result, a)
|
|
||||||
exprColonEqExprListAux(p, tkParRi, result)
|
|
||||||
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
|
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
|
||||||
result.kind = nkObjConstr
|
result.kind = nkObjConstr
|
||||||
else:
|
else:
|
||||||
|
|
@ -654,9 +658,9 @@ proc primarySuffix(p: var TParser, r: PNode): PNode =
|
||||||
result = dotExpr(p, result)
|
result = dotExpr(p, result)
|
||||||
result = parseGStrLit(p, result)
|
result = parseGStrLit(p, result)
|
||||||
of tkBracketLe:
|
of tkBracketLe:
|
||||||
result = indexExprList(p, result, nkBracketExpr, tkBracketRi)
|
result = namedParams(p, result, nkBracketExpr, tkBracketRi)
|
||||||
of tkCurlyLe:
|
of tkCurlyLe:
|
||||||
result = indexExprList(p, result, nkCurlyExpr, tkCurlyRi)
|
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
|
||||||
else: break
|
else: break
|
||||||
|
|
||||||
proc primary(p: var TParser, mode: TPrimaryMode): PNode
|
proc primary(p: var TParser, mode: TPrimaryMode): PNode
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,11 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType =
|
||||||
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
proc newTypeS(kind: TTypeKind, c: PContext): PType =
|
||||||
result = newType(kind, getCurrOwner())
|
result = newType(kind, getCurrOwner())
|
||||||
|
|
||||||
|
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
|
||||||
|
sons: seq[PType]): PType =
|
||||||
|
result = newType(kind, getCurrOwner())
|
||||||
|
result.sons = sons
|
||||||
|
|
||||||
proc errorType*(c: PContext): PType =
|
proc errorType*(c: PContext): PType =
|
||||||
## creates a type representing an error state
|
## creates a type representing an error state
|
||||||
result = newTypeS(tyError, c)
|
result = newTypeS(tyError, c)
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,11 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
# var len = 0 # but won't be called
|
# var len = 0 # but won't be called
|
||||||
# genericThatUsesLen(x) # marked as taking a closure?
|
# genericThatUsesLen(x) # marked as taking a closure?
|
||||||
of skGenericParam:
|
of skGenericParam:
|
||||||
if s.ast != nil: result = semExpr(c, s.ast)
|
if s.typ.kind == tyExpr:
|
||||||
|
result = newSymNode(s, n.info)
|
||||||
|
result.typ = s.typ.lastSon
|
||||||
|
elif s.ast != nil:
|
||||||
|
result = semExpr(c, s.ast)
|
||||||
else:
|
else:
|
||||||
InternalError(n.info, "no default for")
|
InternalError(n.info, "no default for")
|
||||||
result = emptyNode
|
result = emptyNode
|
||||||
|
|
@ -888,10 +892,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
let tbody = ty.sons[0]
|
let tbody = ty.sons[0]
|
||||||
for s in countup(0, tbody.len-2):
|
for s in countup(0, tbody.len-2):
|
||||||
let tParam = tbody.sons[s]
|
let tParam = tbody.sons[s]
|
||||||
assert tParam.kind == tyGenericParam
|
|
||||||
if tParam.sym.name == i:
|
if tParam.sym.name == i:
|
||||||
let foundTyp = makeTypeDesc(c, ty.sons[s + 1])
|
let rawTyp = ty.sons[s + 1]
|
||||||
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info)
|
if rawTyp.kind == tyExpr:
|
||||||
|
return rawTyp.n
|
||||||
|
else:
|
||||||
|
let foundTyp = makeTypeDesc(c, rawTyp)
|
||||||
|
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
# echo "TYPE FIELD ACCESS"
|
# echo "TYPE FIELD ACCESS"
|
||||||
|
|
@ -1820,7 +1827,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkBind:
|
of nkBind:
|
||||||
Message(n.info, warnDeprecated, "bind")
|
Message(n.info, warnDeprecated, "bind")
|
||||||
result = semExpr(c, n.sons[0], flags)
|
result = semExpr(c, n.sons[0], flags)
|
||||||
of nkTypeOfExpr:
|
of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy:
|
||||||
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
|
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
|
||||||
result = symNodeFromType(c, typ, n.info)
|
result = symNodeFromType(c, typ, n.info)
|
||||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
#t = instGenericContainer(c, a, t)
|
#t = instGenericContainer(c, a, t)
|
||||||
t = generateTypeInstance(c, pt, a, t)
|
t = generateTypeInstance(c, pt, a, t)
|
||||||
#t = ReplaceTypeVarsT(cl, t)
|
#t = ReplaceTypeVarsT(cl, t)
|
||||||
t.flags.incl tfInstantiated
|
|
||||||
s.typ = t
|
s.typ = t
|
||||||
addDecl(c, s)
|
addDecl(c, s)
|
||||||
entry.concreteTypes[i] = t
|
entry.concreteTypes[i] = t
|
||||||
|
|
@ -84,11 +83,20 @@ proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
|
||||||
else:
|
else:
|
||||||
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
|
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
|
||||||
|
|
||||||
|
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
|
||||||
|
|
||||||
proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
||||||
if n.sons[bodyPos].kind != nkEmpty:
|
if n.sons[bodyPos].kind != nkEmpty:
|
||||||
|
inc c.InGenericInst
|
||||||
# add it here, so that recursive generic procs are possible:
|
# add it here, so that recursive generic procs are possible:
|
||||||
addDecl(c, result)
|
addDecl(c, result)
|
||||||
pushProcCon(c, result)
|
pushProcCon(c, result)
|
||||||
|
# add params to scope
|
||||||
|
for i in 1 .. <result.typ.n.len:
|
||||||
|
var param = result.typ.n.sons[i].sym
|
||||||
|
param.owner = result
|
||||||
|
addParamOrResult(c, param, result.kind)
|
||||||
|
# debug result.typ.n
|
||||||
maybeAddResult(c, result, n)
|
maybeAddResult(c, result, n)
|
||||||
var b = n.sons[bodyPos]
|
var b = n.sons[bodyPos]
|
||||||
var symMap: TIdTable
|
var symMap: TIdTable
|
||||||
|
|
@ -100,6 +108,7 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
||||||
#echo "code instantiated ", result.name.s
|
#echo "code instantiated ", result.name.s
|
||||||
excl(result.flags, sfForward)
|
excl(result.flags, sfForward)
|
||||||
popProcCon(c)
|
popProcCon(c)
|
||||||
|
dec c.InGenericInst
|
||||||
|
|
||||||
proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||||
for i in countup(0, c.generics.len - 1):
|
for i in countup(0, c.generics.len - 1):
|
||||||
|
|
@ -109,8 +118,6 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||||
openScope(c)
|
openScope(c)
|
||||||
var n = oldPrc.ast
|
var n = oldPrc.ast
|
||||||
n.sons[bodyPos] = copyTree(s.getBody)
|
n.sons[bodyPos] = copyTree(s.getBody)
|
||||||
if n.sons[paramsPos].kind != nkEmpty:
|
|
||||||
addParams(c, oldPrc.typ.n, oldPrc.kind)
|
|
||||||
instantiateBody(c, n, oldPrc)
|
instantiateBody(c, n, oldPrc)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
@ -123,6 +130,97 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||||
s.ast.sons[genericParamsPos].kind == nkEmpty:
|
s.ast.sons[genericParamsPos].kind == nkEmpty:
|
||||||
c.threadEntries.add(s)
|
c.threadEntries.add(s)
|
||||||
|
|
||||||
|
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType): PType =
|
||||||
|
var cl: TReplTypeVars
|
||||||
|
InitIdTable(cl.symMap)
|
||||||
|
InitIdTable(cl.typeMap)
|
||||||
|
cl.info = info
|
||||||
|
cl.c = c
|
||||||
|
result = ReplaceTypeVarsT(cl, header)
|
||||||
|
|
||||||
|
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
||||||
|
result = instGenericContainer(c, n.info, header)
|
||||||
|
|
||||||
|
proc fixupProcType(c: PContext, genericType: PType,
|
||||||
|
inst: TInstantiation): PType =
|
||||||
|
# XXX: This is starting to look suspiciously like ReplaceTypeVarsT
|
||||||
|
# there are few apparent differences, but maybe the code could be
|
||||||
|
# moved over.
|
||||||
|
# * the code here uses the new genericSym.position property when
|
||||||
|
# doing lookups.
|
||||||
|
# * the handling of tyTypeDesc seems suspicious in ReplaceTypeVarsT
|
||||||
|
# typedesc params were previously handled in the second pass of
|
||||||
|
# semParamList
|
||||||
|
# * void (nkEmpty) params doesn't seem to be stripped in ReplaceTypeVarsT
|
||||||
|
result = genericType
|
||||||
|
if result == nil: return
|
||||||
|
|
||||||
|
case genericType.kind
|
||||||
|
of tyGenericParam, tyTypeClass:
|
||||||
|
result = inst.concreteTypes[genericType.sym.position]
|
||||||
|
of tyTypeDesc:
|
||||||
|
result = inst.concreteTypes[genericType.sym.position]
|
||||||
|
if tfUnresolved in genericType.flags:
|
||||||
|
result = result.sons[0]
|
||||||
|
of tyExpr:
|
||||||
|
result = inst.concreteTypes[genericType.sym.position]
|
||||||
|
of tyOpenArray, tyArray, tySet, tySequence, tyTuple, tyProc,
|
||||||
|
tyPtr, tyVar, tyRef, tyOrdinal, tyRange, tyVarargs:
|
||||||
|
if genericType.sons == nil: return
|
||||||
|
var head = 0
|
||||||
|
for i in 0 .. <genericType.sons.len:
|
||||||
|
let origType = genericType.sons[i]
|
||||||
|
var changed = fixupProcType(c, origType, inst)
|
||||||
|
if changed != genericType.sons[i]:
|
||||||
|
var changed = changed.skipIntLit
|
||||||
|
if result == genericType:
|
||||||
|
# the first detected change initializes the result
|
||||||
|
result = copyType(genericType, genericType.owner, false)
|
||||||
|
if genericType.n != nil:
|
||||||
|
result.n = copyTree(genericType.n)
|
||||||
|
|
||||||
|
# XXX: doh, we have to treat seq and arrays as special case
|
||||||
|
# because sometimes the `@` magic will be applied to an empty
|
||||||
|
# sequence having the type tySequence(tyEmpty)
|
||||||
|
if changed.kind == tyEmpty and
|
||||||
|
genericType.kind notin {tyArray, tySequence}:
|
||||||
|
if genericType.kind == tyProc and i == 0:
|
||||||
|
# return types of procs are overwritten with nil
|
||||||
|
changed = nil
|
||||||
|
else:
|
||||||
|
# otherwise, `empty` is just erased from the signature
|
||||||
|
result.sons[i..i] = []
|
||||||
|
if result.n != nil: result.n.sons[i..i] = []
|
||||||
|
continue
|
||||||
|
|
||||||
|
result.sons[head] = changed
|
||||||
|
|
||||||
|
if result.n != nil:
|
||||||
|
if result.n.kind == nkRecList:
|
||||||
|
for son in result.n.sons:
|
||||||
|
if son.typ == origType:
|
||||||
|
son.typ = changed
|
||||||
|
son.sym = copySym(son.sym, true)
|
||||||
|
son.sym.typ = changed
|
||||||
|
if result.n.kind == nkFormalParams:
|
||||||
|
if i != 0:
|
||||||
|
let origParam = result.n.sons[head].sym
|
||||||
|
var param = copySym(origParam)
|
||||||
|
param.typ = changed
|
||||||
|
param.ast = origParam.ast
|
||||||
|
result.n.sons[head] = newSymNode(param)
|
||||||
|
|
||||||
|
# won't be advanced on empty (void) nodes
|
||||||
|
inc head
|
||||||
|
|
||||||
|
of tyGenericInvokation:
|
||||||
|
result = newTypeWithSons(c, tyGenericInvokation, genericType.sons)
|
||||||
|
for i in 1 .. <genericType.sons.len:
|
||||||
|
result.sons[i] = fixupProcType(c, result.sons[i], inst)
|
||||||
|
result = instGenericContainer(c, getInfoContext(-1), result)
|
||||||
|
|
||||||
|
else: nil
|
||||||
|
|
||||||
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
info: TLineInfo): PSym =
|
info: TLineInfo): PSym =
|
||||||
# no need to instantiate generic templates/macros:
|
# no need to instantiate generic templates/macros:
|
||||||
|
|
@ -137,11 +235,11 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
# we set the friend module:
|
# we set the friend module:
|
||||||
var oldFriend = c.friendModule
|
var oldFriend = c.friendModule
|
||||||
c.friendModule = getModule(fn)
|
c.friendModule = getModule(fn)
|
||||||
|
#let oldScope = c.currentScope
|
||||||
|
#c.currentScope = fn.scope
|
||||||
result = copySym(fn, false)
|
result = copySym(fn, false)
|
||||||
incl(result.flags, sfFromGeneric)
|
incl(result.flags, sfFromGeneric)
|
||||||
# keep the owner if it's an inner proc (for proper closure transformations):
|
result.owner = fn
|
||||||
if fn.owner.kind == skModule:
|
|
||||||
result.owner = getCurrOwner().owner
|
|
||||||
result.ast = n
|
result.ast = n
|
||||||
pushOwner(result)
|
pushOwner(result)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
|
|
@ -152,16 +250,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
var entry = TInstantiation.new
|
var entry = TInstantiation.new
|
||||||
entry.sym = result
|
entry.sym = result
|
||||||
instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
|
instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
|
||||||
|
result.typ = fixupProcType(c, fn.typ, entry[])
|
||||||
n.sons[genericParamsPos] = ast.emptyNode
|
n.sons[genericParamsPos] = ast.emptyNode
|
||||||
# semantic checking for the parameters:
|
|
||||||
if n.sons[paramsPos].kind != nkEmpty:
|
|
||||||
removeDefaultParamValues(n.sons[ParamsPos])
|
|
||||||
semParamList(c, n.sons[ParamsPos], nil, result)
|
|
||||||
else:
|
|
||||||
result.typ = newTypeS(tyProc, c)
|
|
||||||
rawAddSon(result.typ, nil)
|
|
||||||
result.typ.callConv = fn.typ.callConv
|
|
||||||
if result.kind == skIterator: result.typ.flags.incl(tfIterator)
|
|
||||||
var oldPrc = GenericCacheGet(fn, entry[])
|
var oldPrc = GenericCacheGet(fn, entry[])
|
||||||
if oldPrc == nil:
|
if oldPrc == nil:
|
||||||
fn.procInstCache.safeAdd(entry)
|
fn.procInstCache.safeAdd(entry)
|
||||||
|
|
@ -179,15 +269,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
closeScope(c) # close scope for parameters
|
closeScope(c) # close scope for parameters
|
||||||
popOwner()
|
popOwner()
|
||||||
|
#c.currentScope = oldScope
|
||||||
c.friendModule = oldFriend
|
c.friendModule = oldFriend
|
||||||
dec(c.InstCounter)
|
dec(c.InstCounter)
|
||||||
if result.kind == skMethod: finishMethod(c, result)
|
if result.kind == skMethod: finishMethod(c, result)
|
||||||
|
|
||||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
|
||||||
var cl: TReplTypeVars
|
|
||||||
InitIdTable(cl.symMap)
|
|
||||||
InitIdTable(cl.typeMap)
|
|
||||||
cl.info = n.info
|
|
||||||
cl.c = c
|
|
||||||
result = ReplaceTypeVarsT(cl, header)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -721,7 +721,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
# TGObj[T] = object
|
# TGObj[T] = object
|
||||||
# TAlias[T] = TGObj[T]
|
# TAlias[T] = TGObj[T]
|
||||||
#
|
#
|
||||||
a.sons[1] = semGenericParamList(c, a.sons[1], s.typ)
|
s.typ.n = semGenericParamList(c, a.sons[1], s.typ)
|
||||||
|
a.sons[1] = s.typ.n
|
||||||
s.typ.size = -1 # could not be computed properly
|
s.typ.size = -1 # could not be computed properly
|
||||||
# we fill it out later. For magic generics like 'seq', it won't be filled
|
# we fill it out later. For magic generics like 'seq', it won't be filled
|
||||||
# so we use tyEmpty instead of nil to not crash for strange conversions
|
# so we use tyEmpty instead of nil to not crash for strange conversions
|
||||||
|
|
|
||||||
|
|
@ -236,16 +236,18 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
markUsed(n, result)
|
markUsed(n, result)
|
||||||
if result.kind == skParam and result.typ.kind == tyTypeDesc:
|
if result.kind == skParam and result.typ.kind == tyTypeDesc:
|
||||||
# This is a typedesc param. is it already bound?
|
# This is a typedesc param. is it already bound?
|
||||||
# it's not bound when it's also used as return type for example
|
# it's not bound when it's used multiple times in the
|
||||||
if result.typ.sonsLen > 0:
|
# proc signature for example
|
||||||
|
if c.InGenericInst > 0:
|
||||||
let bound = result.typ.sons[0].sym
|
let bound = result.typ.sons[0].sym
|
||||||
if bound != nil:
|
if bound != nil: return bound
|
||||||
return bound
|
|
||||||
return result
|
return result
|
||||||
if result.typ.sym == nil:
|
if result.typ.sym == nil:
|
||||||
LocalError(n.info, errTypeExpected)
|
LocalError(n.info, errTypeExpected)
|
||||||
return errorSym(c, n)
|
return errorSym(c, n)
|
||||||
return result.typ.sym
|
result = result.typ.sym.copySym
|
||||||
|
result.typ = copyType(result.typ, result.typ.owner, true)
|
||||||
|
result.typ.flags.incl tfUnresolved
|
||||||
if result.kind != skType:
|
if result.kind != skType:
|
||||||
# this implements the wanted ``var v: V, x: V`` feature ...
|
# this implements the wanted ``var v: V, x: V`` feature ...
|
||||||
var ov: TOverloadIter
|
var ov: TOverloadIter
|
||||||
|
|
@ -382,7 +384,7 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||||
# for ``{}`` we want to trigger the type mismatch in ``fitNode``:
|
# for ``{}`` we want to trigger the type mismatch in ``fitNode``:
|
||||||
if r.kind != nkCurly or len(r) == 0:
|
if r.kind != nkCurly or len(r) == 0:
|
||||||
checkMinSonsLen(t, 1)
|
checkMinSonsLen(t, 1)
|
||||||
branch.sons[i] = fitNode(c, t.sons[0].typ, r)
|
branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r))
|
||||||
inc(covered)
|
inc(covered)
|
||||||
else:
|
else:
|
||||||
# constant sets have special rules
|
# constant sets have special rules
|
||||||
|
|
@ -585,81 +587,95 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
|
||||||
else:
|
else:
|
||||||
if sfGenSym notin param.flags: addDecl(c, param)
|
if sfGenSym notin param.flags: addDecl(c, param)
|
||||||
|
|
||||||
proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind):
|
|
||||||
tuple[typ: PType, id: PIdent] =
|
|
||||||
# if typ is not-nil, the param should be turned into a generic param
|
|
||||||
# if id is not nil, the generic param will bind just once (see below)
|
|
||||||
case paramType.kind:
|
|
||||||
of tyExpr:
|
|
||||||
if paramType.sonsLen == 0:
|
|
||||||
# proc(a, b: expr)
|
|
||||||
# no constraints, treat like generic param
|
|
||||||
result.typ = newTypeS(tyGenericParam, c)
|
|
||||||
else:
|
|
||||||
# proc(a: expr{string}, b: expr{nkLambda})
|
|
||||||
# overload on compile time values and AST trees
|
|
||||||
result.typ = newTypeS(tyExpr, c)
|
|
||||||
result.typ.sons = paramType.sons
|
|
||||||
of tyTypeDesc:
|
|
||||||
if tfInstantiated notin paramType.flags:
|
|
||||||
result.typ = newTypeS(tyTypeDesc, c)
|
|
||||||
result.typ.sons = paramType.sons
|
|
||||||
of tyDistinct:
|
|
||||||
result = paramTypeClass(c, paramType.lastSon, procKind)
|
|
||||||
# disable the bindOnce behavior for the type class
|
|
||||||
result.id = nil
|
|
||||||
return
|
|
||||||
of tyGenericBody:
|
|
||||||
# type Foo[T] = object
|
|
||||||
# proc x(a: Foo, b: Foo)
|
|
||||||
result.typ = newTypeS(tyTypeClass, c)
|
|
||||||
result.typ.addSonSkipIntLit(paramType)
|
|
||||||
of tyTypeClass:
|
|
||||||
result.typ = copyType(paramType, getCurrOwner(), false)
|
|
||||||
else: nil
|
|
||||||
# bindOnce by default
|
|
||||||
if paramType.sym != nil: result.id = paramType.sym.name
|
|
||||||
|
|
||||||
proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
paramType: PType, paramName: string,
|
paramType: PType, paramName: string,
|
||||||
info: TLineInfo): PType =
|
info: TLineInfo, anon = false): PType =
|
||||||
result = paramType
|
|
||||||
if procKind in {skMacro, skTemplate}:
|
if procKind in {skMacro, skTemplate}:
|
||||||
# generic param types in macros and templates affect overload
|
# generic param types in macros and templates affect overload
|
||||||
# resolution, but don't work as generic params when it comes
|
# resolution, but don't work as generic params when it comes
|
||||||
# to proc instantiation. We don't need to lift such params here.
|
# to proc instantiation. We don't need to lift such params here.
|
||||||
return
|
return
|
||||||
## Params having implicit generic types or pseudo types such as 'expr'
|
|
||||||
## need to be added to the generic params lists.
|
|
||||||
## 'expr' is different from 'expr{string}' so we must first call
|
|
||||||
## paramTypeClass to get the actual type we are going to use.
|
|
||||||
var (typeClass, paramTypId) = paramTypeClass(c, paramType, procKind)
|
|
||||||
let isAnon = paramTypId == nil
|
|
||||||
if typeClass != nil:
|
|
||||||
if isAnon: paramTypId = getIdent(paramName & ":type")
|
|
||||||
if genericParams == nil:
|
|
||||||
# genericParams is nil when the proc is being instantiated
|
|
||||||
# the resolved type will be in scope then
|
|
||||||
let s = searchInScopes(c, paramTypId)
|
|
||||||
# tests/run/tinterf triggers this:
|
|
||||||
if s != nil: result = s.typ
|
|
||||||
else:
|
|
||||||
LocalError(info, errCannotInstantiateX, paramName)
|
|
||||||
result = errorType(c)
|
|
||||||
else:
|
|
||||||
block addImplicitGeneric:
|
|
||||||
# is this a bindOnce type class already present in the param list?
|
|
||||||
for i in countup(0, genericParams.len - 1):
|
|
||||||
if genericParams.sons[i].sym.name.id == paramTypId.id:
|
|
||||||
result = genericParams.sons[i].typ
|
|
||||||
break addImplicitGeneric
|
|
||||||
|
|
||||||
var s = newSym(skType, paramTypId, getCurrOwner(), info)
|
proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType =
|
||||||
if isAnon: s.flags.incl(sfAnon)
|
let finalTypId = if typId != nil: typId
|
||||||
s.linkTo(typeClass)
|
else: getIdent(paramName & ":type")
|
||||||
s.position = genericParams.len
|
# is this a bindOnce type class already present in the param list?
|
||||||
genericParams.addSon(newSymNode(s))
|
for i in countup(0, genericParams.len - 1):
|
||||||
result = typeClass
|
if genericParams.sons[i].sym.name.id == finalTypId.id:
|
||||||
|
return genericParams.sons[i].typ
|
||||||
|
|
||||||
|
var s = newSym(skType, finalTypId, getCurrOwner(), info)
|
||||||
|
if typId == nil: s.flags.incl(sfAnon)
|
||||||
|
s.linkTo(typeClass)
|
||||||
|
s.position = genericParams.len
|
||||||
|
genericParams.addSon(newSymNode(s))
|
||||||
|
result = typeClass
|
||||||
|
|
||||||
|
# XXX: There are codegen errors if this is turned into a nested proc
|
||||||
|
template liftingWalk(typ: PType, anonFlag = false): expr =
|
||||||
|
liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag)
|
||||||
|
#proc liftingWalk(paramType: PType, anon = false): PType =
|
||||||
|
|
||||||
|
var paramTypId = if not anon and paramType.sym != nil: paramType.sym.name
|
||||||
|
else: nil
|
||||||
|
|
||||||
|
template addImplicitGeneric(e: expr): expr =
|
||||||
|
addImplicitGenericImpl(e, paramTypId)
|
||||||
|
|
||||||
|
case paramType.kind:
|
||||||
|
of tyExpr:
|
||||||
|
if paramType.sonsLen == 0:
|
||||||
|
# proc(a, b: expr)
|
||||||
|
# no constraints, treat like generic param
|
||||||
|
result = addImplicitGeneric(newTypeS(tyGenericParam, c))
|
||||||
|
else:
|
||||||
|
# proc(a: expr{string}, b: expr{nkLambda})
|
||||||
|
# overload on compile time values and AST trees
|
||||||
|
result = addImplicitGeneric(c.newTypeWithSons(tyExpr, paramType.sons))
|
||||||
|
of tyTypeDesc:
|
||||||
|
if tfUnresolved notin paramType.flags:
|
||||||
|
result = addImplicitGeneric(c.newTypeWithSons(tyTypeDesc, paramType.sons))
|
||||||
|
of tyDistinct:
|
||||||
|
if paramType.sonsLen == 1:
|
||||||
|
# disable the bindOnce behavior for the type class
|
||||||
|
result = liftingWalk(paramType.sons[0], true)
|
||||||
|
of tySequence, tySet, tyArray, tyOpenArray:
|
||||||
|
# XXX: this is a bit strange, but proc(s: seq)
|
||||||
|
# produces tySequence(tyGenericParam, null).
|
||||||
|
# This also seems to be true when creating aliases
|
||||||
|
# like: type myseq = distinct seq.
|
||||||
|
# Maybe there is another better place to associate
|
||||||
|
# the seq type class with the seq identifier.
|
||||||
|
if paramType.lastSon == nil:
|
||||||
|
let typ = c.newTypeWithSons(tyTypeClass, @[newTypeS(paramType.kind, c)])
|
||||||
|
result = addImplicitGeneric(typ)
|
||||||
|
else:
|
||||||
|
for i in 0 .. <paramType.sons.len:
|
||||||
|
var lifted = liftingWalk(paramType.sons[i])
|
||||||
|
if lifted != nil:
|
||||||
|
paramType.sons[i] = lifted
|
||||||
|
result = paramType
|
||||||
|
of tyGenericBody:
|
||||||
|
# type Foo[T] = object
|
||||||
|
# proc x(a: Foo, b: Foo)
|
||||||
|
var typ = newTypeS(tyTypeClass, c)
|
||||||
|
typ.addSonSkipIntLit(paramType)
|
||||||
|
result = addImplicitGeneric(typ)
|
||||||
|
of tyGenericInst:
|
||||||
|
for i in 1 .. (paramType.sons.len - 2):
|
||||||
|
var lifted = liftingWalk(paramType.sons[i])
|
||||||
|
if lifted != nil:
|
||||||
|
paramType.sons[i] = lifted
|
||||||
|
result = paramType
|
||||||
|
|
||||||
|
if result != nil:
|
||||||
|
result.kind = tyGenericInvokation
|
||||||
|
result.sons.setLen(result.sons.len - 1)
|
||||||
|
of tyTypeClass:
|
||||||
|
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), false))
|
||||||
|
else: nil
|
||||||
|
|
||||||
|
# result = liftingWalk(paramType)
|
||||||
|
|
||||||
proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
|
proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
|
||||||
if n.kind == nkCurlyExpr:
|
if n.kind == nkCurlyExpr:
|
||||||
|
|
@ -698,7 +714,6 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
length = sonsLen(a)
|
length = sonsLen(a)
|
||||||
hasType = a.sons[length-2].kind != nkEmpty
|
hasType = a.sons[length-2].kind != nkEmpty
|
||||||
hasDefault = a.sons[length-1].kind != nkEmpty
|
hasDefault = a.sons[length-1].kind != nkEmpty
|
||||||
|
|
||||||
if hasType:
|
if hasType:
|
||||||
typ = semParamType(c, a.sons[length-2], constraint)
|
typ = semParamType(c, a.sons[length-2], constraint)
|
||||||
|
|
||||||
|
|
@ -719,8 +734,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
||||||
for j in countup(0, length-3):
|
for j in countup(0, length-3):
|
||||||
var arg = newSymG(skParam, a.sons[j], c)
|
var arg = newSymG(skParam, a.sons[j], c)
|
||||||
var finalType = liftParamType(c, kind, genericParams, typ, arg.name.s,
|
let lifted = liftParamType(c, kind, genericParams, typ,
|
||||||
a.sons[length-2].info).skipIntLit
|
arg.name.s, arg.info)
|
||||||
|
let finalType = if lifted != nil: lifted else: typ.skipIntLit
|
||||||
arg.typ = finalType
|
arg.typ = finalType
|
||||||
arg.position = counter
|
arg.position = counter
|
||||||
arg.constraint = constraint
|
arg.constraint = constraint
|
||||||
|
|
@ -738,7 +754,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
# compiler only checks for 'nil':
|
# compiler only checks for 'nil':
|
||||||
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
||||||
if r.sym == nil or sfAnon notin r.sym.flags:
|
if r.sym == nil or sfAnon notin r.sym.flags:
|
||||||
r = liftParamType(c, kind, genericParams, r, "result", n.sons[0].info)
|
let lifted = liftParamType(c, kind, genericParams, r, "result",
|
||||||
|
n.sons[0].info)
|
||||||
|
if lifted != nil: r = lifted
|
||||||
r.flags.incl tfRetType
|
r.flags.incl tfRetType
|
||||||
result.sons[0] = skipIntLit(r)
|
result.sons[0] = skipIntLit(r)
|
||||||
res.typ = result.sons[0]
|
res.typ = result.sons[0]
|
||||||
|
|
@ -788,29 +806,47 @@ proc semGenericParamInInvokation(c: PContext, n: PNode): PType =
|
||||||
|
|
||||||
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||||
result = newOrPrevType(tyGenericInvokation, prev, c)
|
result = newOrPrevType(tyGenericInvokation, prev, c)
|
||||||
var isConcrete = true
|
addSonSkipIntLit(result, s.typ)
|
||||||
|
|
||||||
|
template addToResult(typ) =
|
||||||
|
if typ.isNil:
|
||||||
|
InternalAssert false
|
||||||
|
rawAddSon(result, typ)
|
||||||
|
else: addSonSkipIntLit(result, typ)
|
||||||
|
|
||||||
if s.typ == nil:
|
if s.typ == nil:
|
||||||
LocalError(n.info, errCannotInstantiateX, s.name.s)
|
LocalError(n.info, errCannotInstantiateX, s.name.s)
|
||||||
return newOrPrevType(tyError, prev, c)
|
return newOrPrevType(tyError, prev, c)
|
||||||
elif s.typ.kind != tyGenericBody:
|
elif s.typ.kind == tyForward:
|
||||||
isConcrete = false
|
for i in countup(1, sonsLen(n)-1):
|
||||||
elif sonsLen(n) != sonsLen(s.typ):
|
var elem = semGenericParamInInvokation(c, n.sons[i])
|
||||||
LocalError(n.info, errWrongNumberOfArguments)
|
addToResult(elem)
|
||||||
return newOrPrevType(tyError, prev, c)
|
else:
|
||||||
addSonSkipIntLit(result, s.typ)
|
internalAssert s.typ.kind == tyGenericBody
|
||||||
# iterate over arguments:
|
|
||||||
for i in countup(1, sonsLen(n)-1):
|
var m = newCandidate(s, n)
|
||||||
var elem = semGenericParamInInvokation(c, n.sons[i])
|
matches(c, n, copyTree(n), m)
|
||||||
if containsGenericType(elem): isConcrete = false
|
|
||||||
#if elem.kind in {tyGenericParam, tyGenericInvokation}: isConcrete = false
|
if m.state != csMatch:
|
||||||
if elem.isNil: rawAddSon(result, elem)
|
var err = "cannot instantiate " & typeToString(s.typ) & "\n" &
|
||||||
else: addSonSkipIntLit(result, elem)
|
"got: (" & describeArgs(c, n) & ")\n" &
|
||||||
if isConcrete:
|
"but expected: (" & describeArgs(c, s.typ.n, 0) & ")"
|
||||||
if s.ast == nil:
|
LocalError(n.info, errGenerated, err)
|
||||||
LocalError(n.info, errCannotInstantiateX, s.name.s)
|
return newOrPrevType(tyError, prev, c)
|
||||||
result = newOrPrevType(tyError, prev, c)
|
|
||||||
else:
|
var isConcrete = true
|
||||||
result = instGenericContainer(c, n, result)
|
|
||||||
|
for i in 1 .. <m.call.len:
|
||||||
|
let typ = m.call[i].typ.skipTypes({tyTypeDesc})
|
||||||
|
if containsGenericType(typ): isConcrete = false
|
||||||
|
addToResult(typ)
|
||||||
|
|
||||||
|
if isConcrete:
|
||||||
|
if s.ast == nil:
|
||||||
|
LocalError(n.info, errCannotInstantiateX, s.name.s)
|
||||||
|
result = newOrPrevType(tyError, prev, c)
|
||||||
|
else:
|
||||||
|
result = instGenericContainer(c, n, result)
|
||||||
|
|
||||||
proc semTypeExpr(c: PContext, n: PNode): PType =
|
proc semTypeExpr(c: PContext, n: PNode): PType =
|
||||||
var n = semExprWithType(c, n, {efDetermineType})
|
var n = semExprWithType(c, n, {efDetermineType})
|
||||||
|
|
@ -1014,12 +1050,12 @@ proc processMagicType(c: PContext, m: PSym) =
|
||||||
of mPNimrodNode: nil
|
of mPNimrodNode: nil
|
||||||
else: LocalError(m.info, errTypeExpected)
|
else: LocalError(m.info, errTypeExpected)
|
||||||
|
|
||||||
proc semGenericConstraints(c: PContext, n: PNode, result: PType) =
|
proc semGenericConstraints(c: PContext, x: PType): PType =
|
||||||
var x = semTypeNode(c, n, nil)
|
|
||||||
if x.kind in StructuralEquivTypes and (
|
if x.kind in StructuralEquivTypes and (
|
||||||
sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}):
|
sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}):
|
||||||
x = newConstraint(c, x.kind)
|
result = newConstraint(c, x.kind)
|
||||||
result.addSonSkipIntLit(x)
|
else:
|
||||||
|
result = newTypeWithSons(c, tyGenericParam, @[x])
|
||||||
|
|
||||||
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
|
|
@ -1029,40 +1065,46 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind != nkIdentDefs: illFormedAst(n)
|
if a.kind != nkIdentDefs: illFormedAst(n)
|
||||||
var L = sonsLen(a)
|
let L = a.len
|
||||||
var def = a.sons[L-1]
|
var def = a{-1}
|
||||||
|
let constraint = a{-2}
|
||||||
var typ: PType
|
var typ: PType
|
||||||
if a.sons[L-2].kind != nkEmpty:
|
|
||||||
typ = newTypeS(tyGenericParam, c)
|
if constraint.kind != nkEmpty:
|
||||||
semGenericConstraints(c, a.sons[L-2], typ)
|
typ = semTypeNode(c, constraint, nil)
|
||||||
if sonsLen(typ) == 1 and typ.sons[0].kind == tyTypeDesc:
|
if typ.kind != tyExpr or typ.len == 0:
|
||||||
typ = typ.sons[0]
|
if typ.len == 0 and typ.kind == tyTypeDesc:
|
||||||
elif def.kind != nkEmpty: typ = newTypeS(tyExpr, c)
|
typ = newTypeS(tyGenericParam, c)
|
||||||
else: typ = nil
|
|
||||||
for j in countup(0, L-3):
|
|
||||||
var s: PSym
|
|
||||||
if typ == nil:
|
|
||||||
s = newSymG(skType, a.sons[j], c)
|
|
||||||
s.typ = newTypeS(tyGenericParam, c)
|
|
||||||
else:
|
|
||||||
case typ.kind
|
|
||||||
of tyTypeDesc:
|
|
||||||
s = newSymG(skType, a.sons[j], c)
|
|
||||||
s.typ = newTypeS(tyGenericParam, c)
|
|
||||||
of tyExpr:
|
|
||||||
#echo "GENERIC EXPR ", a.info.toFileLineCol
|
|
||||||
# not a type param, but an expression
|
|
||||||
# proc foo[x: expr](bar: int) what is this?
|
|
||||||
s = newSymG(skGenericParam, a.sons[j], c)
|
|
||||||
s.typ = typ
|
|
||||||
else:
|
else:
|
||||||
# This handles cases like proc foo[t: tuple]
|
typ = semGenericConstraints(c, typ)
|
||||||
# XXX: we want to turn that into a type class
|
|
||||||
s = newSymG(skType, a.sons[j], c)
|
if def.kind != nkEmpty:
|
||||||
s.typ = typ
|
def = semConstExpr(c, def)
|
||||||
|
if typ == nil:
|
||||||
|
if def.typ.kind != tyTypeDesc:
|
||||||
|
typ = newTypeWithSons(c, tyExpr, @[def.typ])
|
||||||
|
else:
|
||||||
|
if not containsGenericType(def.typ):
|
||||||
|
def = fitNode(c, typ, def)
|
||||||
|
|
||||||
|
if typ == nil:
|
||||||
|
typ = newTypeS(tyGenericParam, c)
|
||||||
|
|
||||||
|
for j in countup(0, L-3):
|
||||||
|
let finalType = if j == 0: typ
|
||||||
|
else: copyType(typ, typ.owner, false)
|
||||||
|
# it's important the we create an unique
|
||||||
|
# type for each generic param. the index
|
||||||
|
# of the parameter will be stored in the
|
||||||
|
# attached symbol.
|
||||||
|
var s = case finalType.kind
|
||||||
|
of tyExpr:
|
||||||
|
newSymG(skGenericParam, a.sons[j], c).linkTo(finalType)
|
||||||
|
else:
|
||||||
|
newSymG(skType, a.sons[j], c).linkTo(finalType)
|
||||||
if def.kind != nkEmpty: s.ast = def
|
if def.kind != nkEmpty: s.ast = def
|
||||||
s.typ.sym = s
|
|
||||||
if father != nil: addSonSkipIntLit(father, s.typ)
|
if father != nil: addSonSkipIntLit(father, s.typ)
|
||||||
s.position = i
|
s.position = result.len
|
||||||
addSon(result, newSymNode(s))
|
addSon(result, newSymNode(s))
|
||||||
if sfGenSym notin s.flags: addDecl(c, s)
|
if sfGenSym notin s.flags: addDecl(c, s)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ type
|
||||||
proxyMatch*: bool # to prevent instantiations
|
proxyMatch*: bool # to prevent instantiations
|
||||||
genericConverter*: bool # true if a generic converter needs to
|
genericConverter*: bool # true if a generic converter needs to
|
||||||
# be instantiated
|
# be instantiated
|
||||||
|
typedescMatched: bool
|
||||||
inheritancePenalty: int # to prefer closest father object type
|
inheritancePenalty: int # to prefer closest father object type
|
||||||
|
|
||||||
TTypeRelation* = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
|
|
@ -89,6 +90,9 @@ proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode,
|
||||||
#debug(formalTypeParam)
|
#debug(formalTypeParam)
|
||||||
put(c.bindings, formalTypeParam, binding[i].typ)
|
put(c.bindings, formalTypeParam, binding[i].typ)
|
||||||
|
|
||||||
|
proc newCandidate*(callee: PSym, binding: PNode, calleeScope = -1): TCandidate =
|
||||||
|
initCandidate(result, callee, binding, calleeScope)
|
||||||
|
|
||||||
proc copyCandidate(a: var TCandidate, b: TCandidate) =
|
proc copyCandidate(a: var TCandidate, b: TCandidate) =
|
||||||
a.exactMatches = b.exactMatches
|
a.exactMatches = b.exactMatches
|
||||||
a.subtypeMatches = b.subtypeMatches
|
a.subtypeMatches = b.subtypeMatches
|
||||||
|
|
@ -177,15 +181,9 @@ proc argTypeToString(arg: PNode): string =
|
||||||
else:
|
else:
|
||||||
result = arg.typ.typeToString
|
result = arg.typ.typeToString
|
||||||
|
|
||||||
proc NotFoundError*(c: PContext, n: PNode) =
|
proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
|
||||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
result = ""
|
||||||
# as semOverlodedCall is already pretty slow (and we need this information
|
for i in countup(startIdx, n.len - 1):
|
||||||
# only in case of an error).
|
|
||||||
if c.InCompilesContext > 0:
|
|
||||||
# fail fast:
|
|
||||||
GlobalError(n.info, errTypeMismatch, "")
|
|
||||||
var result = msgKindToString(errTypeMismatch)
|
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
|
||||||
var arg = n.sons[i]
|
var arg = n.sons[i]
|
||||||
if n.sons[i].kind == nkExprEqExpr:
|
if n.sons[i].kind == nkExprEqExpr:
|
||||||
add(result, renderTree(n.sons[i].sons[0]))
|
add(result, renderTree(n.sons[i].sons[0]))
|
||||||
|
|
@ -201,6 +199,16 @@ proc NotFoundError*(c: PContext, n: PNode) =
|
||||||
if arg.typ.kind == tyError: return
|
if arg.typ.kind == tyError: return
|
||||||
add(result, argTypeToString(arg))
|
add(result, argTypeToString(arg))
|
||||||
if i != sonsLen(n) - 1: add(result, ", ")
|
if i != sonsLen(n) - 1: add(result, ", ")
|
||||||
|
|
||||||
|
proc NotFoundError*(c: PContext, n: PNode) =
|
||||||
|
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||||
|
# as semOverlodedCall is already pretty slow (and we need this information
|
||||||
|
# only in case of an error).
|
||||||
|
if c.InCompilesContext > 0:
|
||||||
|
# fail fast:
|
||||||
|
GlobalError(n.info, errTypeMismatch, "")
|
||||||
|
var result = msgKindToString(errTypeMismatch)
|
||||||
|
add(result, describeArgs(c, n))
|
||||||
add(result, ')')
|
add(result, ')')
|
||||||
var candidates = ""
|
var candidates = ""
|
||||||
var o: TOverloadIter
|
var o: TOverloadIter
|
||||||
|
|
@ -492,8 +500,11 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
if isOrdinalType(a):
|
if isOrdinalType(a):
|
||||||
var x = if a.kind == tyOrdinal: a.sons[0] else: a
|
var x = if a.kind == tyOrdinal: a.sons[0] else: a
|
||||||
|
|
||||||
result = typeRel(c, f.sons[0], x)
|
result = typeRel(c, f.sons[0], x)
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
|
elif a.kind == tyGenericParam:
|
||||||
|
result = isGeneric
|
||||||
of tyForward: InternalError("forward type in typeRel()")
|
of tyForward: InternalError("forward type in typeRel()")
|
||||||
of tyNil:
|
of tyNil:
|
||||||
if a.kind == f.kind: result = isEqual
|
if a.kind == f.kind: result = isEqual
|
||||||
|
|
@ -611,7 +622,24 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
of tyGenericParam, tyTypeClass:
|
of tyGenericParam, tyTypeClass:
|
||||||
var x = PType(idTableGet(c.bindings, f))
|
var x = PType(idTableGet(c.bindings, f))
|
||||||
if x == nil:
|
if x == nil:
|
||||||
result = matchTypeClass(c, f, a)
|
if c.calleeSym.kind == skType and f.kind == tyGenericParam and not c.typedescMatched:
|
||||||
|
# XXX: The fact that generic types currently use tyGenericParam for
|
||||||
|
# their parameters is really a misnomer. tyGenericParam means "match
|
||||||
|
# any value" and what we need is "match any type", which can be encoded
|
||||||
|
# by a tyTypeDesc params. Unfortunately, this requires more substantial
|
||||||
|
# changes in semtypinst and elsewhere.
|
||||||
|
if a.kind == tyTypeDesc:
|
||||||
|
if f.sons == nil or f.sons.len == 0:
|
||||||
|
result = isGeneric
|
||||||
|
else:
|
||||||
|
InternalAssert a.sons != nil and a.sons.len > 0
|
||||||
|
c.typedescMatched = true
|
||||||
|
result = typeRel(c, f.sons[0], a.sons[0])
|
||||||
|
else:
|
||||||
|
result = isNone
|
||||||
|
else:
|
||||||
|
result = matchTypeClass(c, f, a)
|
||||||
|
|
||||||
if result == isGeneric:
|
if result == isGeneric:
|
||||||
var concrete = concreteType(c, a)
|
var concrete = concreteType(c, a)
|
||||||
if concrete == nil:
|
if concrete == nil:
|
||||||
|
|
@ -910,15 +938,21 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
return
|
return
|
||||||
|
|
||||||
var f = 1 # iterates over formal parameters
|
var
|
||||||
var a = 1 # iterates over the actual given arguments
|
# iterates over formal parameters
|
||||||
m.state = csMatch # until proven otherwise
|
f = if m.callee.kind != tyGenericBody: 1
|
||||||
|
else: 0
|
||||||
|
# iterates over the actual given arguments
|
||||||
|
a = 1
|
||||||
|
|
||||||
|
m.state = csMatch # until proven otherwise
|
||||||
m.call = newNodeI(n.kind, n.info)
|
m.call = newNodeI(n.kind, n.info)
|
||||||
m.call.typ = base(m.callee) # may be nil
|
m.call.typ = base(m.callee) # may be nil
|
||||||
var formalLen = sonsLen(m.callee.n)
|
var formalLen = m.callee.n.len
|
||||||
addSon(m.call, copyTree(n.sons[0]))
|
addSon(m.call, copyTree(n.sons[0]))
|
||||||
var container: PNode = nil # constructed container
|
var container: PNode = nil # constructed container
|
||||||
var formal: PSym = nil
|
var formal: PSym = nil
|
||||||
|
|
||||||
while a < n.len:
|
while a < n.len:
|
||||||
if n.sons[a].kind == nkExprEqExpr:
|
if n.sons[a].kind == nkExprEqExpr:
|
||||||
# named param
|
# named param
|
||||||
|
|
|
||||||
|
|
@ -926,11 +926,21 @@ proc commonSuperclass*(a, b: PType): PType =
|
||||||
if ancestors.contains(y.id): return y
|
if ancestors.contains(y.id): return y
|
||||||
y = y.sons[0]
|
y = y.sons[0]
|
||||||
|
|
||||||
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool
|
type
|
||||||
proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
|
TTypeAllowedFlag = enum
|
||||||
|
taField,
|
||||||
|
taHeap
|
||||||
|
|
||||||
|
TTypeAllowedFlags = set[TTypeAllowedFlag]
|
||||||
|
|
||||||
|
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind,
|
||||||
|
flags: TTypeAllowedFlags = {}): bool
|
||||||
|
|
||||||
|
proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind,
|
||||||
|
flags: TTypeAllowedFlags = {}): bool =
|
||||||
result = true
|
result = true
|
||||||
if n != nil:
|
if n != nil:
|
||||||
result = typeAllowedAux(marker, n.typ, kind)
|
result = typeAllowedAux(marker, n.typ, kind, flags)
|
||||||
#if not result: debug(n.typ)
|
#if not result: debug(n.typ)
|
||||||
if result:
|
if result:
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -938,7 +948,7 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
|
||||||
nil
|
nil
|
||||||
else:
|
else:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
result = typeAllowedNode(marker, n.sons[i], kind)
|
result = typeAllowedNode(marker, n.sons[i], kind, flags)
|
||||||
if not result: break
|
if not result: break
|
||||||
|
|
||||||
proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
|
proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
|
||||||
|
|
@ -959,8 +969,8 @@ proc skipGenericAlias*(t: PType): PType =
|
||||||
proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
|
proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
|
||||||
for i in countup(0, typeClass.sonsLen - 1):
|
for i in countup(0, typeClass.sonsLen - 1):
|
||||||
let req = typeClass.sons[i]
|
let req = typeClass.sons[i]
|
||||||
var match = req.kind == skipTypes(t, {tyGenericInst, tyRange}).kind or
|
var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
|
||||||
req.kind == skipTypes(t, {tyGenericInst}).kind
|
|
||||||
if not match:
|
if not match:
|
||||||
case req.kind
|
case req.kind
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
|
|
@ -969,7 +979,9 @@ proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
|
||||||
IdTablePut(bindings, typeClass, t)
|
IdTablePut(bindings, typeClass, t)
|
||||||
of tyTypeClass:
|
of tyTypeClass:
|
||||||
match = matchTypeClass(bindings, req, t)
|
match = matchTypeClass(bindings, req, t)
|
||||||
else: nil
|
elif t.kind == tyTypeClass:
|
||||||
|
match = matchTypeClass(bindings, t, req)
|
||||||
|
|
||||||
elif t.kind in {tyObject} and req.len != 0:
|
elif t.kind in {tyObject} and req.len != 0:
|
||||||
# empty 'object' is fine as constraint in a type class
|
# empty 'object' is fine as constraint in a type class
|
||||||
match = sameType(t, req)
|
match = sameType(t, req)
|
||||||
|
|
@ -982,13 +994,16 @@ proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
|
||||||
# if the loop finished without returning, either all constraints matched
|
# if the loop finished without returning, either all constraints matched
|
||||||
# or none of them matched.
|
# or none of them matched.
|
||||||
result = if tfAny in typeClass.flags: false else: true
|
result = if tfAny in typeClass.flags: false else: true
|
||||||
|
if result == true:
|
||||||
|
IdTablePut(bindings, typeClass, t)
|
||||||
|
|
||||||
proc matchTypeClass*(typeClass, typ: PType): bool =
|
proc matchTypeClass*(typeClass, typ: PType): bool =
|
||||||
var bindings: TIdTable
|
var bindings: TIdTable
|
||||||
initIdTable(bindings)
|
initIdTable(bindings)
|
||||||
result = matchTypeClass(bindings, typeClass, typ)
|
result = matchTypeClass(bindings, typeClass, typ)
|
||||||
|
|
||||||
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind,
|
||||||
|
flags: TTypeAllowedFlags = {}): bool =
|
||||||
assert(kind in {skVar, skLet, skConst, skParam, skResult})
|
assert(kind in {skVar, skLet, skConst, skParam, skResult})
|
||||||
# if we have already checked the type, return true, because we stop the
|
# if we have already checked the type, return true, because we stop the
|
||||||
# evaluation if something is wrong:
|
# evaluation if something is wrong:
|
||||||
|
|
@ -1002,58 +1017,62 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
||||||
var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
|
var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
|
||||||
case t2.kind
|
case t2.kind
|
||||||
of tyVar:
|
of tyVar:
|
||||||
result = false # ``var var`` is always an invalid type:
|
result = taHeap in flags # ``var var`` is illegal on the heap:
|
||||||
of tyOpenArray:
|
of tyOpenArray:
|
||||||
result = kind == skParam and typeAllowedAux(marker, t2, kind)
|
result = kind == skParam and typeAllowedAux(marker, t2, kind, flags)
|
||||||
else:
|
else:
|
||||||
result = kind in {skParam, skResult} and typeAllowedAux(marker, t2, kind)
|
result = kind in {skParam, skResult} and
|
||||||
|
typeAllowedAux(marker, t2, kind, flags)
|
||||||
of tyProc:
|
of tyProc:
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
result = typeAllowedAux(marker, t.sons[i], skParam)
|
result = typeAllowedAux(marker, t.sons[i], skParam, flags)
|
||||||
if not result: break
|
if not result: break
|
||||||
if result and t.sons[0] != nil:
|
if result and t.sons[0] != nil:
|
||||||
result = typeAllowedAux(marker, t.sons[0], skResult)
|
result = typeAllowedAux(marker, t.sons[0], skResult, flags)
|
||||||
of tyExpr, tyStmt, tyTypeDesc:
|
of tyExpr, tyStmt, tyTypeDesc:
|
||||||
result = true
|
result = true
|
||||||
# XXX er ... no? these should not be allowed!
|
# XXX er ... no? these should not be allowed!
|
||||||
|
of tyEmpty:
|
||||||
|
result = taField in flags
|
||||||
of tyTypeClass:
|
of tyTypeClass:
|
||||||
result = true
|
result = true
|
||||||
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation:
|
of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation:
|
||||||
result = false
|
result = false
|
||||||
of tyEmpty, tyNil:
|
of tyNil:
|
||||||
result = kind == skConst
|
result = kind == skConst
|
||||||
of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer:
|
of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer:
|
||||||
result = true
|
result = true
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
result = kind == skParam
|
result = kind == skParam
|
||||||
of tyGenericInst, tyDistinct:
|
of tyGenericInst, tyDistinct:
|
||||||
result = typeAllowedAux(marker, lastSon(t), kind)
|
result = typeAllowedAux(marker, lastSon(t), kind, flags)
|
||||||
of tyRange:
|
of tyRange:
|
||||||
result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in
|
result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in
|
||||||
{tyChar, tyEnum, tyInt..tyUInt64}
|
{tyChar, tyEnum, tyInt..tyFloat128}
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar)
|
result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar, flags)
|
||||||
of tySequence:
|
of tySequence:
|
||||||
result = t.sons[0].kind == tyEmpty or
|
result = t.sons[0].kind == tyEmpty or
|
||||||
typeAllowedAux(marker, t.sons[0], skVar)
|
typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
|
||||||
of tyArray:
|
of tyArray:
|
||||||
result = t.sons[1].kind == tyEmpty or
|
result = t.sons[1].kind == tyEmpty or
|
||||||
typeAllowedAux(marker, t.sons[1], skVar)
|
typeAllowedAux(marker, t.sons[1], skVar, flags)
|
||||||
of tyRef:
|
of tyRef:
|
||||||
if kind == skConst: return false
|
if kind == skConst: return false
|
||||||
result = typeAllowedAux(marker, t.sons[0], skVar)
|
result = typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
|
||||||
of tyPtr:
|
of tyPtr:
|
||||||
result = typeAllowedAux(marker, t.sons[0], skVar)
|
result = typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
|
||||||
of tyArrayConstr, tyTuple, tySet, tyConst, tyMutable, tyIter:
|
of tyArrayConstr, tySet, tyConst, tyMutable, tyIter:
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
for i in countup(0, sonsLen(t) - 1):
|
||||||
result = typeAllowedAux(marker, t.sons[i], kind)
|
result = typeAllowedAux(marker, t.sons[i], kind, flags)
|
||||||
if not result: break
|
if not result: break
|
||||||
of tyObject:
|
of tyObject, tyTuple:
|
||||||
if kind == skConst: return false
|
if kind == skConst and t.kind == tyObject: return false
|
||||||
|
let flags = flags+{taField}
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
for i in countup(0, sonsLen(t) - 1):
|
||||||
result = typeAllowedAux(marker, t.sons[i], kind)
|
result = typeAllowedAux(marker, t.sons[i], kind, flags)
|
||||||
if not result: break
|
if not result: break
|
||||||
if result and t.n != nil: result = typeAllowedNode(marker, t.n, kind)
|
if result and t.n != nil: result = typeAllowedNode(marker, t.n, kind, flags)
|
||||||
of tyProxy:
|
of tyProxy:
|
||||||
# for now same as error node; we say it's a valid type as it should
|
# for now same as error node; we say it's a valid type as it should
|
||||||
# prevent cascading errors:
|
# prevent cascading errors:
|
||||||
|
|
@ -1061,7 +1080,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
||||||
|
|
||||||
proc typeAllowed(t: PType, kind: TSymKind): bool =
|
proc typeAllowed(t: PType, kind: TSymKind): bool =
|
||||||
var marker = InitIntSet()
|
var marker = InitIntSet()
|
||||||
result = typeAllowedAux(marker, t, kind)
|
result = typeAllowedAux(marker, t, kind, {})
|
||||||
|
|
||||||
proc align(address, alignment: biggestInt): biggestInt =
|
proc align(address, alignment: biggestInt): biggestInt =
|
||||||
result = (address + (alignment - 1)) and not (alignment - 1)
|
result = (address + (alignment - 1)) and not (alignment - 1)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
output: "1.0000000000000000e+00 10"
|
output: "1.1000000000000001e+00 11"
|
||||||
ccodecheck: "!@'ClEnv'"
|
ccodecheck: "!@'ClEnv'"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -8,5 +8,6 @@ proc p[T](a, b: T): T
|
||||||
echo p(0.9, 0.1), " ", p(9, 1)
|
echo p(0.9, 0.1), " ", p(9, 1)
|
||||||
|
|
||||||
proc p[T](a, b: T): T =
|
proc p[T](a, b: T): T =
|
||||||
result = a + b
|
let c = b
|
||||||
|
result = a + b + c
|
||||||
|
|
||||||
|
|
|
||||||
10
tests/compile/tgeneric4.nim
Normal file
10
tests/compile/tgeneric4.nim
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
type
|
||||||
|
TIDGen*[A: Ordinal] = object
|
||||||
|
next: A
|
||||||
|
free: seq[A]
|
||||||
|
|
||||||
|
proc newIDGen*[A]: TIDGen[A] =
|
||||||
|
newSeq result.free, 0
|
||||||
|
|
||||||
|
var x = newIDGen[int]()
|
||||||
|
|
||||||
29
tests/compile/tgenericdefaults.nim
Normal file
29
tests/compile/tgenericdefaults.nim
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
type
|
||||||
|
TFoo[T, U, R = int] = object
|
||||||
|
x: T
|
||||||
|
y: U
|
||||||
|
z: R
|
||||||
|
|
||||||
|
TBar[T] = TFoo[T, array[4, T], T]
|
||||||
|
|
||||||
|
var x1: TFoo[int, float]
|
||||||
|
|
||||||
|
static:
|
||||||
|
assert type(x1.x) is int
|
||||||
|
assert type(x1.y) is float
|
||||||
|
assert type(x1.z) is int
|
||||||
|
|
||||||
|
var x2: TFoo[string, R = float, U = seq[int]]
|
||||||
|
|
||||||
|
static:
|
||||||
|
assert type(x2.x) is string
|
||||||
|
assert type(x2.y) is seq[int]
|
||||||
|
assert type(x2.z) is float
|
||||||
|
|
||||||
|
var x3: TBar[float]
|
||||||
|
|
||||||
|
static:
|
||||||
|
assert type(x3.x) is float
|
||||||
|
assert type(x3.y) is array[4, float]
|
||||||
|
assert type(x3.z) is float
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ type
|
||||||
|
|
||||||
type
|
type
|
||||||
TMyObject = object of TObject
|
TMyObject = object of TObject
|
||||||
case disp: range[0..4]:
|
case disp: range[0..4]
|
||||||
of 0: arg: char
|
of 0: arg: char
|
||||||
of 1: s: string
|
of 1: s: string
|
||||||
else: wtf: bool
|
else: wtf: bool
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ type
|
||||||
T1 = expr
|
T1 = expr
|
||||||
T2 = expr
|
T2 = expr
|
||||||
|
|
||||||
|
Numeric = int|float
|
||||||
|
|
||||||
proc takesExpr(x, y) =
|
proc takesExpr(x, y) =
|
||||||
echo x, y
|
echo x, y
|
||||||
|
|
||||||
|
|
@ -32,3 +34,22 @@ takesFoo(f, f)
|
||||||
takes2Types(1, 1, "string")
|
takes2Types(1, 1, "string")
|
||||||
takes2Types[string, int]("test", "test", 1)
|
takes2Types[string, int]("test", "test", 1)
|
||||||
|
|
||||||
|
proc takesSeq(x: seq) =
|
||||||
|
echo "seq"
|
||||||
|
|
||||||
|
takesSeq(@[1, 2, 3])
|
||||||
|
takesSeq(@["x", "y", "z"])
|
||||||
|
|
||||||
|
proc takesSeqOfFoos(x: seq[TFoo]) =
|
||||||
|
echo "foo seq"
|
||||||
|
|
||||||
|
var sf = newSeq[TFoo[int]](3)
|
||||||
|
|
||||||
|
takesSeq(sf)
|
||||||
|
takesSeqOfFoos(sf)
|
||||||
|
|
||||||
|
proc takesFooOfNumeric(x: TFoo[Numeric]) =
|
||||||
|
echo "foo of numeric"
|
||||||
|
|
||||||
|
takesFooOfNumeric(sf[0])
|
||||||
|
|
||||||
|
|
|
||||||
30
tests/reject/tgenconstraints.nim
Normal file
30
tests/reject/tgenconstraints.nim
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
discard """
|
||||||
|
file: "tgenconstraints.nim"
|
||||||
|
line: 25
|
||||||
|
errormsg: "cannot instantiate T2"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
T1[T: int|string] = object
|
||||||
|
x: T
|
||||||
|
|
||||||
|
T2[T: Ordinal] = object
|
||||||
|
x: T
|
||||||
|
|
||||||
|
var x1: T1[int]
|
||||||
|
var x2: T1[string]
|
||||||
|
var x3: T2[int]
|
||||||
|
|
||||||
|
proc foo[T](x: T): T2[T] {.discardable.} =
|
||||||
|
var o: T1[T]
|
||||||
|
|
||||||
|
foo(10)
|
||||||
|
|
||||||
|
proc bar(x: string|TNumber): T1[type(x)] {.discardable.} =
|
||||||
|
when type(x) is TNumber:
|
||||||
|
var o: T2[type(x)]
|
||||||
|
|
||||||
|
bar "test"
|
||||||
|
bar 100
|
||||||
|
bar 1.1
|
||||||
|
|
||||||
|
|
@ -5,7 +5,7 @@ discard """
|
||||||
type
|
type
|
||||||
TMyTuple = tuple[a, b: int]
|
TMyTuple = tuple[a, b: int]
|
||||||
|
|
||||||
proc indexOf*(t: typedesc, name: string): int {.compiletime.} =
|
proc indexOf*(t: typedesc, name: string): int =
|
||||||
## takes a tuple and looks for the field by name.
|
## takes a tuple and looks for the field by name.
|
||||||
## returs index of that field.
|
## returs index of that field.
|
||||||
var
|
var
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
file: "tfinally.nim"
|
file: "tfinally.nim"
|
||||||
output: '''came
|
output: "came\nhere\n3"
|
||||||
here
|
|
||||||
3'''
|
|
||||||
"""
|
"""
|
||||||
# Test return in try statement:
|
# Test return in try statement:
|
||||||
|
|
||||||
|
|
@ -14,10 +12,8 @@ proc main: int =
|
||||||
echo("came")
|
echo("came")
|
||||||
return 2
|
return 2
|
||||||
finally:
|
finally:
|
||||||
echo("here ")
|
echo("here")
|
||||||
return 3
|
return 3
|
||||||
|
|
||||||
echo main() #OUT came here 3
|
echo main() #OUT came here 3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
17
tests/run/tstaticparams.nim
Normal file
17
tests/run/tstaticparams.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
discard """
|
||||||
|
file: "tstaticparams.nim"
|
||||||
|
output: "abracadabra\ntest"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
TFoo[T; Val: expr[string]] = object
|
||||||
|
data: array[4, T]
|
||||||
|
|
||||||
|
proc takeFoo(x: TFoo) =
|
||||||
|
echo "abracadabra"
|
||||||
|
echo TFoo.Val
|
||||||
|
|
||||||
|
var x: TFoo[int, "test"]
|
||||||
|
|
||||||
|
takeFoo(x)
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue