Merge branch 'araq2' into devel
This commit is contained in:
commit
8f67b90997
54 changed files with 2479 additions and 340 deletions
|
|
@ -224,7 +224,7 @@ type
|
||||||
TNodeKinds* = set[TNodeKind]
|
TNodeKinds* = set[TNodeKind]
|
||||||
|
|
||||||
type
|
type
|
||||||
TSymFlag* = enum # already 32 flags!
|
TSymFlag* = enum # already 33 flags!
|
||||||
sfUsed, # read access of sym (for warnings) or simply used
|
sfUsed, # read access of sym (for warnings) or simply used
|
||||||
sfExported, # symbol is exported from module
|
sfExported, # symbol is exported from module
|
||||||
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
||||||
|
|
@ -452,10 +452,12 @@ type
|
||||||
nfExprCall # this is an attempt to call a regular expression
|
nfExprCall # this is an attempt to call a regular expression
|
||||||
nfIsRef # this node is a 'ref' node; used for the VM
|
nfIsRef # this node is a 'ref' node; used for the VM
|
||||||
nfPreventCg # this node should be ignored by the codegen
|
nfPreventCg # this node should be ignored by the codegen
|
||||||
|
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
|
||||||
|
|
||||||
TNodeFlags* = set[TNodeFlag]
|
TNodeFlags* = set[TNodeFlag]
|
||||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 30)
|
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: beyond that)
|
||||||
tfVarargs, # procedure has C styled varargs
|
tfVarargs, # procedure has C styled varargs
|
||||||
|
# tyArray type represeting a varargs list
|
||||||
tfNoSideEffect, # procedure type does not allow side effects
|
tfNoSideEffect, # procedure type does not allow side effects
|
||||||
tfFinal, # is the object final?
|
tfFinal, # is the object final?
|
||||||
tfInheritable, # is the object inheritable?
|
tfInheritable, # is the object inheritable?
|
||||||
|
|
@ -506,6 +508,9 @@ type
|
||||||
tfTriggersCompileTime # uses the NimNode type which make the proc
|
tfTriggersCompileTime # uses the NimNode type which make the proc
|
||||||
# implicitly '.compiletime'
|
# implicitly '.compiletime'
|
||||||
tfRefsAnonObj # used for 'ref object' and 'ptr object'
|
tfRefsAnonObj # used for 'ref object' and 'ptr object'
|
||||||
|
tfCovariant # covariant generic param mimicing a ptr type
|
||||||
|
tfWeakCovariant # covariant generic param mimicing a seq/array type
|
||||||
|
tfContravariant # contravariant generic param
|
||||||
|
|
||||||
TTypeFlags* = set[TTypeFlag]
|
TTypeFlags* = set[TTypeFlag]
|
||||||
|
|
||||||
|
|
@ -1002,15 +1007,17 @@ proc add*(father, son: PNode) =
|
||||||
if isNil(father.sons): father.sons = @[]
|
if isNil(father.sons): father.sons = @[]
|
||||||
add(father.sons, son)
|
add(father.sons, son)
|
||||||
|
|
||||||
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
type Indexable = PNode | PType
|
||||||
result = n.sons[i]
|
|
||||||
|
template `[]`*(n: Indexable, i: int): Indexable =
|
||||||
|
n.sons[i]
|
||||||
|
|
||||||
template `-|`*(b, s: untyped): untyped =
|
template `-|`*(b, s: untyped): untyped =
|
||||||
(if b >= 0: b else: s.len + b)
|
(if b >= 0: b else: s.len + b)
|
||||||
|
|
||||||
# son access operators with support for negative indices
|
# son access operators with support for negative indices
|
||||||
template `{}`*(n: PNode, i: int): untyped = n[i -| n]
|
template `{}`*(n: Indexable, i: int): untyped = n[i -| n]
|
||||||
template `{}=`*(n: PNode, i: int, s: PNode) =
|
template `{}=`*(n: Indexable, i: int, s: Indexable) =
|
||||||
n.sons[i -| n] = s
|
n.sons[i -| n] = s
|
||||||
|
|
||||||
when defined(useNodeIds):
|
when defined(useNodeIds):
|
||||||
|
|
@ -1346,6 +1353,9 @@ proc initIdTable*(x: var TIdTable) =
|
||||||
x.counter = 0
|
x.counter = 0
|
||||||
newSeq(x.data, StartSize)
|
newSeq(x.data, StartSize)
|
||||||
|
|
||||||
|
proc newIdTable*: TIdTable =
|
||||||
|
initIdTable(result)
|
||||||
|
|
||||||
proc resetIdTable*(x: var TIdTable) =
|
proc resetIdTable*(x: var TIdTable) =
|
||||||
x.counter = 0
|
x.counter = 0
|
||||||
# clear and set to old initial size:
|
# clear and set to old initial size:
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,8 @@ proc debug*(n: PNode) {.deprecated.}
|
||||||
template mdbg*: bool {.dirty.} =
|
template mdbg*: bool {.dirty.} =
|
||||||
when compiles(c.module):
|
when compiles(c.module):
|
||||||
c.module.fileIdx == gProjectMainIdx
|
c.module.fileIdx == gProjectMainIdx
|
||||||
|
elif compiles(c.c.module):
|
||||||
|
c.c.module.fileIdx == gProjectMainIdx
|
||||||
elif compiles(m.c.module):
|
elif compiles(m.c.module):
|
||||||
m.c.module.fileIdx == gProjectMainIdx
|
m.c.module.fileIdx == gProjectMainIdx
|
||||||
elif compiles(cl.c.module):
|
elif compiles(cl.c.module):
|
||||||
|
|
@ -79,6 +81,8 @@ template mdbg*: bool {.dirty.} =
|
||||||
p.lex.fileIdx == gProjectMainIdx
|
p.lex.fileIdx == gProjectMainIdx
|
||||||
else:
|
else:
|
||||||
p.module.module.fileIdx == gProjectMainIdx
|
p.module.module.fileIdx == gProjectMainIdx
|
||||||
|
elif compiles(m.module.fileIdx):
|
||||||
|
m.module.fileIdx == gProjectMainIdx
|
||||||
elif compiles(L.fileIdx):
|
elif compiles(L.fileIdx):
|
||||||
L.fileIdx == gProjectMainIdx
|
L.fileIdx == gProjectMainIdx
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
# little HACK to support the new 'var T' as return type:
|
# little HACK to support the new 'var T' as return type:
|
||||||
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
||||||
return
|
return
|
||||||
let ty = skipTypes(dest.t, abstractRange)
|
let ty = skipTypes(dest.t, abstractRange + tyUserTypeClasses)
|
||||||
case ty.kind
|
case ty.kind
|
||||||
of tyRef:
|
of tyRef:
|
||||||
genRefAssign(p, dest, src, flags)
|
genRefAssign(p, dest, src, flags)
|
||||||
|
|
@ -758,7 +758,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||||
genRecordFieldAux(p, e, d, a)
|
genRecordFieldAux(p, e, d, a)
|
||||||
var r = rdLoc(a)
|
var r = rdLoc(a)
|
||||||
var f = e.sons[1].sym
|
var f = e.sons[1].sym
|
||||||
let ty = skipTypes(a.t, abstractInst)
|
let ty = skipTypes(a.t, abstractInst + tyUserTypeClasses)
|
||||||
if ty.kind == tyTuple:
|
if ty.kind == tyTuple:
|
||||||
# we found a unique tuple type which lacks field information
|
# we found a unique tuple type which lacks field information
|
||||||
# so we use Field$i
|
# so we use Field$i
|
||||||
|
|
@ -2205,7 +2205,7 @@ proc getNullValueAux(p: BProc; obj, cons: PNode, result: var Rope) =
|
||||||
let field = obj.sym
|
let field = obj.sym
|
||||||
for i in 1..<cons.len:
|
for i in 1..<cons.len:
|
||||||
if cons[i].kind == nkExprColonExpr:
|
if cons[i].kind == nkExprColonExpr:
|
||||||
if cons[i][0].sym == field:
|
if cons[i][0].sym.name == field.name:
|
||||||
result.add genConstExpr(p, cons[i][1])
|
result.add genConstExpr(p, cons[i][1])
|
||||||
return
|
return
|
||||||
elif i == field.position:
|
elif i == field.position:
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ proc mapType(typ: PType): TCTypeKind =
|
||||||
of tySet: result = mapSetType(typ)
|
of tySet: result = mapSetType(typ)
|
||||||
of tyOpenArray, tyArray, tyVarargs: result = ctArray
|
of tyOpenArray, tyArray, tyVarargs: result = ctArray
|
||||||
of tyObject, tyTuple: result = ctStruct
|
of tyObject, tyTuple: result = ctStruct
|
||||||
of tyUserTypeClass, tyUserTypeClassInst:
|
of tyUserTypeClasses:
|
||||||
internalAssert typ.isResolvedUserTypeClass
|
internalAssert typ.isResolvedUserTypeClass
|
||||||
return mapType(typ.lastSon)
|
return mapType(typ.lastSon)
|
||||||
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
|
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
|
||||||
|
|
@ -1094,7 +1094,7 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
|
||||||
|
|
||||||
proc genTypeInfo(m: BModule, t: PType): Rope =
|
proc genTypeInfo(m: BModule, t: PType): Rope =
|
||||||
let origType = t
|
let origType = t
|
||||||
var t = skipTypes(origType, irrelevantForBackend)
|
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
|
||||||
|
|
||||||
let sig = hashType(origType)
|
let sig = hashType(origType)
|
||||||
result = m.typeInfoMarker.getOrDefault(sig)
|
result = m.typeInfoMarker.getOrDefault(sig)
|
||||||
|
|
@ -1131,6 +1131,9 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
if t.n != nil: result = genTypeInfo(m, lastSon t)
|
if t.n != nil: result = genTypeInfo(m, lastSon t)
|
||||||
else: internalError("genTypeInfo(" & $t.kind & ')')
|
else: internalError("genTypeInfo(" & $t.kind & ')')
|
||||||
|
of tyUserTypeClasses:
|
||||||
|
internalAssert t.isResolvedUserTypeClass
|
||||||
|
return genTypeInfo(m, t.lastSon)
|
||||||
of tyProc:
|
of tyProc:
|
||||||
if t.callConv != ccClosure:
|
if t.callConv != ccClosure:
|
||||||
genTypeInfoAuxBase(m, t, t, result, rope"0")
|
genTypeInfoAuxBase(m, t, t, result, rope"0")
|
||||||
|
|
|
||||||
|
|
@ -103,3 +103,4 @@ proc initDefines*() =
|
||||||
defineSymbol("nimNewShiftOps")
|
defineSymbol("nimNewShiftOps")
|
||||||
defineSymbol("nimDistros")
|
defineSymbol("nimDistros")
|
||||||
defineSymbol("nimHasCppDefine")
|
defineSymbol("nimHasCppDefine")
|
||||||
|
defineSymbol("nimGenericInOutFlags")
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
|
||||||
|
|
||||||
result = newNodeI(nkArgList, n.info)
|
result = newNodeI(nkArgList, n.info)
|
||||||
for i in 1 .. givenRegularParams:
|
for i in 1 .. givenRegularParams:
|
||||||
result.addSon n.sons[i]
|
result.addSon n[i]
|
||||||
|
|
||||||
# handle parameters with default values, which were
|
# handle parameters with default values, which were
|
||||||
# not supplied by the user
|
# not supplied by the user
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ type
|
||||||
errGenericLambdaNotAllowed,
|
errGenericLambdaNotAllowed,
|
||||||
errProcHasNoConcreteType,
|
errProcHasNoConcreteType,
|
||||||
errCompilerDoesntSupportTarget,
|
errCompilerDoesntSupportTarget,
|
||||||
|
errInOutFlagNotExtern,
|
||||||
errUser,
|
errUser,
|
||||||
warnCannotOpenFile,
|
warnCannotOpenFile,
|
||||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||||
|
|
@ -380,6 +381,7 @@ const
|
||||||
"of the generic paramers can be inferred from the expected signature.",
|
"of the generic paramers can be inferred from the expected signature.",
|
||||||
errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.",
|
errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.",
|
||||||
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
|
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
|
||||||
|
errInOutFlagNotExtern: "The `$1` modifier can be used only with imported types",
|
||||||
errUser: "$1",
|
errUser: "$1",
|
||||||
warnCannotOpenFile: "cannot open \'$1\'",
|
warnCannotOpenFile: "cannot open \'$1\'",
|
||||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
|
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,8 @@ proc parseTry(p: var TParser; isExpr: bool): PNode
|
||||||
proc parseCase(p: var TParser): PNode
|
proc parseCase(p: var TParser): PNode
|
||||||
proc parseStmtPragma(p: var TParser): PNode
|
proc parseStmtPragma(p: var TParser): PNode
|
||||||
proc parsePragma(p: var TParser): PNode
|
proc parsePragma(p: var TParser): PNode
|
||||||
|
proc postExprBlocks(p: var TParser, x: PNode): PNode
|
||||||
|
proc parseExprStmt(p: var TParser): PNode
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
proc getTok(p: var TParser) =
|
proc getTok(p: var TParser) =
|
||||||
|
|
@ -194,7 +196,6 @@ proc newIdentNodeP(ident: PIdent, p: TParser): PNode =
|
||||||
proc parseExpr(p: var TParser): PNode
|
proc parseExpr(p: var TParser): PNode
|
||||||
proc parseStmt(p: var TParser): PNode
|
proc parseStmt(p: var TParser): PNode
|
||||||
proc parseTypeDesc(p: var TParser): PNode
|
proc parseTypeDesc(p: var TParser): PNode
|
||||||
proc parseDoBlocks(p: var TParser, call: PNode)
|
|
||||||
proc parseParamList(p: var TParser, retColon = true): PNode
|
proc parseParamList(p: var TParser, retColon = true): PNode
|
||||||
|
|
||||||
proc isSigilLike(tok: TToken): bool {.inline.} =
|
proc isSigilLike(tok: TToken): bool {.inline.} =
|
||||||
|
|
@ -365,6 +366,9 @@ proc colonOrEquals(p: var TParser, a: PNode): PNode =
|
||||||
proc exprColonEqExpr(p: var TParser): PNode =
|
proc exprColonEqExpr(p: var TParser): PNode =
|
||||||
#| exprColonEqExpr = expr (':'|'=' expr)?
|
#| exprColonEqExpr = expr (':'|'=' expr)?
|
||||||
var a = parseExpr(p)
|
var a = parseExpr(p)
|
||||||
|
if p.tok.tokType == tkDo:
|
||||||
|
result = postExprBlocks(p, a)
|
||||||
|
else:
|
||||||
result = colonOrEquals(p, a)
|
result = colonOrEquals(p, a)
|
||||||
|
|
||||||
proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
|
proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
|
||||||
|
|
@ -520,7 +524,9 @@ proc parsePar(p: var TParser): PNode =
|
||||||
result.add(parseStmtPragma(p))
|
result.add(parseStmtPragma(p))
|
||||||
elif p.tok.tokType != tkParRi:
|
elif p.tok.tokType != tkParRi:
|
||||||
var a = simpleExpr(p)
|
var a = simpleExpr(p)
|
||||||
if p.tok.tokType == tkEquals:
|
if p.tok.tokType == tkDo:
|
||||||
|
result = postExprBlocks(p, a)
|
||||||
|
elif p.tok.tokType == tkEquals:
|
||||||
# special case: allow assignments
|
# special case: allow assignments
|
||||||
let asgn = newNodeP(nkAsgn, p)
|
let asgn = newNodeP(nkAsgn, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
@ -669,7 +675,6 @@ proc namedParams(p: var TParser, callee: PNode,
|
||||||
# progress guaranteed
|
# progress guaranteed
|
||||||
exprColonEqExprListAux(p, endTok, result)
|
exprColonEqExprListAux(p, endTok, result)
|
||||||
|
|
||||||
proc parseMacroColon(p: var TParser, x: PNode): PNode
|
|
||||||
proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
||||||
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
||||||
#| | doBlocks
|
#| | doBlocks
|
||||||
|
|
@ -696,14 +701,6 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
||||||
result = namedParams(p, result, nkCall, tkParRi)
|
result = namedParams(p, result, nkCall, tkParRi)
|
||||||
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
|
||||||
elif p.tok.tokType == tkDo:
|
|
||||||
parseDoBlocks(p, result)
|
|
||||||
of tkDo:
|
|
||||||
# progress guaranteed
|
|
||||||
var a = result
|
|
||||||
result = newNodeP(nkCall, p)
|
|
||||||
addSon(result, a)
|
|
||||||
parseDoBlocks(p, result)
|
|
||||||
of tkDot:
|
of tkDot:
|
||||||
# progress guaranteed
|
# progress guaranteed
|
||||||
result = dotExpr(p, result)
|
result = dotExpr(p, result)
|
||||||
|
|
@ -735,10 +732,7 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
||||||
if p.tok.tokType != tkComma: break
|
if p.tok.tokType != tkComma: break
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, x)
|
optInd(p, x)
|
||||||
if p.tok.tokType == tkDo:
|
result = postExprBlocks(p, result)
|
||||||
parseDoBlocks(p, result)
|
|
||||||
else:
|
|
||||||
result = parseMacroColon(p, result)
|
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
@ -977,16 +971,9 @@ proc parseDoBlock(p: var TParser; info: TLineInfo): PNode =
|
||||||
let params = parseParamList(p, retColon=false)
|
let params = parseParamList(p, retColon=false)
|
||||||
let pragmas = optPragmas(p)
|
let pragmas = optPragmas(p)
|
||||||
colcom(p, result)
|
colcom(p, result)
|
||||||
result = newProcNode(nkDo, info, parseStmt(p),
|
result = parseStmt(p)
|
||||||
params = params,
|
if params.kind != nkEmpty:
|
||||||
pragmas = pragmas)
|
result = newProcNode(nkDo, info, result, params = params, pragmas = pragmas)
|
||||||
|
|
||||||
proc parseDoBlocks(p: var TParser, call: PNode) =
|
|
||||||
#| doBlocks = doBlock ^* IND{=}
|
|
||||||
while sameOrNoInd(p) and p.tok.tokType == tkDo:
|
|
||||||
let info = parLineInfo(p)
|
|
||||||
getTok(p)
|
|
||||||
addSon(call, parseDoBlock(p, info))
|
|
||||||
|
|
||||||
proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
|
proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
|
||||||
#| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
|
#| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
|
||||||
|
|
@ -1162,49 +1149,75 @@ proc makeCall(n: PNode): PNode =
|
||||||
result = newNodeI(nkCall, n.info)
|
result = newNodeI(nkCall, n.info)
|
||||||
result.add n
|
result.add n
|
||||||
|
|
||||||
proc parseMacroColon(p: var TParser, x: PNode): PNode =
|
proc postExprBlocks(p: var TParser, x: PNode): PNode =
|
||||||
#| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
|
#| postExprBlocks = ':' stmt? ( IND{=} doBlock
|
||||||
|
#| | IND{=} 'of' exprList ':' stmt
|
||||||
#| | IND{=} 'elif' expr ':' stmt
|
#| | IND{=} 'elif' expr ':' stmt
|
||||||
#| | IND{=} 'except' exprList ':' stmt
|
#| | IND{=} 'except' exprList ':' stmt
|
||||||
#| | IND{=} 'else' ':' stmt )*
|
#| | IND{=} 'else' ':' stmt )*
|
||||||
result = x
|
result = x
|
||||||
if p.tok.tokType == tkColon and p.tok.indent < 0:
|
if p.tok.indent >= 0: return
|
||||||
|
|
||||||
|
var
|
||||||
|
openingParams = emptyNode
|
||||||
|
openingPragmas = emptyNode
|
||||||
|
|
||||||
|
if p.tok.tokType == tkDo:
|
||||||
|
getTok(p)
|
||||||
|
openingParams = parseParamList(p, retColon=false)
|
||||||
|
openingPragmas = optPragmas(p)
|
||||||
|
|
||||||
|
if p.tok.tokType == tkColon:
|
||||||
result = makeCall(result)
|
result = makeCall(result)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
skipComment(p, result)
|
skipComment(p, result)
|
||||||
let stmtList = newNodeP(nkStmtList, p)
|
|
||||||
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
||||||
let body = parseStmt(p)
|
var stmtList = newNodeP(nkStmtList, p)
|
||||||
stmtList.add body
|
stmtList.add parseStmt(p)
|
||||||
#addSon(result, makeStmtList(body))
|
# to keep backwards compatibility (see tests/vm/tstringnil)
|
||||||
# progress guaranteed
|
if stmtList[0].kind == nkStmtList: stmtList = stmtList[0]
|
||||||
|
|
||||||
|
stmtList.flags.incl nfBlockArg
|
||||||
|
if openingParams.kind != nkEmpty:
|
||||||
|
result.add newProcNode(nkDo, stmtList.info, stmtList,
|
||||||
|
params = openingParams, pragmas = openingPragmas)
|
||||||
|
else:
|
||||||
|
result.add stmtList
|
||||||
|
|
||||||
while sameInd(p):
|
while sameInd(p):
|
||||||
var b: PNode
|
var nextBlock: PNode
|
||||||
case p.tok.tokType
|
let nextToken = p.tok.tokType
|
||||||
of tkOf:
|
if nextToken == tkDo:
|
||||||
b = newNodeP(nkOfBranch, p)
|
let info = parLineInfo(p)
|
||||||
exprList(p, tkColon, b)
|
|
||||||
of tkElif:
|
|
||||||
b = newNodeP(nkElifBranch, p)
|
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, b)
|
nextBlock = parseDoBlock(p, info)
|
||||||
addSon(b, parseExpr(p))
|
else:
|
||||||
|
case nextToken:
|
||||||
|
of tkOf:
|
||||||
|
nextBlock = newNodeP(nkOfBranch, p)
|
||||||
|
exprList(p, tkColon, nextBlock)
|
||||||
|
of tkElif:
|
||||||
|
nextBlock = newNodeP(nkElifBranch, p)
|
||||||
|
getTok(p)
|
||||||
|
optInd(p, nextBlock)
|
||||||
|
nextBlock.addSon parseExpr(p)
|
||||||
of tkExcept:
|
of tkExcept:
|
||||||
b = newNodeP(nkExceptBranch, p)
|
nextBlock = newNodeP(nkExceptBranch, p)
|
||||||
exprList(p, tkColon, b)
|
exprList(p, tkColon, nextBlock)
|
||||||
of tkElse:
|
of tkElse:
|
||||||
b = newNodeP(nkElse, p)
|
nextBlock = newNodeP(nkElse, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
else: break
|
else: break
|
||||||
eat(p, tkColon)
|
eat(p, tkColon)
|
||||||
addSon(b, parseStmt(p))
|
nextBlock.addSon parseStmt(p)
|
||||||
addSon(stmtList, b)
|
|
||||||
if b.kind == nkElse: break
|
nextBlock.flags.incl nfBlockArg
|
||||||
if stmtList.len == 1 and stmtList[0].kind == nkStmtList:
|
result.add nextBlock
|
||||||
# to keep backwards compatibility (see tests/vm/tstringnil)
|
|
||||||
result.add stmtList[0]
|
if nextBlock.kind == nkElse: break
|
||||||
else:
|
else:
|
||||||
result.add stmtList
|
if openingParams.kind != nkEmpty:
|
||||||
|
parMessage(p, errTokenExpected, ":")
|
||||||
|
|
||||||
proc parseExprStmt(p: var TParser): PNode =
|
proc parseExprStmt(p: var TParser): PNode =
|
||||||
#| exprStmt = simpleExpr
|
#| exprStmt = simpleExpr
|
||||||
|
|
@ -1219,12 +1232,7 @@ proc parseExprStmt(p: var TParser): PNode =
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
var b = parseExpr(p)
|
var b = parseExpr(p)
|
||||||
if p.tok.tokType == tkColon and p.tok.indent < 0:
|
b = postExprBlocks(p, b)
|
||||||
if b.kind != nkEmpty:
|
|
||||||
let call = makeCall(b)
|
|
||||||
call.add parseDoBlock(p, parLineInfo(p))
|
|
||||||
parseDoBlocks(p, call)
|
|
||||||
b = call
|
|
||||||
addSon(result, a)
|
addSon(result, a)
|
||||||
addSon(result, b)
|
addSon(result, b)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1247,11 +1255,7 @@ proc parseExprStmt(p: var TParser): PNode =
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
else:
|
else:
|
||||||
result = a
|
result = a
|
||||||
if p.tok.tokType == tkDo and p.tok.indent < 0:
|
result = postExprBlocks(p, result)
|
||||||
result = makeCall(result)
|
|
||||||
parseDoBlocks(p, result)
|
|
||||||
return result
|
|
||||||
result = parseMacroColon(p, result)
|
|
||||||
|
|
||||||
proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
|
proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
|
||||||
result = parseExpr(p)
|
result = parseExpr(p)
|
||||||
|
|
@ -1341,7 +1345,9 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
|
||||||
# NL terminates:
|
# NL terminates:
|
||||||
addSon(result, ast.emptyNode)
|
addSon(result, ast.emptyNode)
|
||||||
else:
|
else:
|
||||||
addSon(result, parseExpr(p))
|
var e = parseExpr(p)
|
||||||
|
e = postExprBlocks(p, e)
|
||||||
|
addSon(result, e)
|
||||||
|
|
||||||
proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
|
proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
|
||||||
#| condStmt = expr colcom stmt COMMENT?
|
#| condStmt = expr colcom stmt COMMENT?
|
||||||
|
|
@ -1514,6 +1520,13 @@ proc parseGenericParam(p: var TParser): PNode =
|
||||||
# progress guaranteed
|
# progress guaranteed
|
||||||
while true:
|
while true:
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
|
of tkIn, tkOut:
|
||||||
|
let x = p.lex.cache.getIdent(if p.tok.tokType == tkIn: "in" else: "out")
|
||||||
|
a = newNodeP(nkPrefix, p)
|
||||||
|
a.addSon newIdentNodeP(x, p)
|
||||||
|
getTok(p)
|
||||||
|
expectIdent(p)
|
||||||
|
a.addSon(parseSymbol(p))
|
||||||
of tkSymbol, tkAccent:
|
of tkSymbol, tkAccent:
|
||||||
a = parseSymbol(p)
|
a = parseSymbol(p)
|
||||||
if a.kind == nkEmpty: return
|
if a.kind == nkEmpty: return
|
||||||
|
|
@ -1542,7 +1555,7 @@ proc parseGenericParamList(p: var TParser): PNode =
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
# progress guaranteed
|
# progress guaranteed
|
||||||
while p.tok.tokType in {tkSymbol, tkAccent}:
|
while p.tok.tokType in {tkSymbol, tkAccent, tkIn, tkOut}:
|
||||||
var a = parseGenericParam(p)
|
var a = parseGenericParam(p)
|
||||||
addSon(result, a)
|
addSon(result, a)
|
||||||
if p.tok.tokType notin {tkComma, tkSemiColon}: break
|
if p.tok.tokType notin {tkComma, tkSemiColon}: break
|
||||||
|
|
@ -1893,14 +1906,7 @@ proc parseVariable(p: var TParser): PNode =
|
||||||
#| variable = (varTuple / identColonEquals) colonBody? indAndComment
|
#| variable = (varTuple / identColonEquals) colonBody? indAndComment
|
||||||
if p.tok.tokType == tkParLe: result = parseVarTuple(p)
|
if p.tok.tokType == tkParLe: result = parseVarTuple(p)
|
||||||
else: result = parseIdentColonEquals(p, {withPragma})
|
else: result = parseIdentColonEquals(p, {withPragma})
|
||||||
if p.tok.tokType == tkColon and p.tok.indent < 0:
|
result{-1} = postExprBlocks(p, result{-1})
|
||||||
let last = result.len-1
|
|
||||||
let ex = result.sons[last]
|
|
||||||
if ex.kind != nkEmpty:
|
|
||||||
let call = makeCall(ex)
|
|
||||||
call.add parseDoBlock(p, parLineInfo(p))
|
|
||||||
parseDoBlocks(p, call)
|
|
||||||
result.sons[last] = call
|
|
||||||
indAndComment(p, result)
|
indAndComment(p, result)
|
||||||
|
|
||||||
proc parseBind(p: var TParser, k: TNodeKind): PNode =
|
proc parseBind(p: var TParser, k: TNodeKind): PNode =
|
||||||
|
|
|
||||||
|
|
@ -1336,6 +1336,11 @@ proc parseGenericParam(p: var TParser): PNode =
|
||||||
result = newNodeP(nkIdentDefs, p)
|
result = newNodeP(nkIdentDefs, p)
|
||||||
while true:
|
while true:
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
|
of tkIn, tkOut:
|
||||||
|
let t = p.tok.tokType
|
||||||
|
getTok(p)
|
||||||
|
expectIdent(p)
|
||||||
|
a = parseSymbol(p)
|
||||||
of tkSymbol, tkAccent:
|
of tkSymbol, tkAccent:
|
||||||
a = parseSymbol(p)
|
a = parseSymbol(p)
|
||||||
if a.kind == nkEmpty: return
|
if a.kind == nkEmpty: return
|
||||||
|
|
|
||||||
|
|
@ -351,8 +351,8 @@ when false:
|
||||||
for i in 0 ..< n.safeLen:
|
for i in 0 ..< n.safeLen:
|
||||||
resetSemFlag(n[i])
|
resetSemFlag(n[i])
|
||||||
|
|
||||||
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||||
flags: TExprFlags): PNode =
|
s: PSym, flags: TExprFlags): PNode =
|
||||||
## Semantically check the output of a macro.
|
## Semantically check the output of a macro.
|
||||||
## This involves processes such as re-checking the macro output for type
|
## This involves processes such as re-checking the macro output for type
|
||||||
## coherence, making sure that variables declared with 'let' aren't
|
## coherence, making sure that variables declared with 'let' aren't
|
||||||
|
|
@ -363,8 +363,8 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||||
globalError(s.info, errTemplateInstantiationTooNested)
|
globalError(s.info, errTemplateInstantiationTooNested)
|
||||||
c.friendModules.add(s.owner.getModule)
|
c.friendModules.add(s.owner.getModule)
|
||||||
|
|
||||||
result = n
|
result = macroResult
|
||||||
excl(n.flags, nfSem)
|
excl(result.flags, nfSem)
|
||||||
#resetSemFlag n
|
#resetSemFlag n
|
||||||
if s.typ.sons[0] == nil:
|
if s.typ.sons[0] == nil:
|
||||||
result = semStmt(c, result)
|
result = semStmt(c, result)
|
||||||
|
|
@ -378,13 +378,26 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||||
of tyStmt:
|
of tyStmt:
|
||||||
result = semStmt(c, result)
|
result = semStmt(c, result)
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
if n.kind == nkStmtList: result.kind = nkStmtListType
|
if result.kind == nkStmtList: result.kind = nkStmtListType
|
||||||
var typ = semTypeNode(c, result, nil)
|
var typ = semTypeNode(c, result, nil)
|
||||||
result.typ = makeTypeDesc(c, typ)
|
result.typ = makeTypeDesc(c, typ)
|
||||||
#result = symNodeFromType(c, typ, n.info)
|
#result = symNodeFromType(c, typ, n.info)
|
||||||
else:
|
else:
|
||||||
|
var retType = s.typ.sons[0]
|
||||||
|
if s.ast[genericParamsPos] != nil and retType.isMetaType:
|
||||||
|
# The return type may depend on the Macro arguments
|
||||||
|
# e.g. template foo(T: typedesc): seq[T]
|
||||||
|
# We will instantiate the return type here, because
|
||||||
|
# we now know the supplied arguments
|
||||||
|
var paramTypes = newIdTable()
|
||||||
|
for param, value in genericParamsInMacroCall(s, call):
|
||||||
|
idTablePut(paramTypes, param.typ, value.typ)
|
||||||
|
|
||||||
|
retType = generateTypeInstance(c, paramTypes,
|
||||||
|
macroResult.info, retType)
|
||||||
|
|
||||||
result = semExpr(c, result, flags)
|
result = semExpr(c, result, flags)
|
||||||
result = fitNode(c, s.typ.sons[0], result, result.info)
|
result = fitNode(c, retType, result, result.info)
|
||||||
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
|
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
|
||||||
dec(evalTemplateCounter)
|
dec(evalTemplateCounter)
|
||||||
discard c.friendModules.pop()
|
discard c.friendModules.pop()
|
||||||
|
|
@ -409,7 +422,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||||
# c.evalContext = c.createEvalContext(emStatic)
|
# c.evalContext = c.createEvalContext(emStatic)
|
||||||
result = evalMacroCall(c.module, c.cache, n, nOrig, sym)
|
result = evalMacroCall(c.module, c.cache, n, nOrig, sym)
|
||||||
if efNoSemCheck notin flags:
|
if efNoSemCheck notin flags:
|
||||||
result = semAfterMacroCall(c, result, sym, flags)
|
result = semAfterMacroCall(c, n, result, sym, flags)
|
||||||
result = wrapInComesFrom(nOrig.info, result)
|
result = wrapInComesFrom(nOrig.info, result)
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -429,7 +429,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
for i in 1..sonsLen(n)-1:
|
for i in 1..sonsLen(n)-1:
|
||||||
let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
|
let formal = s.ast.sons[genericParamsPos].sons[i-1].typ
|
||||||
let arg = n[i].typ
|
let arg = n[i].typ
|
||||||
let tm = typeRel(m, formal, arg, true)
|
let tm = typeRel(m, formal, arg)
|
||||||
if tm in {isNone, isConvertible}: return nil
|
if tm in {isNone, isConvertible}: return nil
|
||||||
var newInst = generateInstance(c, s, m.bindings, n.info)
|
var newInst = generateInstance(c, s, m.bindings, n.info)
|
||||||
newInst.typ.flags.excl tfUnresolved
|
newInst.typ.flags.excl tfUnresolved
|
||||||
|
|
|
||||||
|
|
@ -277,6 +277,10 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
|
||||||
assert n != nil
|
assert n != nil
|
||||||
result.n = n
|
result.n = n
|
||||||
|
|
||||||
|
proc newTypeWithSons2*(kind: TTypeKind, owner: PSym, sons: seq[PType]): PType =
|
||||||
|
result = newType(kind, owner)
|
||||||
|
result.sons = sons
|
||||||
|
|
||||||
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
|
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
|
||||||
sons: seq[PType]): PType =
|
sons: seq[PType]): PType =
|
||||||
result = newType(kind, getCurrOwner(c))
|
result = newType(kind, getCurrOwner(c))
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||||
styleCheckUse(n.info, s)
|
styleCheckUse(n.info, s)
|
||||||
pushInfoContext(n.info)
|
pushInfoContext(n.info)
|
||||||
result = evalTemplate(n, s, getCurrOwner(c), efFromHlo in flags)
|
result = evalTemplate(n, s, getCurrOwner(c), efFromHlo in flags)
|
||||||
if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
|
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
||||||
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||||
|
|
@ -47,6 +47,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
#raiseRecoverableError("")
|
#raiseRecoverableError("")
|
||||||
result = errorNode(c, n)
|
result = errorNode(c, n)
|
||||||
if result.typ == nil or result.typ == enforceVoidContext:
|
if result.typ == nil or result.typ == enforceVoidContext:
|
||||||
|
if n.kind != nkStmtList:
|
||||||
# we cannot check for 'void' in macros ...
|
# we cannot check for 'void' in macros ...
|
||||||
localError(n.info, errExprXHasNoType,
|
localError(n.info, errExprXHasNoType,
|
||||||
renderTree(result, {renderNoComments}))
|
renderTree(result, {renderNoComments}))
|
||||||
|
|
@ -682,27 +683,9 @@ proc bracketedMacro(n: PNode): PSym =
|
||||||
if result.kind notin {skMacro, skTemplate}:
|
if result.kind notin {skMacro, skTemplate}:
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
proc semBracketedMacro(c: PContext; outer, inner: PNode; s: PSym;
|
proc setGenericParams(c: PContext, n: PNode) =
|
||||||
flags: TExprFlags): PNode =
|
for i in 1 .. <n.len:
|
||||||
# We received untransformed bracket expression coming from macroOrTmpl[].
|
n[i].typ = semTypeNode(c, n[i], nil)
|
||||||
# Transform it to macro or template call, where first come normal
|
|
||||||
# arguments, next come generic template arguments.
|
|
||||||
var sons = newSeq[PNode]()
|
|
||||||
sons.add inner.sons[0]
|
|
||||||
# Normal arguments:
|
|
||||||
for i in 1..<outer.len:
|
|
||||||
sons.add outer.sons[i]
|
|
||||||
# Generic template arguments from bracket expression:
|
|
||||||
for i in 1..<inner.len:
|
|
||||||
sons.add inner.sons[i]
|
|
||||||
shallowCopy(outer.sons, sons)
|
|
||||||
# FIXME: Shouldn't we check sfImmediate and call semDirectOp?
|
|
||||||
# However passing to semDirectOp doesn't work here.
|
|
||||||
case s.kind
|
|
||||||
of skMacro: result = semMacroExpr(c, outer, outer, s, flags)
|
|
||||||
of skTemplate: result = semTemplateExpr(c, outer, s, flags)
|
|
||||||
else: assert(false)
|
|
||||||
return
|
|
||||||
|
|
||||||
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -744,7 +727,8 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
elif n.sons[0].kind == nkBracketExpr:
|
elif n.sons[0].kind == nkBracketExpr:
|
||||||
let s = bracketedMacro(n.sons[0])
|
let s = bracketedMacro(n.sons[0])
|
||||||
if s != nil:
|
if s != nil:
|
||||||
return semBracketedMacro(c, n, n.sons[0], s, flags)
|
setGenericParams(c, n[0])
|
||||||
|
return semDirectOp(c, n, flags)
|
||||||
|
|
||||||
let nOrig = n.copyTree
|
let nOrig = n.copyTree
|
||||||
semOpAux(c, n)
|
semOpAux(c, n)
|
||||||
|
|
@ -1155,6 +1139,8 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
ty = n.sons[0].typ
|
ty = n.sons[0].typ
|
||||||
return nil
|
return nil
|
||||||
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef, tyAlias})
|
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef, tyAlias})
|
||||||
|
if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
|
||||||
|
ty = ty.lastSon
|
||||||
while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
|
while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
|
||||||
var check: PNode = nil
|
var check: PNode = nil
|
||||||
if ty.kind == tyObject:
|
if ty.kind == tyObject:
|
||||||
|
|
@ -1713,7 +1699,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||||
# We transform the do block into a template with a param for
|
# We transform the do block into a template with a param for
|
||||||
# each interpolation. We'll pass this template to getAst.
|
# each interpolation. We'll pass this template to getAst.
|
||||||
var
|
var
|
||||||
doBlk = n{-1}
|
quotedBlock = n{-1}
|
||||||
op = if n.len == 3: expectString(c, n[1]) else: "``"
|
op = if n.len == 3: expectString(c, n[1]) else: "``"
|
||||||
quotes = newSeq[PNode](1)
|
quotes = newSeq[PNode](1)
|
||||||
# the quotes will be added to a nkCall statement
|
# the quotes will be added to a nkCall statement
|
||||||
|
|
@ -1721,20 +1707,23 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||||
ids = newSeq[PNode]()
|
ids = newSeq[PNode]()
|
||||||
# this will store the generated param names
|
# this will store the generated param names
|
||||||
|
|
||||||
if doBlk.kind != nkDo:
|
if quotedBlock.kind != nkStmtList:
|
||||||
localError(n.info, errXExpected, "block")
|
localError(n.info, errXExpected, "block")
|
||||||
|
|
||||||
processQuotations(doBlk.sons[bodyPos], op, quotes, ids)
|
processQuotations(quotedBlock, op, quotes, ids)
|
||||||
|
|
||||||
|
var dummyTemplate = newProcNode(
|
||||||
|
nkTemplateDef, quotedBlock.info, quotedBlock,
|
||||||
|
name = newAnonSym(c, skTemplate, n.info).newSymNode)
|
||||||
|
|
||||||
doBlk.sons[namePos] = newAnonSym(c, skTemplate, n.info).newSymNode
|
|
||||||
if ids.len > 0:
|
if ids.len > 0:
|
||||||
doBlk.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
|
dummyTemplate.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
|
||||||
doBlk[paramsPos].add getSysSym("typed").newSymNode # return type
|
dummyTemplate[paramsPos].add getSysSym("typed").newSymNode # return type
|
||||||
ids.add getSysSym("untyped").newSymNode # params type
|
ids.add getSysSym("untyped").newSymNode # params type
|
||||||
ids.add emptyNode # no default value
|
ids.add emptyNode # no default value
|
||||||
doBlk[paramsPos].add newNode(nkIdentDefs, n.info, ids)
|
dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids)
|
||||||
|
|
||||||
var tmpl = semTemplateDef(c, doBlk)
|
var tmpl = semTemplateDef(c, dummyTemplate)
|
||||||
quotes[0] = tmpl[namePos]
|
quotes[0] = tmpl[namePos]
|
||||||
result = newNode(nkCall, n.info, @[
|
result = newNode(nkCall, n.info, @[
|
||||||
getMagicSym(mExpandToAst).newSymNode,
|
getMagicSym(mExpandToAst).newSymNode,
|
||||||
|
|
@ -2158,10 +2147,6 @@ proc shouldBeBracketExpr(n: PNode): bool =
|
||||||
n.sons[0] = be
|
n.sons[0] = be
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc setGenericParams(c: PContext, n: PNode) =
|
|
||||||
for i in 1 .. <n.len:
|
|
||||||
n[i].typ = semTypeNode(c, n[i], nil)
|
|
||||||
|
|
||||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
result = n
|
result = n
|
||||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||||
|
|
@ -2325,8 +2310,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkCurly: result = semSetConstr(c, n)
|
of nkCurly: result = semSetConstr(c, n)
|
||||||
of nkBracket: result = semArrayConstr(c, n, flags)
|
of nkBracket: result = semArrayConstr(c, n, flags)
|
||||||
of nkObjConstr: result = semObjConstr(c, n, flags)
|
of nkObjConstr: result = semObjConstr(c, n, flags)
|
||||||
of nkLambda: result = semLambda(c, n, flags)
|
of nkLambdaKinds: result = semLambda(c, n, flags)
|
||||||
of nkDo: result = semDo(c, n, flags)
|
|
||||||
of nkDerefExpr: result = semDeref(c, n)
|
of nkDerefExpr: result = semDeref(c, n)
|
||||||
of nkAddr:
|
of nkAddr:
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -121,12 +121,13 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
||||||
localError(n.info, errWrongNumberOfVariables)
|
localError(n.info, errWrongNumberOfVariables)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
|
const skippedTypesForFields = abstractVar - {tyTypeDesc} + tyUserTypeClasses
|
||||||
|
var tupleTypeA = skipTypes(call.sons[1].typ, skippedTypesForFields)
|
||||||
if tupleTypeA.kind notin {tyTuple, tyObject}:
|
if tupleTypeA.kind notin {tyTuple, tyObject}:
|
||||||
localError(n.info, errGenerated, "no object or tuple type")
|
localError(n.info, errGenerated, "no object or tuple type")
|
||||||
return result
|
return result
|
||||||
for i in 1..call.len-1:
|
for i in 1..call.len-1:
|
||||||
var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc})
|
var tupleTypeB = skipTypes(call.sons[i].typ, skippedTypesForFields)
|
||||||
if not sameType(tupleTypeA, tupleTypeB):
|
if not sameType(tupleTypeA, tupleTypeB):
|
||||||
typeMismatch(call.sons[i].info, tupleTypeA, tupleTypeB)
|
typeMismatch(call.sons[i].info, tupleTypeA, tupleTypeB)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@ proc rawPushProcCon(c: PContext, owner: PSym) =
|
||||||
c.p = x
|
c.p = x
|
||||||
|
|
||||||
proc rawHandleSelf(c: PContext; owner: PSym) =
|
proc rawHandleSelf(c: PContext; owner: PSym) =
|
||||||
if c.selfName != nil and owner.kind in {skProc, skMethod, skConverter, skIterator, skMacro} and owner.typ != nil:
|
const callableSymbols = {skProc, skMethod, skConverter, skIterator, skMacro}
|
||||||
|
if c.selfName != nil and owner.kind in callableSymbols and owner.typ != nil:
|
||||||
let params = owner.typ.n
|
let params = owner.typ.n
|
||||||
if params.len > 1:
|
if params.len > 1:
|
||||||
let arg = params[1].sym
|
let arg = params[1].sym
|
||||||
|
|
|
||||||
|
|
@ -109,27 +109,43 @@ proc uninstantiate(t: PType): PType =
|
||||||
of tyCompositeTypeClass: uninstantiate t.sons[1]
|
of tyCompositeTypeClass: uninstantiate t.sons[1]
|
||||||
else: t
|
else: t
|
||||||
|
|
||||||
proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
|
proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
|
||||||
var typ = operand.skipTypes({tyTypeDesc})
|
const skippedTypes = {tyTypeDesc}
|
||||||
|
let trait = traitCall[0]
|
||||||
|
internalAssert trait.kind == nkSym
|
||||||
|
var operand = operand.skipTypes(skippedTypes)
|
||||||
|
|
||||||
|
template operand2: PType =
|
||||||
|
traitCall.sons[2].typ.skipTypes({tyTypeDesc})
|
||||||
|
|
||||||
|
template typeWithSonsResult(kind, sons): PNode =
|
||||||
|
newTypeWithSons2(kind, context, sons).toNode(traitCall.info)
|
||||||
|
|
||||||
case trait.sym.name.s
|
case trait.sym.name.s
|
||||||
|
of "or", "|":
|
||||||
|
return typeWithSonsResult(tyOr, @[operand, operand2])
|
||||||
|
of "and":
|
||||||
|
return typeWithSonsResult(tyAnd, @[operand, operand2])
|
||||||
|
of "not":
|
||||||
|
return typeWithSonsResult(tyNot, @[operand])
|
||||||
of "name":
|
of "name":
|
||||||
result = newStrNode(nkStrLit, typ.typeToString(preferName))
|
result = newStrNode(nkStrLit, operand.typeToString(preferName))
|
||||||
result.typ = newType(tyString, context)
|
result.typ = newType(tyString, context)
|
||||||
result.info = trait.info
|
result.info = traitCall.info
|
||||||
of "arity":
|
of "arity":
|
||||||
result = newIntNode(nkIntLit, typ.len - ord(typ.kind==tyProc))
|
result = newIntNode(nkIntLit, operand.len - ord(operand.kind==tyProc))
|
||||||
result.typ = newType(tyInt, context)
|
result.typ = newType(tyInt, context)
|
||||||
result.info = trait.info
|
result.info = traitCall.info
|
||||||
of "genericHead":
|
of "genericHead":
|
||||||
var res = uninstantiate(typ)
|
var res = uninstantiate(operand)
|
||||||
if res == typ and res.kind notin tyMagicGenerics:
|
if res == operand and res.kind notin tyMagicGenerics:
|
||||||
localError(trait.info,
|
localError(traitCall.info,
|
||||||
"genericHead expects a generic type. The given type was " &
|
"genericHead expects a generic type. The given type was " &
|
||||||
typeToString(typ))
|
typeToString(operand))
|
||||||
return newType(tyError, context).toNode(trait.info)
|
return newType(tyError, context).toNode(traitCall.info)
|
||||||
result = res.base.toNode(trait.info)
|
result = res.base.toNode(traitCall.info)
|
||||||
of "stripGenericParams":
|
of "stripGenericParams":
|
||||||
result = uninstantiate(typ).toNode(trait.info)
|
result = uninstantiate(operand).toNode(traitCall.info)
|
||||||
else:
|
else:
|
||||||
internalAssert false
|
internalAssert false
|
||||||
|
|
||||||
|
|
@ -140,7 +156,7 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
|
||||||
if t.sonsLen > 0:
|
if t.sonsLen > 0:
|
||||||
# This is either a type known to sem or a typedesc
|
# This is either a type known to sem or a typedesc
|
||||||
# param to a regular proc (again, known at instantiation)
|
# param to a regular proc (again, known at instantiation)
|
||||||
result = evalTypeTrait(n[0], t, getCurrOwner(c))
|
result = evalTypeTrait(n, t, getCurrOwner(c))
|
||||||
else:
|
else:
|
||||||
# a typedesc variable, pass unmodified to evals
|
# a typedesc variable, pass unmodified to evals
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -730,7 +730,9 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
||||||
var s: PSym
|
var s: PSym
|
||||||
if name.kind == nkDotExpr:
|
if name.kind == nkDotExpr:
|
||||||
s = qualifiedLookUp(c, name, {checkUndeclared, checkModule})
|
s = qualifiedLookUp(c, name, {checkUndeclared, checkModule})
|
||||||
if s.kind != skType or s.typ.skipTypes(abstractPtrs).kind != tyObject or tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
|
if s.kind != skType or
|
||||||
|
s.typ.skipTypes(abstractPtrs).kind != tyObject or
|
||||||
|
tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
|
||||||
localError(name.info, "only .partial objects can be extended")
|
localError(name.info, "only .partial objects can be extended")
|
||||||
else:
|
else:
|
||||||
s = semIdentDef(c, name, skType)
|
s = semIdentDef(c, name, skType)
|
||||||
|
|
@ -742,6 +744,87 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
||||||
if sfGenSym notin s.flags: addInterfaceDecl(c, s)
|
if sfGenSym notin s.flags: addInterfaceDecl(c, s)
|
||||||
a.sons[0] = newSymNode(s)
|
a.sons[0] = newSymNode(s)
|
||||||
|
|
||||||
|
proc checkCovariantParamsUsages(genericType: PType) =
|
||||||
|
var body = genericType{-1}
|
||||||
|
|
||||||
|
proc traverseSubTypes(t: PType): bool =
|
||||||
|
template error(msg) = localError(genericType.sym.info, msg)
|
||||||
|
|
||||||
|
result = false
|
||||||
|
|
||||||
|
template subresult(r) =
|
||||||
|
let sub = r
|
||||||
|
result = result or sub
|
||||||
|
|
||||||
|
case t.kind
|
||||||
|
of tyGenericParam:
|
||||||
|
t.flags.incl tfWeakCovariant
|
||||||
|
return true
|
||||||
|
|
||||||
|
of tyObject:
|
||||||
|
for field in t.n:
|
||||||
|
subresult traverseSubTypes(field.typ)
|
||||||
|
|
||||||
|
of tyArray:
|
||||||
|
return traverseSubTypes(t[1])
|
||||||
|
|
||||||
|
of tyProc:
|
||||||
|
for subType in t.sons:
|
||||||
|
if subType != nil:
|
||||||
|
subresult traverseSubTypes(subType)
|
||||||
|
if result:
|
||||||
|
error("non-invariant type param used in a proc type: " & $t)
|
||||||
|
|
||||||
|
of tySequence:
|
||||||
|
return traverseSubTypes(t[0])
|
||||||
|
|
||||||
|
of tyGenericInvocation:
|
||||||
|
let targetBody = t[0]
|
||||||
|
for i in 1 .. <t.len:
|
||||||
|
let param = t[i]
|
||||||
|
if param.kind == tyGenericParam:
|
||||||
|
if tfCovariant in param.flags:
|
||||||
|
let formalFlags = targetBody[i-1].flags
|
||||||
|
if tfCovariant notin formalFlags:
|
||||||
|
error("covariant param '" & param.sym.name.s &
|
||||||
|
"' used in a non-covariant position")
|
||||||
|
elif tfWeakCovariant in formalFlags:
|
||||||
|
param.flags.incl tfWeakCovariant
|
||||||
|
result = true
|
||||||
|
elif tfContravariant in param.flags:
|
||||||
|
let formalParam = targetBody[i-1].sym
|
||||||
|
if tfContravariant notin formalParam.typ.flags:
|
||||||
|
error("contravariant param '" & param.sym.name.s &
|
||||||
|
"' used in a non-contravariant position")
|
||||||
|
result = true
|
||||||
|
else:
|
||||||
|
subresult traverseSubTypes(param)
|
||||||
|
|
||||||
|
of tyAnd, tyOr, tyNot, tyStatic, tyBuiltInTypeClass, tyCompositeTypeClass:
|
||||||
|
error("non-invariant type parameters cannot be used with types such '" & $t & "'")
|
||||||
|
|
||||||
|
of tyUserTypeClass, tyUserTypeClassInst:
|
||||||
|
error("non-invariant type parameters are not supported in concepts")
|
||||||
|
|
||||||
|
of tyTuple:
|
||||||
|
for fieldType in t.sons:
|
||||||
|
subresult traverseSubTypes(fieldType)
|
||||||
|
|
||||||
|
of tyPtr, tyRef, tyVar:
|
||||||
|
if t.base.kind == tyGenericParam: return true
|
||||||
|
return traverseSubTypes(t.base)
|
||||||
|
|
||||||
|
of tyDistinct, tyAlias:
|
||||||
|
return traverseSubTypes(t.lastSon)
|
||||||
|
|
||||||
|
of tyGenericInst:
|
||||||
|
internalAssert false
|
||||||
|
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
discard traverseSubTypes(body)
|
||||||
|
|
||||||
proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
proc typeSectionRightSidePass(c: PContext, n: 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]
|
||||||
|
|
@ -782,6 +865,22 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
body.sym = s
|
body.sym = s
|
||||||
body.size = -1 # could not be computed properly
|
body.size = -1 # could not be computed properly
|
||||||
s.typ.sons[sonsLen(s.typ) - 1] = body
|
s.typ.sons[sonsLen(s.typ) - 1] = body
|
||||||
|
if tfCovariant in s.typ.flags:
|
||||||
|
checkCovariantParamsUsages(s.typ)
|
||||||
|
# XXX: This is a temporary limitation:
|
||||||
|
# The codegen currently produces various failures with
|
||||||
|
# generic imported types that have fields, but we need
|
||||||
|
# the fields specified in order to detect weak covariance.
|
||||||
|
# The proper solution is to teach the codegen how to handle
|
||||||
|
# such types, because this would offer various interesting
|
||||||
|
# possibilities such as instantiating C++ generic types with
|
||||||
|
# garbage collected Nim types.
|
||||||
|
if sfImportc in s.flags:
|
||||||
|
var body = s.typ.lastSon
|
||||||
|
if body.kind == tyObject:
|
||||||
|
# erases all declared fields
|
||||||
|
body.n.sons = nil
|
||||||
|
|
||||||
popOwner(c)
|
popOwner(c)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
elif a.sons[2].kind != nkEmpty:
|
elif a.sons[2].kind != nkEmpty:
|
||||||
|
|
@ -851,9 +950,12 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
|
||||||
# type aliases are hard:
|
# type aliases are hard:
|
||||||
var t = semTypeNode(c, x, nil)
|
var t = semTypeNode(c, x, nil)
|
||||||
assert t != nil
|
assert t != nil
|
||||||
if t.kind in {tyObject, tyEnum, tyDistinct}:
|
if s.typ != nil and s.typ.kind != tyAlias:
|
||||||
|
if t.kind in {tyProc, tyGenericInst} and not t.isMetaType:
|
||||||
|
assignType(s.typ, t)
|
||||||
|
s.typ.id = t.id
|
||||||
|
elif t.kind in {tyObject, tyEnum, tyDistinct}:
|
||||||
assert s.typ != nil
|
assert s.typ != nil
|
||||||
if s.typ.kind != tyAlias:
|
|
||||||
assignType(s.typ, t)
|
assignType(s.typ, t)
|
||||||
s.typ.id = t.id # same id
|
s.typ.id = t.id # same id
|
||||||
checkConstructedType(s.info, s.typ)
|
checkConstructedType(s.info, s.typ)
|
||||||
|
|
@ -1066,13 +1168,6 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
popOwner(c)
|
popOwner(c)
|
||||||
result.typ = s.typ
|
result.typ = s.typ
|
||||||
|
|
||||||
proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|
||||||
# 'do' without params produces a stmt:
|
|
||||||
if n[genericParamsPos].kind == nkEmpty and n[paramsPos].kind == nkEmpty:
|
|
||||||
result = semStmt(c, n[bodyPos])
|
|
||||||
else:
|
|
||||||
result = semLambda(c, n, flags)
|
|
||||||
|
|
||||||
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||||
var n = n
|
var n = n
|
||||||
|
|
||||||
|
|
@ -1177,7 +1272,8 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||||
var objB = t.sons[2]
|
var objB = t.sons[2]
|
||||||
while true:
|
while true:
|
||||||
if objB.kind == tyGenericBody: objB = objB.lastSon
|
if objB.kind == tyGenericBody: objB = objB.lastSon
|
||||||
elif objB.kind == tyGenericInvocation: objB = objB.sons[0]
|
elif objB.kind in {tyGenericInvocation, tyGenericInst}:
|
||||||
|
objB = objB.sons[0]
|
||||||
else: break
|
else: break
|
||||||
if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB):
|
if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB):
|
||||||
if obj.assignment.isNil:
|
if obj.assignment.isNil:
|
||||||
|
|
@ -1666,7 +1762,11 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
if result.len == 1 and
|
if result.len == 1 and
|
||||||
c.inTypeClass == 0 and # concept bodies should be preserved as a stmt list
|
# concept bodies should be preserved as a stmt list:
|
||||||
|
c.inTypeClass == 0 and
|
||||||
|
# also, don't make life complicated for macros.
|
||||||
|
# they will always expect a proper stmtlist:
|
||||||
|
nfBlockArg notin n.flags and
|
||||||
result.sons[0].kind != nkDefer:
|
result.sons[0].kind != nkDefer:
|
||||||
result = result.sons[0]
|
result = result.sons[0]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,9 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||||
let isCall = ord(n.kind in nkCallKinds+{nkBracketExpr})
|
let isCall = ord(n.kind in nkCallKinds+{nkBracketExpr})
|
||||||
let n = if n[0].kind == nkBracket: n[0] else: n
|
let n = if n[0].kind == nkBracket: n[0] else: n
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
var base = semTypeNode(c, n.lastSon, nil).skipTypes({tyTypeDesc})
|
var t = semTypeNode(c, n.lastSon, nil)
|
||||||
|
if t.kind == tyTypeDesc and tfUnresolved notin t.flags:
|
||||||
|
t = t.base
|
||||||
result = newOrPrevType(kind, prev, c)
|
result = newOrPrevType(kind, prev, c)
|
||||||
var isNilable = false
|
var isNilable = false
|
||||||
# check every except the last is an object:
|
# check every except the last is an object:
|
||||||
|
|
@ -149,7 +151,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||||
tyError, tyObject}:
|
tyError, tyObject}:
|
||||||
message n[i].info, errGenerated, "region needs to be an object type"
|
message n[i].info, errGenerated, "region needs to be an object type"
|
||||||
addSonSkipIntLit(result, region)
|
addSonSkipIntLit(result, region)
|
||||||
addSonSkipIntLit(result, base)
|
addSonSkipIntLit(result, t)
|
||||||
#if not isNilable: result.flags.incl tfNotNil
|
#if not isNilable: result.flags.incl tfNotNil
|
||||||
|
|
||||||
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
||||||
|
|
@ -891,13 +893,20 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
let lifted = liftingWalk(paramType.sons[i])
|
let lifted = liftingWalk(paramType.sons[i])
|
||||||
if lifted != nil: paramType.sons[i] = lifted
|
if lifted != nil: paramType.sons[i] = lifted
|
||||||
|
|
||||||
if paramType.base.lastSon.kind == tyUserTypeClass:
|
let body = paramType.base
|
||||||
|
if body.kind == tyForward:
|
||||||
|
# this may happen for proc type appearing in a type section
|
||||||
|
# before one of its param types
|
||||||
|
return
|
||||||
|
|
||||||
|
if body.lastSon.kind == tyUserTypeClass:
|
||||||
let expanded = instGenericContainer(c, info, paramType,
|
let expanded = instGenericContainer(c, info, paramType,
|
||||||
allowMetaTypes = true)
|
allowMetaTypes = true)
|
||||||
result = liftingWalk(expanded, true)
|
result = liftingWalk(expanded, true)
|
||||||
|
|
||||||
of tyUserTypeClasses, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
of tyUserTypeClasses, tyBuiltInTypeClass, tyCompositeTypeClass,
|
||||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), true))
|
tyAnd, tyOr, tyNot:
|
||||||
|
result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), false))
|
||||||
|
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
markUsed(info, paramType.sym, c.graph.usageSym)
|
markUsed(info, paramType.sym, c.graph.usageSym)
|
||||||
|
|
@ -1065,6 +1074,7 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
|
||||||
|
|
||||||
proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
|
proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
|
||||||
result = semTypeNode(c, n, nil)
|
result = semTypeNode(c, n, nil)
|
||||||
|
n.typ = makeTypeDesc(c, result)
|
||||||
|
|
||||||
proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) =
|
proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) =
|
||||||
var
|
var
|
||||||
|
|
@ -1574,10 +1584,24 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
# type for each generic param. the index
|
# type for each generic param. the index
|
||||||
# of the parameter will be stored in the
|
# of the parameter will be stored in the
|
||||||
# attached symbol.
|
# attached symbol.
|
||||||
|
var paramName = a.sons[j]
|
||||||
|
var covarianceFlag = tfUnresolved
|
||||||
|
|
||||||
|
if paramName.safeLen == 2:
|
||||||
|
if not nimEnableCovariance or paramName[0].ident.s == "in":
|
||||||
|
if father == nil or sfImportc notin father.sym.flags:
|
||||||
|
localError(paramName.info, errInOutFlagNotExtern, paramName[0].ident.s)
|
||||||
|
covarianceFlag = if paramName[0].ident.s == "in": tfContravariant
|
||||||
|
else: tfCovariant
|
||||||
|
if father != nil: father.flags.incl tfCovariant
|
||||||
|
paramName = paramName[1]
|
||||||
|
|
||||||
var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
|
var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
|
||||||
newSymG(skGenericParam, a.sons[j], c).linkTo(finalType)
|
newSymG(skGenericParam, paramName, c).linkTo(finalType)
|
||||||
else:
|
else:
|
||||||
newSymG(skType, a.sons[j], c).linkTo(finalType)
|
newSymG(skType, paramName, c).linkTo(finalType)
|
||||||
|
|
||||||
|
if covarianceFlag != tfUnresolved: s.typ.flags.incl(covarianceFlag)
|
||||||
if def.kind != nkEmpty: s.ast = def
|
if def.kind != nkEmpty: s.ast = def
|
||||||
if father != nil: addSonSkipIntLit(father, s.typ)
|
if father != nil: addSonSkipIntLit(father, s.typ)
|
||||||
s.position = result.len
|
s.position = result.len
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@
|
||||||
|
|
||||||
# This module does the instantiation of generic types.
|
# This module does the instantiation of generic types.
|
||||||
|
|
||||||
import ast, astalgo, msgs, types, magicsys, semdata, renderer
|
import ast, astalgo, msgs, types, magicsys, semdata, renderer, options
|
||||||
|
|
||||||
const
|
const
|
||||||
tfInstClearedFlags = {tfHasMeta}
|
tfInstClearedFlags = {tfHasMeta, tfUnresolved}
|
||||||
|
|
||||||
proc checkPartialConstructedType(info: TLineInfo, t: PType) =
|
proc checkPartialConstructedType(info: TLineInfo, t: PType) =
|
||||||
if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
|
if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
|
||||||
|
|
@ -50,6 +50,9 @@ proc searchInstTypes*(key: PType): PType =
|
||||||
# types such as Channel[empty]. Why?
|
# types such as Channel[empty]. Why?
|
||||||
# See the notes for PActor in handleGenericInvocation
|
# See the notes for PActor in handleGenericInvocation
|
||||||
return
|
return
|
||||||
|
if not sameFlags(inst, key):
|
||||||
|
continue
|
||||||
|
|
||||||
block matchType:
|
block matchType:
|
||||||
for j in 1 .. high(key.sons):
|
for j in 1 .. high(key.sons):
|
||||||
# XXX sameType is not really correct for nested generics?
|
# XXX sameType is not really correct for nested generics?
|
||||||
|
|
@ -231,6 +234,7 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
||||||
proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
|
proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
|
||||||
# XXX: relying on allowMetaTypes is a kludge
|
# XXX: relying on allowMetaTypes is a kludge
|
||||||
result = copyType(t, t.owner, cl.allowMetaTypes)
|
result = copyType(t, t.owner, cl.allowMetaTypes)
|
||||||
|
if cl.allowMetaTypes: return
|
||||||
result.flags.incl tfFromGeneric
|
result.flags.incl tfFromGeneric
|
||||||
if not (t.kind in tyMetaTypes or
|
if not (t.kind in tyMetaTypes or
|
||||||
(t.kind == tyStatic and t.n == nil)):
|
(t.kind == tyStatic and t.n == nil)):
|
||||||
|
|
@ -247,10 +251,11 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = PType(idTableGet(cl.localCache, t))
|
result = PType(idTableGet(cl.localCache, t))
|
||||||
else:
|
else:
|
||||||
result = searchInstTypes(t)
|
result = searchInstTypes(t)
|
||||||
|
|
||||||
if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
|
if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
var x = t.sons[i]
|
var x = t.sons[i]
|
||||||
if x.kind == tyGenericParam:
|
if x.kind in {tyGenericParam}:
|
||||||
x = lookupTypeVar(cl, x)
|
x = lookupTypeVar(cl, x)
|
||||||
if x != nil:
|
if x != nil:
|
||||||
if header == t: header = instCopyType(cl, t)
|
if header == t: header = instCopyType(cl, t)
|
||||||
|
|
@ -307,6 +312,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
rawAddSon(result, newbody)
|
rawAddSon(result, newbody)
|
||||||
checkPartialConstructedType(cl.info, newbody)
|
checkPartialConstructedType(cl.info, newbody)
|
||||||
let dc = newbody.deepCopy
|
let dc = newbody.deepCopy
|
||||||
|
if cl.allowMetaTypes == false:
|
||||||
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
|
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
|
||||||
# 'deepCopy' needs to be instantiated for
|
# 'deepCopy' needs to be instantiated for
|
||||||
# generics *when the type is constructed*:
|
# generics *when the type is constructed*:
|
||||||
|
|
@ -526,6 +532,14 @@ proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||||
result = replaceTypeVarsT(cl, t)
|
result = replaceTypeVarsT(cl, t)
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
||||||
|
proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||||
|
t: PType): PType =
|
||||||
|
var cl = initTypeVars(p, pt, info, nil)
|
||||||
|
cl.allowMetaTypes = true
|
||||||
|
pushInfoContext(info)
|
||||||
|
result = replaceTypeVarsT(cl, t)
|
||||||
|
popInfoContext()
|
||||||
|
|
||||||
template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
|
template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
|
||||||
t: PType): untyped =
|
t: PType): untyped =
|
||||||
generateTypeInstance(p, pt, arg.info, t)
|
generateTypeInstance(p, pt, arg.info, t)
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||||
else:
|
else:
|
||||||
c.hashSym(t.sym)
|
c.hashSym(t.sym)
|
||||||
return
|
return
|
||||||
of tyAlias, tyGenericInst:
|
of tyAlias, tyGenericInst, tyUserTypeClasses:
|
||||||
c.hashType t.lastSon, flags
|
c.hashType t.lastSon, flags
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
|
@ -201,16 +201,6 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||||
of tyRef, tyPtr, tyGenericBody, tyVar:
|
of tyRef, tyPtr, tyGenericBody, tyVar:
|
||||||
c.hashType t.lastSon, flags
|
c.hashType t.lastSon, flags
|
||||||
if tfVarIsPtr in t.flags: c &= ".varisptr"
|
if tfVarIsPtr in t.flags: c &= ".varisptr"
|
||||||
of tyUserTypeClass:
|
|
||||||
if t.sym != nil and t.sym.owner != nil:
|
|
||||||
c &= t.sym.owner.name.s
|
|
||||||
else:
|
|
||||||
c &= "unknown typeclass"
|
|
||||||
of tyUserTypeClassInst:
|
|
||||||
let body = t.sons[0]
|
|
||||||
c.hashSym body.sym
|
|
||||||
for i in countup(1, sonsLen(t) - 2):
|
|
||||||
c.hashType t.sons[i], flags
|
|
||||||
of tyFromExpr, tyFieldAccessor:
|
of tyFromExpr, tyFieldAccessor:
|
||||||
c.hashTree(t.n)
|
c.hashTree(t.n)
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,12 @@ type
|
||||||
mutabilityProblem*: uint8 # tyVar mismatch
|
mutabilityProblem*: uint8 # tyVar mismatch
|
||||||
inheritancePenalty: int # to prefer closest father object type
|
inheritancePenalty: int # to prefer closest father object type
|
||||||
|
|
||||||
|
TTypeRelFlag* = enum
|
||||||
|
trDontBind
|
||||||
|
trNoCovariance
|
||||||
|
|
||||||
|
TTypeRelFlags* = set[TTypeRelFlag]
|
||||||
|
|
||||||
TTypeRelation* = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
isNone, isConvertible,
|
isNone, isConvertible,
|
||||||
isIntConv,
|
isIntConv,
|
||||||
|
|
@ -177,6 +183,13 @@ proc sumGeneric(t: PType): int =
|
||||||
tyOpenArray, tyVarargs, tySet, tyRange, tySequence, tyGenericBody:
|
tyOpenArray, tyVarargs, tySet, tyRange, tySequence, tyGenericBody:
|
||||||
t = t.lastSon
|
t = t.lastSon
|
||||||
inc result
|
inc result
|
||||||
|
of tyOr:
|
||||||
|
var maxBranch = 0
|
||||||
|
for branch in t.sons:
|
||||||
|
let branchSum = branch.sumGeneric
|
||||||
|
if branchSum > maxBranch: maxBranch = branchSum
|
||||||
|
inc result, maxBranch + 1
|
||||||
|
break
|
||||||
of tyVar:
|
of tyVar:
|
||||||
t = t.sons[0]
|
t = t.sons[0]
|
||||||
inc result
|
inc result
|
||||||
|
|
@ -185,8 +198,8 @@ proc sumGeneric(t: PType): int =
|
||||||
t = t.lastSon
|
t = t.lastSon
|
||||||
if t.kind == tyEmpty: break
|
if t.kind == tyEmpty: break
|
||||||
inc result
|
inc result
|
||||||
of tyGenericInvocation, tyTuple, tyProc:
|
of tyGenericInvocation, tyTuple, tyProc, tyAnd:
|
||||||
result += ord(t.kind == tyGenericInvocation)
|
result += ord(t.kind in {tyGenericInvocation, tyAnd})
|
||||||
for i in 0 .. <t.len:
|
for i in 0 .. <t.len:
|
||||||
if t.sons[i] != nil:
|
if t.sons[i] != nil:
|
||||||
result += t.sons[i].sumGeneric
|
result += t.sons[i].sumGeneric
|
||||||
|
|
@ -228,6 +241,15 @@ proc complexDisambiguation(a, b: PType): int =
|
||||||
for i in 1 .. <b.len: y += b.sons[i].sumGeneric
|
for i in 1 .. <b.len: y += b.sons[i].sumGeneric
|
||||||
result = x - y
|
result = x - y
|
||||||
|
|
||||||
|
proc writeMatches*(c: TCandidate) =
|
||||||
|
echo "Candidate '", c.calleeSym.name.s, "' at ", c.calleeSym.info
|
||||||
|
echo " exact matches: ", c.exactMatches
|
||||||
|
echo " generic matches: ", c.genericMatches
|
||||||
|
echo " subtype matches: ", c.subtypeMatches
|
||||||
|
echo " intconv matches: ", c.intConvMatches
|
||||||
|
echo " conv matches: ", c.convMatches
|
||||||
|
echo " inheritance: ", c.inheritancePenalty
|
||||||
|
|
||||||
proc cmpCandidates*(a, b: TCandidate): int =
|
proc cmpCandidates*(a, b: TCandidate): int =
|
||||||
result = a.exactMatches - b.exactMatches
|
result = a.exactMatches - b.exactMatches
|
||||||
if result != 0: return
|
if result != 0: return
|
||||||
|
|
@ -248,14 +270,6 @@ proc cmpCandidates*(a, b: TCandidate): int =
|
||||||
if result != 0: return
|
if result != 0: return
|
||||||
result = a.calleeScope - b.calleeScope
|
result = a.calleeScope - b.calleeScope
|
||||||
|
|
||||||
proc writeMatches*(c: TCandidate) =
|
|
||||||
writeLine(stdout, "exact matches: " & $c.exactMatches)
|
|
||||||
writeLine(stdout, "generic matches: " & $c.genericMatches)
|
|
||||||
writeLine(stdout, "subtype matches: " & $c.subtypeMatches)
|
|
||||||
writeLine(stdout, "intconv matches: " & $c.intConvMatches)
|
|
||||||
writeLine(stdout, "conv matches: " & $c.convMatches)
|
|
||||||
writeLine(stdout, "inheritance: " & $c.inheritancePenalty)
|
|
||||||
|
|
||||||
proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
|
proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
|
||||||
if arg.kind in nkSymChoices:
|
if arg.kind in nkSymChoices:
|
||||||
result = typeToString(arg[0].typ, prefer)
|
result = typeToString(arg[0].typ, prefer)
|
||||||
|
|
@ -288,7 +302,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
|
||||||
add(result, argTypeToString(arg, prefer))
|
add(result, argTypeToString(arg, prefer))
|
||||||
if i != sonsLen(n) - 1: add(result, ", ")
|
if i != sonsLen(n) - 1: add(result, ", ")
|
||||||
|
|
||||||
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
|
proc typeRel*(c: var TCandidate, f, aOrig: PType,
|
||||||
|
flags: TTypeRelFlags = {}): TTypeRelation
|
||||||
|
|
||||||
proc concreteType(c: TCandidate, t: PType): PType =
|
proc concreteType(c: TCandidate, t: PType): PType =
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyNil:
|
of tyNil:
|
||||||
|
|
@ -739,7 +755,7 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode,
|
||||||
allowMetaTypes = allowUnresolved)
|
allowMetaTypes = allowUnresolved)
|
||||||
result = c.c.semExpr(c.c, instantiated)
|
result = c.c.semExpr(c.c, instantiated)
|
||||||
|
|
||||||
proc inferStaticParam*(lhs: PNode, rhs: BiggestInt): PType =
|
proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool =
|
||||||
# This is a simple integer arithimetic equation solver,
|
# This is a simple integer arithimetic equation solver,
|
||||||
# capable of deriving the value of a static parameter in
|
# capable of deriving the value of a static parameter in
|
||||||
# expressions such as (N + 5) / 2 = rhs
|
# expressions such as (N + 5) / 2 = rhs
|
||||||
|
|
@ -754,64 +770,69 @@ proc inferStaticParam*(lhs: PNode, rhs: BiggestInt): PType =
|
||||||
#
|
#
|
||||||
# Result:
|
# Result:
|
||||||
#
|
#
|
||||||
# The proc will return the inferred static type with the `n` field
|
# The proc will return true if the static types was successfully
|
||||||
# populated with the inferred value.
|
# inferred. The result will be bound to the original static type
|
||||||
#
|
# in the TCandidate.
|
||||||
# `nil` will be returned if the inference was not possible
|
|
||||||
#
|
#
|
||||||
if lhs.kind in nkCallKinds and lhs[0].kind == nkSym:
|
if lhs.kind in nkCallKinds and lhs[0].kind == nkSym:
|
||||||
case lhs[0].sym.magic
|
case lhs[0].sym.magic
|
||||||
of mUnaryLt:
|
of mUnaryLt:
|
||||||
return inferStaticParam(lhs[1], rhs + 1)
|
return inferStaticParam(c, lhs[1], rhs + 1)
|
||||||
|
|
||||||
of mAddI, mAddU, mInc, mSucc:
|
of mAddI, mAddU, mInc, mSucc:
|
||||||
if lhs[1].kind == nkIntLit:
|
if lhs[1].kind == nkIntLit:
|
||||||
return inferStaticParam(lhs[2], rhs - lhs[1].intVal)
|
return inferStaticParam(c, lhs[2], rhs - lhs[1].intVal)
|
||||||
elif lhs[2].kind == nkIntLit:
|
elif lhs[2].kind == nkIntLit:
|
||||||
return inferStaticParam(lhs[1], rhs - lhs[2].intVal)
|
return inferStaticParam(c, lhs[1], rhs - lhs[2].intVal)
|
||||||
|
|
||||||
of mDec, mSubI, mSubU, mPred:
|
of mDec, mSubI, mSubU, mPred:
|
||||||
if lhs[1].kind == nkIntLit:
|
if lhs[1].kind == nkIntLit:
|
||||||
return inferStaticParam(lhs[2], lhs[1].intVal - rhs)
|
return inferStaticParam(c, lhs[2], lhs[1].intVal - rhs)
|
||||||
elif lhs[2].kind == nkIntLit:
|
elif lhs[2].kind == nkIntLit:
|
||||||
return inferStaticParam(lhs[1], rhs + lhs[2].intVal)
|
return inferStaticParam(c, lhs[1], rhs + lhs[2].intVal)
|
||||||
|
|
||||||
of mMulI, mMulU:
|
of mMulI, mMulU:
|
||||||
if lhs[1].kind == nkIntLit:
|
if lhs[1].kind == nkIntLit:
|
||||||
if rhs mod lhs[1].intVal == 0:
|
if rhs mod lhs[1].intVal == 0:
|
||||||
return inferStaticParam(lhs[2], rhs div lhs[1].intVal)
|
return inferStaticParam(c, lhs[2], rhs div lhs[1].intVal)
|
||||||
elif lhs[2].kind == nkIntLit:
|
elif lhs[2].kind == nkIntLit:
|
||||||
if rhs mod lhs[2].intVal == 0:
|
if rhs mod lhs[2].intVal == 0:
|
||||||
return inferStaticParam(lhs[1], rhs div lhs[2].intVal)
|
return inferStaticParam(c, lhs[1], rhs div lhs[2].intVal)
|
||||||
|
|
||||||
of mDivI, mDivU:
|
of mDivI, mDivU:
|
||||||
if lhs[1].kind == nkIntLit:
|
if lhs[1].kind == nkIntLit:
|
||||||
if lhs[1].intVal mod rhs == 0:
|
if lhs[1].intVal mod rhs == 0:
|
||||||
return inferStaticParam(lhs[2], lhs[1].intVal div rhs)
|
return inferStaticParam(c, lhs[2], lhs[1].intVal div rhs)
|
||||||
elif lhs[2].kind == nkIntLit:
|
elif lhs[2].kind == nkIntLit:
|
||||||
return inferStaticParam(lhs[1], lhs[2].intVal * rhs)
|
return inferStaticParam(c, lhs[1], lhs[2].intVal * rhs)
|
||||||
|
|
||||||
of mShlI:
|
of mShlI:
|
||||||
if lhs[2].kind == nkIntLit:
|
if lhs[2].kind == nkIntLit:
|
||||||
return inferStaticParam(lhs[1], rhs shr lhs[2].intVal)
|
return inferStaticParam(c, lhs[1], rhs shr lhs[2].intVal)
|
||||||
|
|
||||||
of mShrI:
|
of mShrI:
|
||||||
if lhs[2].kind == nkIntLit:
|
if lhs[2].kind == nkIntLit:
|
||||||
return inferStaticParam(lhs[1], rhs shl lhs[2].intVal)
|
return inferStaticParam(c, lhs[1], rhs shl lhs[2].intVal)
|
||||||
|
|
||||||
of mUnaryMinusI:
|
of mUnaryMinusI:
|
||||||
return inferStaticParam(lhs[1], -rhs)
|
return inferStaticParam(c, lhs[1], -rhs)
|
||||||
|
|
||||||
of mUnaryPlusI, mToInt, mToBiggestInt:
|
of mUnaryPlusI, mToInt, mToBiggestInt:
|
||||||
return inferStaticParam(lhs[1], rhs)
|
return inferStaticParam(c, lhs[1], rhs)
|
||||||
|
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and lhs.typ.n == nil:
|
elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and lhs.typ.n == nil:
|
||||||
lhs.typ.n = newIntNode(nkIntLit, rhs)
|
var inferred = newTypeWithSons(c.c, tyStatic, lhs.typ.sons)
|
||||||
return lhs.typ
|
inferred.n = newIntNode(nkIntLit, rhs)
|
||||||
|
put(c, lhs.typ, inferred)
|
||||||
|
if c.c.inTypeClass > 0:
|
||||||
|
# inside concepts, binding is currently done with
|
||||||
|
# direct mutation of the involved types:
|
||||||
|
lhs.typ.n = inferred.n
|
||||||
|
return true
|
||||||
|
|
||||||
return nil
|
return false
|
||||||
|
|
||||||
proc failureToInferStaticParam(n: PNode) =
|
proc failureToInferStaticParam(n: PNode) =
|
||||||
let staticParam = n.findUnresolvedStatic
|
let staticParam = n.findUnresolvedStatic
|
||||||
|
|
@ -825,13 +846,10 @@ proc inferStaticsInRange(c: var TCandidate,
|
||||||
allowUnresolved = true)
|
allowUnresolved = true)
|
||||||
let upperBound = tryResolvingStaticExpr(c, inferred.n[1],
|
let upperBound = tryResolvingStaticExpr(c, inferred.n[1],
|
||||||
allowUnresolved = true)
|
allowUnresolved = true)
|
||||||
|
template doInferStatic(e: PNode, r: BiggestInt) =
|
||||||
template doInferStatic(c: var TCandidate, e: PNode, r: BiggestInt) =
|
|
||||||
var exp = e
|
var exp = e
|
||||||
var rhs = r
|
var rhs = r
|
||||||
var inferred = inferStaticParam(exp, rhs)
|
if inferStaticParam(c, exp, rhs):
|
||||||
if inferred != nil:
|
|
||||||
put(c, inferred, inferred)
|
|
||||||
return isGeneric
|
return isGeneric
|
||||||
else:
|
else:
|
||||||
failureToInferStaticParam exp
|
failureToInferStaticParam exp
|
||||||
|
|
@ -842,15 +860,36 @@ proc inferStaticsInRange(c: var TCandidate,
|
||||||
return isGeneric
|
return isGeneric
|
||||||
else:
|
else:
|
||||||
return isNone
|
return isNone
|
||||||
doInferStatic(c, upperBound, lengthOrd(concrete) + lowerBound.intVal - 1)
|
doInferStatic(upperBound, lengthOrd(concrete) + lowerBound.intVal - 1)
|
||||||
elif upperBound.kind == nkIntLit:
|
elif upperBound.kind == nkIntLit:
|
||||||
doInferStatic(c, lowerBound, upperBound.intVal + 1 - lengthOrd(concrete))
|
doInferStatic(lowerBound, upperBound.intVal + 1 - lengthOrd(concrete))
|
||||||
|
|
||||||
template subtypeCheck() =
|
template subtypeCheck() =
|
||||||
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
||||||
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
|
||||||
|
# this proc is always called for a pair of matching types
|
||||||
|
assert f.kind == a.kind
|
||||||
|
|
||||||
|
template baseTypesCheck(lhs, rhs: PType): bool =
|
||||||
|
lhs.kind notin {tyPtr, tyRef, tyVar} and
|
||||||
|
typeRel(c, lhs, rhs, {trNoCovariance}) == isSubtype
|
||||||
|
|
||||||
|
case f.kind
|
||||||
|
of tyRef, tyPtr:
|
||||||
|
return baseTypesCheck(f.base, a.base)
|
||||||
|
of tyGenericInst:
|
||||||
|
let body = f.base
|
||||||
|
return body == a.base and
|
||||||
|
a.sonsLen == 3 and
|
||||||
|
tfWeakCovariant notin body.sons[0].flags and
|
||||||
|
baseTypesCheck(f.sons[1], a.sons[1])
|
||||||
|
else:
|
||||||
|
return false
|
||||||
|
|
||||||
|
proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
|
flags: TTypeRelFlags = {}): TTypeRelation =
|
||||||
# typeRel can be used to establish various relationships between types:
|
# typeRel can be used to establish various relationships between types:
|
||||||
#
|
#
|
||||||
# 1) When used with concrete types, it will check for type equivalence
|
# 1) When used with concrete types, it will check for type equivalence
|
||||||
|
|
@ -917,6 +956,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
result = isEqual
|
result = isEqual
|
||||||
return
|
return
|
||||||
|
|
||||||
|
template doBind: bool = trDontBind notin flags
|
||||||
|
|
||||||
# var and static arguments match regular modifier-free types
|
# var and static arguments match regular modifier-free types
|
||||||
var a = aOrig.skipTypes({tyStatic, tyVar}).maybeSkipDistinct(c.calleeSym)
|
var a = aOrig.skipTypes({tyStatic, tyVar}).maybeSkipDistinct(c.calleeSym)
|
||||||
# XXX: Theoretically, maybeSkipDistinct could be called before we even
|
# XXX: Theoretically, maybeSkipDistinct could be called before we even
|
||||||
|
|
@ -946,23 +987,28 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
|
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyOr:
|
of tyOr:
|
||||||
|
# XXX: deal with the current dual meaning of tyGenericParam
|
||||||
|
c.typedescMatched = true
|
||||||
# seq[int|string] vs seq[number]
|
# seq[int|string] vs seq[number]
|
||||||
# both int and string must match against number
|
# both int and string must match against number
|
||||||
# but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
|
# but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
for branch in a.sons:
|
for branch in a.sons:
|
||||||
let x = typeRel(c, f, branch, false)
|
let x = typeRel(c, f, branch, flags + {trDontBind})
|
||||||
if x == isNone: return isNone
|
if x == isNone: return isNone
|
||||||
if x < result: result = x
|
if x < result: result = x
|
||||||
|
return
|
||||||
|
|
||||||
of tyAnd:
|
of tyAnd:
|
||||||
|
# XXX: deal with the current dual meaning of tyGenericParam
|
||||||
|
c.typedescMatched = true
|
||||||
# seq[Sortable and Iterable] vs seq[Sortable]
|
# seq[Sortable and Iterable] vs seq[Sortable]
|
||||||
# only one match is enough
|
# only one match is enough
|
||||||
for branch in a.sons:
|
for branch in a.sons:
|
||||||
let x = typeRel(c, f, branch, false)
|
let x = typeRel(c, f, branch, flags + {trDontBind})
|
||||||
if x != isNone:
|
if x != isNone:
|
||||||
return if x >= isGeneric: isGeneric else: x
|
return if x >= isGeneric: isGeneric else: x
|
||||||
result = isNone
|
return isNone
|
||||||
|
|
||||||
of tyNot:
|
of tyNot:
|
||||||
case f.kind
|
case f.kind
|
||||||
|
|
@ -986,7 +1032,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyUserTypeClass, tyUserTypeClassInst:
|
of tyUserTypeClass, tyUserTypeClassInst:
|
||||||
# consider this: 'var g: Node' *within* a concept where 'Node'
|
# consider this: 'var g: Node' *within* a concept where 'Node'
|
||||||
# is a concept too (tgraph)
|
# is a concept too (tgraph)
|
||||||
let x = typeRel(c, a, f, false)
|
let x = typeRel(c, a, f, flags + {trDontBind})
|
||||||
if x >= isGeneric:
|
if x >= isGeneric:
|
||||||
return isGeneric
|
return isGeneric
|
||||||
else: discard
|
else: discard
|
||||||
|
|
@ -1032,7 +1078,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyFloat128: result = handleFloatRange(f, a)
|
of tyFloat128: result = handleFloatRange(f, a)
|
||||||
of tyVar:
|
of tyVar:
|
||||||
if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base)
|
if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base)
|
||||||
else: result = typeRel(c, f.base, aOrig)
|
else: result = typeRel(c, f.base, aOrig, flags + {trNoCovariance})
|
||||||
subtypeCheck()
|
subtypeCheck()
|
||||||
of tyArray:
|
of tyArray:
|
||||||
case a.kind
|
case a.kind
|
||||||
|
|
@ -1046,38 +1092,60 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
fRange = a
|
fRange = a
|
||||||
else:
|
else:
|
||||||
fRange = prev
|
fRange = prev
|
||||||
result = typeRel(c, f.sons[1].skipTypes({tyTypeDesc}),
|
let ff = f.sons[1].skipTypes({tyTypeDesc})
|
||||||
a.sons[1].skipTypes({tyTypeDesc}))
|
let aa = a.sons[1].skipTypes({tyTypeDesc})
|
||||||
if result < isGeneric: return isNone
|
result = typeRel(c, ff, aa)
|
||||||
|
if result < isGeneric:
|
||||||
|
if nimEnableCovariance and
|
||||||
|
trNoCovariance notin flags and
|
||||||
|
ff.kind == aa.kind and
|
||||||
|
isCovariantPtr(c, ff, aa):
|
||||||
|
result = isSubtype
|
||||||
|
else:
|
||||||
|
return isNone
|
||||||
|
|
||||||
if fRange.rangeHasUnresolvedStatic:
|
if fRange.rangeHasUnresolvedStatic:
|
||||||
return inferStaticsInRange(c, fRange, a)
|
return inferStaticsInRange(c, fRange, a)
|
||||||
elif c.c.inTypeClass > 0 and aRange.rangeHasUnresolvedStatic:
|
elif c.c.inTypeClass > 0 and aRange.rangeHasUnresolvedStatic:
|
||||||
return inferStaticsInRange(c, aRange, f)
|
return inferStaticsInRange(c, aRange, f)
|
||||||
elif lengthOrd(fRange) != lengthOrd(a):
|
else:
|
||||||
|
if lengthOrd(fRange) != lengthOrd(aRange):
|
||||||
result = isNone
|
result = isNone
|
||||||
else: discard
|
else: discard
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
# varargs[expr] is special too but handled earlier. So we only need to
|
# varargs[expr] is special too but handled earlier. So we only need to
|
||||||
# handle varargs[stmt] which is the same as varargs[typed]:
|
# handle varargs[stmt] which is the same as varargs[typed]:
|
||||||
if f.kind == tyVarargs:
|
if f.kind == tyVarargs:
|
||||||
|
if tfVarargs in a.flags:
|
||||||
|
return typeRel(c, f.base, a.lastSon)
|
||||||
if tfOldSchoolExprStmt in f.sons[0].flags:
|
if tfOldSchoolExprStmt in f.sons[0].flags:
|
||||||
if f.sons[0].kind == tyExpr: return
|
if f.sons[0].kind == tyExpr: return
|
||||||
elif f.sons[0].kind == tyStmt: return
|
elif f.sons[0].kind == tyStmt: return
|
||||||
|
|
||||||
|
template matchArrayOrSeq(aBase: PType) =
|
||||||
|
let ff = f.base
|
||||||
|
let aa = aBase
|
||||||
|
let baseRel = typeRel(c, ff, aa)
|
||||||
|
if baseRel >= isGeneric:
|
||||||
|
result = isConvertible
|
||||||
|
elif nimEnableCovariance and
|
||||||
|
trNoCovariance notin flags and
|
||||||
|
ff.kind == aa.kind and
|
||||||
|
isCovariantPtr(c, ff, aa):
|
||||||
|
result = isConvertible
|
||||||
|
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = typeRel(c, base(f), base(a))
|
result = typeRel(c, base(f), base(a))
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
of tyArray:
|
of tyArray:
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
|
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
|
||||||
result = isSubtype
|
return isSubtype
|
||||||
elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
|
matchArrayOrSeq(a.sons[1])
|
||||||
result = isConvertible
|
|
||||||
of tySequence:
|
of tySequence:
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
||||||
result = isConvertible
|
return isConvertible
|
||||||
elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
|
matchArrayOrSeq(a.sons[0])
|
||||||
result = isConvertible
|
|
||||||
of tyString:
|
of tyString:
|
||||||
if f.kind == tyOpenArray:
|
if f.kind == tyOpenArray:
|
||||||
if f.sons[0].kind == tyChar:
|
if f.sons[0].kind == tyChar:
|
||||||
|
|
@ -1092,8 +1160,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
||||||
result = isSubtype
|
result = isSubtype
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f.sons[0], a.sons[0])
|
let ff = f.sons[0]
|
||||||
if result < isGeneric: result = isNone
|
let aa = a.sons[0]
|
||||||
|
result = typeRel(c, ff, aa)
|
||||||
|
if result < isGeneric:
|
||||||
|
if nimEnableCovariance and
|
||||||
|
trNoCovariance notin flags and
|
||||||
|
ff.kind == aa.kind and
|
||||||
|
isCovariantPtr(c, ff, aa):
|
||||||
|
result = isSubtype
|
||||||
|
else:
|
||||||
|
result = isNone
|
||||||
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
||||||
result = isNilConversion
|
result = isNilConversion
|
||||||
of tyNil: result = f.allowsNil
|
of tyNil: result = f.allowsNil
|
||||||
|
|
@ -1145,7 +1222,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if a.len < f.len: return isNone
|
if a.len < f.len: return isNone
|
||||||
for i in 0..f.len-2:
|
for i in 0..f.len-2:
|
||||||
if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone
|
if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone
|
||||||
result = typeRel(c, f.lastSon, a.lastSon)
|
result = typeRel(c, f.lastSon, a.lastSon, flags + {trNoCovariance})
|
||||||
subtypeCheck()
|
subtypeCheck()
|
||||||
if result <= isConvertible: result = isNone
|
if result <= isConvertible: result = isNone
|
||||||
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
||||||
|
|
@ -1204,9 +1281,66 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyEmpty, tyVoid:
|
of tyEmpty, tyVoid:
|
||||||
if a.kind == f.kind: result = isEqual
|
if a.kind == f.kind: result = isEqual
|
||||||
|
|
||||||
of tyGenericInst, tyAlias:
|
of tyAlias:
|
||||||
result = typeRel(c, lastSon(f), a)
|
result = typeRel(c, lastSon(f), a)
|
||||||
|
|
||||||
|
of tyGenericInst:
|
||||||
|
var prev = PType(idTableGet(c.bindings, f))
|
||||||
|
var f = if prev == nil: f else: prev
|
||||||
|
|
||||||
|
let roota = a.skipGenericAlias
|
||||||
|
let rootf = f.skipGenericAlias
|
||||||
|
|
||||||
|
var m = c
|
||||||
|
if a.kind == tyGenericInst:
|
||||||
|
if roota.base == rootf.base:
|
||||||
|
let nextFlags = flags + {trNoCovariance}
|
||||||
|
var hasCovariance = false
|
||||||
|
for i in 1 .. rootf.sonsLen-2:
|
||||||
|
let ff = rootf.sons[i]
|
||||||
|
let aa = roota.sons[i]
|
||||||
|
result = typeRel(c, ff, aa, nextFlags)
|
||||||
|
if result notin {isEqual, isGeneric}:
|
||||||
|
if trNoCovariance notin flags and ff.kind == aa.kind:
|
||||||
|
let paramFlags = rootf.base.sons[i-1].flags
|
||||||
|
hasCovariance =
|
||||||
|
if tfCovariant in paramFlags:
|
||||||
|
if tfWeakCovariant in paramFlags:
|
||||||
|
isCovariantPtr(c, ff, aa)
|
||||||
|
else:
|
||||||
|
ff.kind notin {tyRef, tyPtr} and result == isSubtype
|
||||||
|
else:
|
||||||
|
tfContravariant in paramFlags and
|
||||||
|
typeRel(c, aa, ff) == isSubtype
|
||||||
|
if hasCovariance:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return isNone
|
||||||
|
if prev == nil: put(c, f, a)
|
||||||
|
result = isGeneric
|
||||||
|
else:
|
||||||
|
let fKind = rootf.lastSon.kind
|
||||||
|
if fKind in {tyAnd, tyOr}:
|
||||||
|
result = typeRel(c, lastSon(f), a)
|
||||||
|
if result != isNone: put(c, f, a)
|
||||||
|
return
|
||||||
|
|
||||||
|
var aAsObject = roota.lastSon
|
||||||
|
|
||||||
|
if fKind in {tyRef, tyPtr} and aAsObject.kind == fKind:
|
||||||
|
aAsObject = aAsObject.base
|
||||||
|
|
||||||
|
if aAsObject.kind == tyObject:
|
||||||
|
let baseType = aAsObject.base
|
||||||
|
if baseType != nil:
|
||||||
|
c.inheritancePenalty += 1
|
||||||
|
return typeRel(c, f, baseType)
|
||||||
|
|
||||||
|
result = isNone
|
||||||
|
else:
|
||||||
|
result = typeRel(c, lastSon(f), a)
|
||||||
|
if result != isNone: put(c, f, a)
|
||||||
|
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
if a.kind == tyGenericInst and a.sons[0] == f:
|
if a.kind == tyGenericInst and a.sons[0] == f:
|
||||||
|
|
@ -1217,6 +1351,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
|
|
||||||
of tyGenericInvocation:
|
of tyGenericInvocation:
|
||||||
var x = a.skipGenericAlias
|
var x = a.skipGenericAlias
|
||||||
|
# XXX: This is very hacky. It should be moved back into liftTypeParam
|
||||||
|
if x.kind in {tyGenericInst, tyArray} and
|
||||||
|
c.calleeSym != nil and
|
||||||
|
c.calleeSym.kind == skProc:
|
||||||
|
let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f)
|
||||||
|
return typeRel(c, inst, a)
|
||||||
|
|
||||||
var depth = 0
|
var depth = 0
|
||||||
if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
|
if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
|
||||||
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
|
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
|
||||||
|
|
@ -1333,10 +1474,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if f.isResolvedUserTypeClass:
|
if f.isResolvedUserTypeClass:
|
||||||
result = typeRel(c, f.lastSon, a)
|
result = typeRel(c, f.lastSon, a)
|
||||||
else:
|
else:
|
||||||
|
considerPreviousT:
|
||||||
var matched = matchUserTypeClass(c.c, c, f, aOrig)
|
var matched = matchUserTypeClass(c.c, c, f, aOrig)
|
||||||
if matched != nil:
|
if matched != nil:
|
||||||
bindConcreteTypeToUserTypeClass(matched, a)
|
bindConcreteTypeToUserTypeClass(matched, a)
|
||||||
put(c, f, matched)
|
if doBind: put(c, f, matched)
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
@ -1357,6 +1499,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if result != isNone:
|
if result != isNone:
|
||||||
put(c, f, a)
|
put(c, f, a)
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
var x = PType(idTableGet(c.bindings, f))
|
var x = PType(idTableGet(c.bindings, f))
|
||||||
if x == nil:
|
if x == nil:
|
||||||
|
|
@ -1376,16 +1519,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
internalAssert a.sons != nil and a.sons.len > 0
|
internalAssert a.sons != nil and a.sons.len > 0
|
||||||
c.typedescMatched = true
|
c.typedescMatched = true
|
||||||
var aa = a
|
var aa = a
|
||||||
while aa.kind in {tyTypeDesc, tyGenericParam} and
|
while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0:
|
||||||
aa.len > 0:
|
|
||||||
aa = lastSon(aa)
|
aa = lastSon(aa)
|
||||||
|
if aa.kind == tyGenericParam:
|
||||||
|
return isGeneric
|
||||||
result = typeRel(c, f.base, aa)
|
result = typeRel(c, f.base, aa)
|
||||||
if result > isGeneric: result = isGeneric
|
if result > isGeneric: result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
else:
|
else:
|
||||||
if f.sonsLen > 0 and f.sons[0].kind != tyNone:
|
if f.sonsLen > 0 and f.sons[0].kind != tyNone:
|
||||||
result = typeRel(c, f.lastSon, a)
|
result = typeRel(c, f.lastSon, a, flags + {trDontBind})
|
||||||
if doBind and result notin {isNone, isGeneric}:
|
if doBind and result notin {isNone, isGeneric}:
|
||||||
let concrete = concreteType(c, a)
|
let concrete = concreteType(c, a)
|
||||||
if concrete == nil: return isNone
|
if concrete == nil: return isNone
|
||||||
|
|
@ -1590,6 +1734,10 @@ proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
|
||||||
of isEqual: inc(m.exactMatches)
|
of isEqual: inc(m.exactMatches)
|
||||||
of isNone: discard
|
of isNone: discard
|
||||||
|
|
||||||
|
template matchesVoidProc(t: PType): bool =
|
||||||
|
(t.kind == tyProc and t.len == 1 and t.sons[0] == nil) or
|
||||||
|
(t.kind == tyBuiltInTypeClass and t.sons[0].kind == tyProc)
|
||||||
|
|
||||||
proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||||
argSemantized, argOrig: PNode): PNode =
|
argSemantized, argOrig: PNode): PNode =
|
||||||
var
|
var
|
||||||
|
|
@ -1726,6 +1874,14 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
m.fauxMatch = a.kind
|
m.fauxMatch = a.kind
|
||||||
return arg
|
return arg
|
||||||
|
elif a.kind == tyVoid and f.matchesVoidProc and argOrig.kind == nkStmtList:
|
||||||
|
# lift do blocks without params to lambdas
|
||||||
|
let lifted = c.semExpr(c, newProcNode(nkDo, argOrig.info, argOrig), {})
|
||||||
|
if f.kind == tyBuiltInTypeClass:
|
||||||
|
inc m.genericMatches
|
||||||
|
put(m, f, lifted.typ)
|
||||||
|
inc m.convMatches
|
||||||
|
return implicitConv(nkHiddenStdConv, f, lifted, m, c)
|
||||||
result = userConvMatch(c, m, f, a, arg)
|
result = userConvMatch(c, m, f, a, arg)
|
||||||
# check for a base type match, which supports varargs[T] without []
|
# check for a base type match, which supports varargs[T] without []
|
||||||
# constructor in a call:
|
# constructor in a call:
|
||||||
|
|
@ -2008,6 +2164,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
#assert(container == nil)
|
#assert(container == nil)
|
||||||
if container.isNil:
|
if container.isNil:
|
||||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
||||||
|
container.typ.flags.incl tfVarargs
|
||||||
else:
|
else:
|
||||||
incrIndexType(container.typ)
|
incrIndexType(container.typ)
|
||||||
addSon(container, arg)
|
addSon(container, arg)
|
||||||
|
|
@ -2086,6 +2243,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
|
||||||
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
|
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
|
||||||
return nil
|
return nil
|
||||||
var f = dc.typ.sons[col]
|
var f = dc.typ.sons[col]
|
||||||
|
|
||||||
if op == attachedDeepCopy:
|
if op == attachedDeepCopy:
|
||||||
if f.kind in {tyRef, tyPtr}: f = f.lastSon
|
if f.kind in {tyRef, tyPtr}: f = f.lastSon
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -886,6 +886,9 @@ proc isGenericAlias*(t: PType): bool =
|
||||||
proc skipGenericAlias*(t: PType): PType =
|
proc skipGenericAlias*(t: PType): PType =
|
||||||
return if t.isGenericAlias: t.lastSon else: t
|
return if t.isGenericAlias: t.lastSon else: t
|
||||||
|
|
||||||
|
proc sameFlags*(a, b: PType): bool {.inline.} =
|
||||||
|
result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
|
||||||
|
|
||||||
proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
template cycleCheck() =
|
template cycleCheck() =
|
||||||
# believe it or not, the direct check for ``containsOrIncl(c, a, b)``
|
# believe it or not, the direct check for ``containsOrIncl(c, a, b)``
|
||||||
|
|
@ -898,9 +901,6 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
else:
|
else:
|
||||||
if containsOrIncl(c, a, b): return true
|
if containsOrIncl(c, a, b): return true
|
||||||
|
|
||||||
proc sameFlags(a, b: PType): bool {.inline.} =
|
|
||||||
result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
|
|
||||||
|
|
||||||
if x == y: return true
|
if x == y: return true
|
||||||
var a = skipTypes(x, {tyGenericInst, tyAlias})
|
var a = skipTypes(x, {tyGenericInst, tyAlias})
|
||||||
var b = skipTypes(y, {tyGenericInst, tyAlias})
|
var b = skipTypes(y, {tyGenericInst, tyAlias})
|
||||||
|
|
|
||||||
|
|
@ -1606,6 +1606,13 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
|
||||||
n.typ = x.typ
|
n.typ = x.typ
|
||||||
result.node = n
|
result.node = n
|
||||||
|
|
||||||
|
iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
|
||||||
|
let gp = macroSym.ast[genericParamsPos]
|
||||||
|
for i in 0 .. <gp.len:
|
||||||
|
let genericParam = gp[i].sym
|
||||||
|
let posInCall = macroSym.typ.len + i
|
||||||
|
yield (genericParam, call[posInCall])
|
||||||
|
|
||||||
var evalMacroCounter: int
|
var evalMacroCounter: int
|
||||||
|
|
||||||
proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,
|
proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,105 @@ relation is extended to the types ``var``, ``ref``, ``ptr``:
|
||||||
.. XXX nil is a special value!
|
.. XXX nil is a special value!
|
||||||
|
|
||||||
|
|
||||||
|
Covariance
|
||||||
|
----------
|
||||||
|
|
||||||
|
Covariance in Nim can be introduced only though pointer-like types such
|
||||||
|
as ``ptr`` and ``ref``. Sequence, Array and OpenArray types, instantiated
|
||||||
|
with pointer-like types will be considered covariant if and only if they
|
||||||
|
are also immutable. The introduction of a ``var`` modifier or additional
|
||||||
|
``ptr`` or ``ref`` indirections would result in invariant treatment of
|
||||||
|
these types.
|
||||||
|
|
||||||
|
``proc`` types are currently always invariant, but future versions of Nim
|
||||||
|
may relax this rule.
|
||||||
|
|
||||||
|
User-defined generic types may also be covariant with respect to some of
|
||||||
|
their parameters. By default, all generic params are considered invariant,
|
||||||
|
but you may choose the apply the prefix modifier ``in`` to a parameter to
|
||||||
|
make it contravariant or ``out`` to make it covariant:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
type
|
||||||
|
AnnotatedPtr[out T] =
|
||||||
|
metadata: MyTypeInfo
|
||||||
|
p: ref T
|
||||||
|
|
||||||
|
RingBuffer[out T] =
|
||||||
|
startPos: int
|
||||||
|
data: seq[T]
|
||||||
|
|
||||||
|
Action {.importcpp: "std::function<void ('0)>".} [in T] = object
|
||||||
|
|
||||||
|
When the designated generic parameter is used to instantiate a pointer-like
|
||||||
|
type as in the case of `AnnotatedPtr` above, the resulting generic type will
|
||||||
|
also have pointer-like covariance:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
type
|
||||||
|
GuiWidget = object of RootObj
|
||||||
|
Button = object of GuiWidget
|
||||||
|
ComboBox = object of GuiWidget
|
||||||
|
|
||||||
|
var
|
||||||
|
widgetPtr: AnnotatedPtr[GuiWidget]
|
||||||
|
buttonPtr: AnnotatedPtr[Button]
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
proc drawWidget[T](x: AnnotatedPtr[GuiWidget]) = ...
|
||||||
|
|
||||||
|
# you can call procs expecting base types by supplying a derived type
|
||||||
|
drawWidget(buttonPtr)
|
||||||
|
|
||||||
|
# and you can convert more-specific pointer types to more general ones
|
||||||
|
widgetPtr = buttonPtr
|
||||||
|
|
||||||
|
Just like with regular pointers, covariance will be enabled only for immutable
|
||||||
|
values:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
proc makeComboBox[T](x: var AnnotatedPtr[GuiWidget]) =
|
||||||
|
x.p = new(ComboBox)
|
||||||
|
|
||||||
|
makeComboBox(buttonPtr) # Error, AnnotatedPtr[Button] cannot be modified
|
||||||
|
# to point to a ComboBox
|
||||||
|
|
||||||
|
On the other hand, in the `RingBuffer` example above, the designated generic
|
||||||
|
param is used to instantiate the non-pointer ``seq`` type, which means that
|
||||||
|
the resulting generic type will have covariance that mimics an array or
|
||||||
|
sequence (i.e. it will be covariant only when instantiated with ``ptr`` and
|
||||||
|
``ref`` types):
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
type
|
||||||
|
Base = object of RootObj
|
||||||
|
Derived = object of Base
|
||||||
|
|
||||||
|
proc consumeBaseValues(b: RingBuffer[Base]) = ...
|
||||||
|
|
||||||
|
var derivedValues: RingBuffer[Derived]
|
||||||
|
|
||||||
|
consumeBaseValues(derivedValues) # Error, Base and Derived values may differ
|
||||||
|
# in size
|
||||||
|
|
||||||
|
proc consumeBasePointers(b: RingBuffer[ptr Base]) = ...
|
||||||
|
|
||||||
|
var derivedPointers: RingBuffer[ptr Derived]
|
||||||
|
|
||||||
|
consumeBaseValues(derivedPointers) # This is legal
|
||||||
|
|
||||||
|
Please note that Nim will treat the user-defined pointer-like types as
|
||||||
|
proper alternatives to the built-in pointer types. That is, types such
|
||||||
|
as `seq[AnnotatedPtr[T]]` or `RingBuffer[AnnotatedPtr[T]]` will also be
|
||||||
|
considered covariant and you can create new pointer-like types by instantiating
|
||||||
|
other user-defined pointer-like types.
|
||||||
|
|
||||||
|
The contravariant parameters introduced with the ``in`` modifier are currently
|
||||||
|
useful only when interfacing with imported types having such semantics.
|
||||||
|
|
||||||
|
|
||||||
Convertible relation
|
Convertible relation
|
||||||
--------------------
|
--------------------
|
||||||
A type ``a`` is **implicitly** convertible to type ``b`` iff the following
|
A type ``a`` is **implicitly** convertible to type ``b`` iff the following
|
||||||
|
|
@ -119,6 +218,8 @@ algorithm returns true:
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
# XXX range types?
|
# XXX range types?
|
||||||
proc isImplicitlyConvertible(a, b: PType): bool =
|
proc isImplicitlyConvertible(a, b: PType): bool =
|
||||||
|
if isSubtype(a, b) or isCovariant(a, b):
|
||||||
|
return true
|
||||||
case a.kind
|
case a.kind
|
||||||
of int: result = b in {int8, int16, int32, int64, uint, uint8, uint16,
|
of int: result = b in {int8, int16, int32, int64, uint, uint8, uint16,
|
||||||
uint32, uint64, float, float32, float64}
|
uint32, uint64, float, float32, float64}
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,10 @@ type
|
||||||
## Statically typed wrapper around a JavaScript object.
|
## Statically typed wrapper around a JavaScript object.
|
||||||
NotString = concept c
|
NotString = concept c
|
||||||
c isnot string
|
c isnot string
|
||||||
|
js* = JsObject
|
||||||
|
|
||||||
|
var jsarguments* {.importc: "arguments", nodecl}: JsObject
|
||||||
|
## JavaScript's arguments pseudo-variable
|
||||||
|
|
||||||
# New
|
# New
|
||||||
proc newJsObject*: JsObject {. importcpp: "{@}" .}
|
proc newJsObject*: JsObject {. importcpp: "{@}" .}
|
||||||
|
|
@ -93,18 +97,64 @@ proc hasOwnProperty*(x: JsObject, prop: cstring): bool
|
||||||
proc jsTypeOf*(x: JsObject): cstring {. importcpp: "typeof(#)" .}
|
proc jsTypeOf*(x: JsObject): cstring {. importcpp: "typeof(#)" .}
|
||||||
## Returns the name of the JsObject's JavaScript type as a cstring.
|
## Returns the name of the JsObject's JavaScript type as a cstring.
|
||||||
|
|
||||||
|
proc jsnew*(x: auto): JsObject {.importcpp: "(new #)".}
|
||||||
|
## Turns a regular function call into an invocation of the
|
||||||
|
## JavaScript's `new` operator
|
||||||
|
|
||||||
|
proc jsdelete*(x: auto): JsObject {.importcpp: "(delete #)".}
|
||||||
|
## JavaScript's `delete` operator
|
||||||
|
|
||||||
# Conversion to and from JsObject
|
# Conversion to and from JsObject
|
||||||
proc to*(x: JsObject, T: typedesc): T {. importcpp: "(#)" .}
|
proc to*(x: JsObject, T: typedesc): T {. importcpp: "(#)" .}
|
||||||
## Converts a JsObject `x` to type `T`.
|
## Converts a JsObject `x` to type `T`.
|
||||||
|
|
||||||
proc toJs*[T](val: T): JsObject {. importcpp: "(#)" .}
|
proc toJs*[T](val: T): JsObject {. importcpp: "(#)" .}
|
||||||
## Converts a value of any type to type JsObject
|
## Converts a value of any type to type JsObject
|
||||||
|
|
||||||
|
template toJs*(s: string): JsObject = cstring(s).toJs
|
||||||
|
|
||||||
|
macro jsFromAst*(n: untyped): untyped =
|
||||||
|
result = n
|
||||||
|
if n.kind == nnkStmtList:
|
||||||
|
result = newProc(procType = nnkDo, body = result)
|
||||||
|
return quote: toJs(`result`)
|
||||||
|
|
||||||
|
proc `&`*(a, b: cstring): cstring {.importcpp: "(# + #)".}
|
||||||
|
## Concatenation operator for JavaScript strings
|
||||||
|
|
||||||
|
proc `+` *(x, y: JsObject): JsObject {. importcpp: "(# + #)" .}
|
||||||
|
proc `-` *(x, y: JsObject): JsObject {. importcpp: "(# - #)" .}
|
||||||
|
proc `*` *(x, y: JsObject): JsObject {. importcpp: "(# * #)" .}
|
||||||
|
proc `/` *(x, y: JsObject): JsObject {. importcpp: "(# / #)" .}
|
||||||
|
proc `%` *(x, y: JsObject): JsObject {. importcpp: "(# % #)" .}
|
||||||
|
proc `+=` *(x, y: JsObject): JsObject {. importcpp: "(# += #)", discardable .}
|
||||||
|
proc `-=` *(x, y: JsObject): JsObject {. importcpp: "(# -= #)", discardable .}
|
||||||
|
proc `*=` *(x, y: JsObject): JsObject {. importcpp: "(# *= #)", discardable .}
|
||||||
|
proc `/=` *(x, y: JsObject): JsObject {. importcpp: "(# /= #)", discardable .}
|
||||||
|
proc `%=` *(x, y: JsObject): JsObject {. importcpp: "(# %= #)", discardable .}
|
||||||
|
proc `++` *(x: JsObject): JsObject {. importcpp: "(++#)" .}
|
||||||
|
proc `--` *(x: JsObject): JsObject {. importcpp: "(--#)" .}
|
||||||
|
proc `>` *(x, y: JsObject): JsObject {. importcpp: "(# > #)" .}
|
||||||
|
proc `<` *(x, y: JsObject): JsObject {. importcpp: "(# < #)" .}
|
||||||
|
proc `>=` *(x, y: JsObject): JsObject {. importcpp: "(# >= #)" .}
|
||||||
|
proc `<=` *(x, y: JsObject): JsObject {. importcpp: "(# <= #)" .}
|
||||||
|
proc `and`*(x, y: JsObject): JsObject {. importcpp: "(# && #)" .}
|
||||||
|
proc `or` *(x, y: JsObject): JsObject {. importcpp: "(# || #)" .}
|
||||||
|
proc `not`*(x: JsObject): JsObject {. importcpp: "(!#)" .}
|
||||||
|
proc `in` *(x, y: JsObject): JsObject {. importcpp: "(# in #)" .}
|
||||||
|
|
||||||
proc `[]`*(obj: JsObject, field: cstring): JsObject {. importcpp: getImpl .}
|
proc `[]`*(obj: JsObject, field: cstring): JsObject {. importcpp: getImpl .}
|
||||||
## Return the value of a property of name `field` from a JsObject `obj`.
|
## Return the value of a property of name `field` from a JsObject `obj`.
|
||||||
|
|
||||||
|
proc `[]`*(obj: JsObject, field: int): JsObject {. importcpp: getImpl .}
|
||||||
|
## Return the value of a property of name `field` from a JsObject `obj`.
|
||||||
|
|
||||||
proc `[]=`*[T](obj: JsObject, field: cstring, val: T) {. importcpp: setImpl .}
|
proc `[]=`*[T](obj: JsObject, field: cstring, val: T) {. importcpp: setImpl .}
|
||||||
## Set the value of a property of name `field` in a JsObject `obj` to `v`.
|
## Set the value of a property of name `field` in a JsObject `obj` to `v`.
|
||||||
|
|
||||||
|
proc `[]=`*[T](obj: JsObject, field: int, val: T) {. importcpp: setImpl .}
|
||||||
|
## Set the value of a property of name `field` in a JsObject `obj` to `v`.
|
||||||
|
|
||||||
proc `[]`*[K: NotString, V](obj: JsAssoc[K, V], field: K): V
|
proc `[]`*[K: NotString, V](obj: JsAssoc[K, V], field: K): V
|
||||||
{. importcpp: getImpl .}
|
{. importcpp: getImpl .}
|
||||||
## Return the value of a property of name `field` from a JsAssoc `obj`.
|
## Return the value of a property of name `field` from a JsAssoc `obj`.
|
||||||
|
|
@ -171,8 +221,9 @@ macro `.=`*(obj: JsObject, field: static[cstring], value: untyped): untyped =
|
||||||
{. importcpp: `importString`, gensym .}
|
{. importcpp: `importString`, gensym .}
|
||||||
helper(`obj`, `value`)
|
helper(`obj`, `value`)
|
||||||
|
|
||||||
macro `.()`*(obj: JsObject, field: static[cstring],
|
macro `.()`*(obj: JsObject,
|
||||||
args: varargs[JsObject, toJs]): JsObject =
|
field: static[cstring],
|
||||||
|
args: varargs[JsObject, jsFromAst]): JsObject =
|
||||||
## Experimental "method call" operator for type JsObject.
|
## Experimental "method call" operator for type JsObject.
|
||||||
## Takes the name of a method of the JavaScript object (`field`) and calls
|
## Takes the name of a method of the JavaScript object (`field`) and calls
|
||||||
## it with `args` as arguments, returning a JsObject (which may be discarded,
|
## it with `args` as arguments, returning a JsObject (which may be discarded,
|
||||||
|
|
@ -196,9 +247,9 @@ macro `.()`*(obj: JsObject, field: static[cstring],
|
||||||
if not mangledNames.hasKey($field):
|
if not mangledNames.hasKey($field):
|
||||||
mangledNames[$field] = $mangleJsName(field)
|
mangledNames[$field] = $mangleJsName(field)
|
||||||
importString = "#." & mangledNames[$field] & "(@)"
|
importString = "#." & mangledNames[$field] & "(@)"
|
||||||
result = quote do:
|
result = quote:
|
||||||
proc helper(o: JsObject): JsObject
|
proc helper(o: JsObject): JsObject
|
||||||
{. importcpp: `importString`, gensym .}
|
{. importcpp: `importString`, gensym, discardable .}
|
||||||
helper(`obj`)
|
helper(`obj`)
|
||||||
for idx in 0 ..< args.len:
|
for idx in 0 ..< args.len:
|
||||||
let paramName = newIdentNode(!("param" & $idx))
|
let paramName = newIdentNode(!("param" & $idx))
|
||||||
|
|
@ -222,7 +273,8 @@ macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||||
helper(`obj`)
|
helper(`obj`)
|
||||||
|
|
||||||
macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||||
field: static[cstring], value: V): untyped =
|
field: static[cstring],
|
||||||
|
value: V): untyped =
|
||||||
## Experimental dot accessor (set) for type JsAssoc.
|
## Experimental dot accessor (set) for type JsAssoc.
|
||||||
## Sets the value of a property of name `field` in a JsObject `x` to `value`.
|
## Sets the value of a property of name `field` in a JsObject `x` to `value`.
|
||||||
var importString: string
|
var importString: string
|
||||||
|
|
@ -238,7 +290,8 @@ macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||||
helper(`obj`, `value`)
|
helper(`obj`, `value`)
|
||||||
|
|
||||||
macro `.()`*[K: string | cstring, V: proc](obj: JsAssoc[K, V],
|
macro `.()`*[K: string | cstring, V: proc](obj: JsAssoc[K, V],
|
||||||
field: static[cstring], args: varargs[untyped]): auto =
|
field: static[cstring],
|
||||||
|
args: varargs[untyped]): auto =
|
||||||
## Experimental "method call" operator for type JsAssoc.
|
## Experimental "method call" operator for type JsAssoc.
|
||||||
## Takes the name of a method of the JavaScript object (`field`) and calls
|
## Takes the name of a method of the JavaScript object (`field`) and calls
|
||||||
## it with `args` as arguments. Here, everything is typechecked, so you do not
|
## it with `args` as arguments. Here, everything is typechecked, so you do not
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,9 @@ type
|
||||||
cstring* {.magic: Cstring.} ## built-in cstring (*compatible string*) type
|
cstring* {.magic: Cstring.} ## built-in cstring (*compatible string*) type
|
||||||
pointer* {.magic: Pointer.} ## built-in pointer type, use the ``addr``
|
pointer* {.magic: Pointer.} ## built-in pointer type, use the ``addr``
|
||||||
## operator to get a pointer to a variable
|
## operator to get a pointer to a variable
|
||||||
|
|
||||||
|
typedesc* {.magic: TypeDesc.} ## meta type to denote a type description
|
||||||
|
|
||||||
const
|
const
|
||||||
on* = true ## alias for ``true``
|
on* = true ## alias for ``true``
|
||||||
off* = false ## alias for ``false``
|
off* = false ## alias for ``false``
|
||||||
|
|
@ -56,6 +59,15 @@ const
|
||||||
{.push warning[GcMem]: off, warning[Uninit]: off.}
|
{.push warning[GcMem]: off, warning[Uninit]: off.}
|
||||||
{.push hints: off.}
|
{.push hints: off.}
|
||||||
|
|
||||||
|
proc `or` *(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.}
|
||||||
|
## Constructs an `or` meta class
|
||||||
|
|
||||||
|
proc `and` *(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.}
|
||||||
|
## Constructs an `and` meta class
|
||||||
|
|
||||||
|
proc `not` *(a: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.}
|
||||||
|
## Constructs an `not` meta class
|
||||||
|
|
||||||
type
|
type
|
||||||
Ordinal* {.magic: Ordinal.}[T] ## Generic ordinal type. Includes integer,
|
Ordinal* {.magic: Ordinal.}[T] ## Generic ordinal type. Includes integer,
|
||||||
## bool, character, and enumeration types
|
## bool, character, and enumeration types
|
||||||
|
|
@ -66,11 +78,11 @@ type
|
||||||
`ref`* {.magic: Pointer.}[T] ## built-in generic traced pointer type
|
`ref`* {.magic: Pointer.}[T] ## built-in generic traced pointer type
|
||||||
|
|
||||||
`nil` {.magic: "Nil".}
|
`nil` {.magic: "Nil".}
|
||||||
|
|
||||||
expr* {.magic: Expr, deprecated.} ## meta type to denote an expression (for templates)
|
expr* {.magic: Expr, deprecated.} ## meta type to denote an expression (for templates)
|
||||||
## **Deprecated** since version 0.15. Use ``untyped`` instead.
|
## **Deprecated** since version 0.15. Use ``untyped`` instead.
|
||||||
stmt* {.magic: Stmt, deprecated.} ## meta type to denote a statement (for templates)
|
stmt* {.magic: Stmt, deprecated.} ## meta type to denote a statement (for templates)
|
||||||
## **Deprecated** since version 0.15. Use ``typed`` instead.
|
## **Deprecated** since version 0.15. Use ``typed`` instead.
|
||||||
typedesc* {.magic: TypeDesc.} ## meta type to denote a type description
|
|
||||||
void* {.magic: "VoidType".} ## meta type to denote the absence of any type
|
void* {.magic: "VoidType".} ## meta type to denote the absence of any type
|
||||||
auto* {.magic: Expr.} ## meta type for automatic type determination
|
auto* {.magic: Expr.} ## meta type for automatic type determination
|
||||||
any* = distinct auto ## meta type for any supported type
|
any* = distinct auto ## meta type for any supported type
|
||||||
|
|
@ -1332,6 +1344,7 @@ const
|
||||||
hasThreadSupport = compileOption("threads") and not defined(nimscript)
|
hasThreadSupport = compileOption("threads") and not defined(nimscript)
|
||||||
hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
|
hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
|
||||||
taintMode = compileOption("taintmode")
|
taintMode = compileOption("taintmode")
|
||||||
|
nimEnableCovariance* = defined(nimEnableCovariance) # or true
|
||||||
|
|
||||||
when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"):
|
when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"):
|
||||||
# tcc doesn't support TLS
|
# tcc doesn't support TLS
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ discard """
|
||||||
import macros
|
import macros
|
||||||
|
|
||||||
macro mixer(n: typed): untyped =
|
macro mixer(n: typed): untyped =
|
||||||
expectKind(n, nnkCharLit)
|
expectKind(n[0], nnkCharLit)
|
||||||
|
|
||||||
mixer:
|
mixer:
|
||||||
echo "owh"
|
echo "owh"
|
||||||
45
tests/closure/tdonotation.nim
Normal file
45
tests/closure/tdonotation.nim
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
click at 10,20
|
||||||
|
lost focus 1
|
||||||
|
lost focus 2
|
||||||
|
registered handler for UserEvent 1
|
||||||
|
registered handler for UserEvent 2
|
||||||
|
registered handler for UserEvent 3'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import future
|
||||||
|
|
||||||
|
type
|
||||||
|
Button = object
|
||||||
|
Event = object
|
||||||
|
x, y: int
|
||||||
|
|
||||||
|
proc onClick(x: Button, handler: proc(x: Event)) =
|
||||||
|
handler(Event(x: 10, y: 20))
|
||||||
|
|
||||||
|
proc onFocusLost(x: Button, handler: proc()) =
|
||||||
|
handler()
|
||||||
|
|
||||||
|
proc onUserEvent(x: Button, eventName: string, handler: proc) =
|
||||||
|
echo "registered handler for ", eventName
|
||||||
|
|
||||||
|
var b = Button()
|
||||||
|
|
||||||
|
b.onClick do (e: Event):
|
||||||
|
echo "click at ", e.x, ",", e.y
|
||||||
|
|
||||||
|
b.onFocusLost:
|
||||||
|
echo "lost focus 1"
|
||||||
|
|
||||||
|
b.onFocusLost do:
|
||||||
|
echo "lost focus 2"
|
||||||
|
|
||||||
|
b.onUserEvent "UserEvent 1" do:
|
||||||
|
discard
|
||||||
|
|
||||||
|
b.onUserEvent "UserEvent 2":
|
||||||
|
discard
|
||||||
|
|
||||||
|
b.onUserEvent("UserEvent 3", () => echo "event 3")
|
||||||
|
|
||||||
25
tests/concepts/t5642.nim
Normal file
25
tests/concepts/t5642.nim
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
discard """
|
||||||
|
output: 9
|
||||||
|
"""
|
||||||
|
|
||||||
|
type DataTable = concept x
|
||||||
|
x is object
|
||||||
|
for f in fields(x):
|
||||||
|
f is seq
|
||||||
|
|
||||||
|
type Students = object
|
||||||
|
id : seq[int]
|
||||||
|
name : seq[string]
|
||||||
|
age: seq[int]
|
||||||
|
|
||||||
|
proc nrow*(dt: DataTable) : Natural =
|
||||||
|
var totalLen = 0
|
||||||
|
for f in fields(dt):
|
||||||
|
totalLen += f.len
|
||||||
|
return totalLen
|
||||||
|
|
||||||
|
let
|
||||||
|
stud = Students (id : @[1,2,3], name : @["Vas", "Pas", "NafNaf"], age : @[10,16,32])
|
||||||
|
|
||||||
|
echo nrow(stud)
|
||||||
|
|
||||||
53
tests/concepts/tconceptinclosure.nim
Normal file
53
tests/concepts/tconceptinclosure.nim
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
10
|
||||||
|
20
|
||||||
|
int
|
||||||
|
20
|
||||||
|
3
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typetraits
|
||||||
|
|
||||||
|
type
|
||||||
|
FonConcept = concept x
|
||||||
|
x.x is int
|
||||||
|
|
||||||
|
GenericConcept[T] = concept x
|
||||||
|
x.x is T
|
||||||
|
const L = T.name.len
|
||||||
|
|
||||||
|
Implementation = object
|
||||||
|
x: int
|
||||||
|
|
||||||
|
Closure = object
|
||||||
|
f: proc()
|
||||||
|
|
||||||
|
proc f1(x: FonConcept): Closure =
|
||||||
|
result.f = proc () =
|
||||||
|
echo x.x
|
||||||
|
|
||||||
|
proc f2(x: GenericConcept): Closure =
|
||||||
|
result.f = proc () =
|
||||||
|
echo x.x
|
||||||
|
echo GenericConcept.T.name
|
||||||
|
|
||||||
|
proc f3[T](x: GenericConcept[T]): Closure =
|
||||||
|
result.f = proc () =
|
||||||
|
echo x.x
|
||||||
|
echo x.L
|
||||||
|
|
||||||
|
let x = Implementation(x: 10)
|
||||||
|
let y = Implementation(x: 20)
|
||||||
|
|
||||||
|
let a = x.f1
|
||||||
|
let b = x.f2
|
||||||
|
let c = x.f1
|
||||||
|
let d = y.f2
|
||||||
|
let e = y.f3
|
||||||
|
|
||||||
|
a.f()
|
||||||
|
d.f()
|
||||||
|
e.f()
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ echo p2 is AbstractPointOfFloat # true
|
||||||
echo p2.x is float and p2.y is float # true
|
echo p2.x is float and p2.y is float # true
|
||||||
|
|
||||||
# https://github.com/nim-lang/Nim/issues/2018
|
# https://github.com/nim-lang/Nim/issues/2018
|
||||||
type ProtocolFollower = generic
|
type ProtocolFollower = concept
|
||||||
true # not a particularly involved protocol
|
true # not a particularly involved protocol
|
||||||
|
|
||||||
type ImplementorA = object
|
type ImplementorA = object
|
||||||
|
|
|
||||||
42
tests/concepts/trandom_vars.nim
Normal file
42
tests/concepts/trandom_vars.nim
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
discard """
|
||||||
|
output: "11.0"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
# A random number generator
|
||||||
|
Random = object
|
||||||
|
random: proc(): float
|
||||||
|
# A generic typeclass for a random var
|
||||||
|
RandomVar[A] = concept x
|
||||||
|
var rng: Random
|
||||||
|
rng.sample(x) is A
|
||||||
|
# A few concrete instances
|
||||||
|
Uniform = object
|
||||||
|
a, b: float
|
||||||
|
ClosureVar[A] = object
|
||||||
|
f: proc(rng: var Random): A
|
||||||
|
|
||||||
|
# How to sample from various concrete instances
|
||||||
|
proc sample(rng: var Random, u: Uniform): float = u.a + (u.b - u.a) * rng.random()
|
||||||
|
|
||||||
|
proc sample[A](rng: var Random, c: ClosureVar[A]): A = c.f(rng)
|
||||||
|
|
||||||
|
proc uniform(a, b: float): Uniform = Uniform(a: a, b: b)
|
||||||
|
|
||||||
|
# How to lift a function on values to a function on random variables
|
||||||
|
proc map[A, B](x: RandomVar[A], f: proc(a: A): B): ClosureVar[B] =
|
||||||
|
proc inner(rng: var Random): B =
|
||||||
|
f(rng.sample(x))
|
||||||
|
|
||||||
|
result.f = inner
|
||||||
|
|
||||||
|
import future
|
||||||
|
|
||||||
|
proc fakeRandom(): Random =
|
||||||
|
result.random = () => 0.5
|
||||||
|
|
||||||
|
let x = uniform(1, 10).map((x: float) => 2 * x)
|
||||||
|
|
||||||
|
var rng = fakeRandom()
|
||||||
|
|
||||||
|
echo rng.sample(x)
|
||||||
424
tests/cpp/tcovariancerules.nim
Normal file
424
tests/cpp/tcovariancerules.nim
Normal file
|
|
@ -0,0 +1,424 @@
|
||||||
|
discard """
|
||||||
|
cmd: "nim cpp $file"
|
||||||
|
output: '''
|
||||||
|
cat
|
||||||
|
cat
|
||||||
|
dog
|
||||||
|
dog
|
||||||
|
cat
|
||||||
|
cat
|
||||||
|
dog
|
||||||
|
dog X
|
||||||
|
cat
|
||||||
|
cat
|
||||||
|
dog
|
||||||
|
dog
|
||||||
|
dog value
|
||||||
|
cat value
|
||||||
|
dog value
|
||||||
|
cat value
|
||||||
|
dog
|
||||||
|
dog
|
||||||
|
dog value
|
||||||
|
cat value
|
||||||
|
dog 1
|
||||||
|
dog 2
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
template accept(x) =
|
||||||
|
static: assert(compiles(x))
|
||||||
|
|
||||||
|
template reject(x) =
|
||||||
|
static: assert(not compiles(x))
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
macro skipElse(n: untyped): typed = n[0]
|
||||||
|
|
||||||
|
template acceptWithCovariance(x, otherwise): typed =
|
||||||
|
when nimEnableCovariance:
|
||||||
|
x
|
||||||
|
else:
|
||||||
|
reject(x)
|
||||||
|
skipElse(otherwise)
|
||||||
|
|
||||||
|
type
|
||||||
|
Animal = object of RootObj
|
||||||
|
x: string
|
||||||
|
|
||||||
|
Dog = object of Animal
|
||||||
|
y: int
|
||||||
|
|
||||||
|
Cat = object of Animal
|
||||||
|
z: int
|
||||||
|
|
||||||
|
AnimalRef = ref Animal
|
||||||
|
AnimalPtr = ptr Animal
|
||||||
|
|
||||||
|
RefAlias[T] = ref T
|
||||||
|
|
||||||
|
var dog = new(Dog)
|
||||||
|
dog.x = "dog"
|
||||||
|
|
||||||
|
var cat = new(Cat)
|
||||||
|
cat.x = "cat"
|
||||||
|
|
||||||
|
proc makeDerivedRef(x: string): ref Dog =
|
||||||
|
new(result)
|
||||||
|
result.x = x
|
||||||
|
|
||||||
|
proc makeDerived(x: string): Dog =
|
||||||
|
result.x = x
|
||||||
|
|
||||||
|
var covariantSeq = @[makeDerivedRef("dog 1"), makeDerivedRef("dog 2")]
|
||||||
|
var nonCovariantSeq = @[makeDerived("dog 1"), makeDerived("dog 2")]
|
||||||
|
var covariantArr = [makeDerivedRef("dog 1"), makeDerivedRef("dog 2")]
|
||||||
|
var nonCovariantArr = [makeDerived("dog 1"), makeDerived("dog 2")]
|
||||||
|
|
||||||
|
proc wantsCovariantSeq1(s: seq[ref Animal]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc wantsCovariantSeq2(s: seq[AnimalRef]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc wantsCovariantSeq3(s: seq[RefAlias[Animal]]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc wantsCovariantOperArray(s: openarray[ref Animal]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc modifiesCovariantOperArray(s: var openarray[ref Animal]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc modifiesDerivedOperArray(s: var openarray[ref Dog]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc wantsNonCovariantOperArray(s: openarray[Animal]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc wantsCovariantArray(s: array[2, ref Animal]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc wantsNonCovariantSeq(s: seq[Animal]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc wantsNonCovariantArray(s: array[2, Animal]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc modifiesCovariantSeq(s: var seq[ref Animal]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc modifiesCovariantArray(s: var array[2, ref Animal]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc modifiesCovariantSeq(s: ptr seq[ref Animal]) =
|
||||||
|
for a in s[]: echo a.x
|
||||||
|
|
||||||
|
proc modifiesCovariantArray(s: ptr array[2, ref Animal]) =
|
||||||
|
for a in s[]: echo a.x
|
||||||
|
|
||||||
|
proc modifiesDerivedSeq(s: var seq[ref Dog]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc modifiesDerivedArray(s: var array[2, ref Dog]) =
|
||||||
|
for a in s: echo a.x
|
||||||
|
|
||||||
|
proc modifiesDerivedSeq(s: ptr seq[ref Dog]) =
|
||||||
|
for a in s[]: echo a.x
|
||||||
|
|
||||||
|
proc modifiesDerivedArray(s: ptr array[2, ref Dog]) =
|
||||||
|
for a in s[]: echo a.x
|
||||||
|
|
||||||
|
accept:
|
||||||
|
wantsCovariantArray([AnimalRef(dog), AnimalRef(dog)])
|
||||||
|
wantsCovariantArray([AnimalRef(cat), AnimalRef(dog)])
|
||||||
|
wantsCovariantArray([AnimalRef(cat), dog])
|
||||||
|
|
||||||
|
# there is a special rule that detects the base
|
||||||
|
# type of polymorphic arrays
|
||||||
|
wantsCovariantArray([cat, dog])
|
||||||
|
|
||||||
|
acceptWithCovariance:
|
||||||
|
wantsCovariantArray([cat, cat])
|
||||||
|
else:
|
||||||
|
echo "cat"
|
||||||
|
echo "cat"
|
||||||
|
|
||||||
|
var animalRefArray: array[2, ref Animal]
|
||||||
|
|
||||||
|
accept:
|
||||||
|
animalRefArray = [AnimalRef(dog), AnimalRef(dog)]
|
||||||
|
animalRefArray = [AnimalRef(cat), dog]
|
||||||
|
|
||||||
|
acceptWithCovariance:
|
||||||
|
animalRefArray = [dog, dog]
|
||||||
|
wantsCovariantArray animalRefArray
|
||||||
|
else:
|
||||||
|
echo "dog"
|
||||||
|
echo "dog"
|
||||||
|
|
||||||
|
accept:
|
||||||
|
var animal: AnimalRef = dog
|
||||||
|
animal = cat
|
||||||
|
|
||||||
|
var vdog: Dog
|
||||||
|
vdog.x = "dog value"
|
||||||
|
var vcat: Cat
|
||||||
|
vcat.x = "cat value"
|
||||||
|
|
||||||
|
reject:
|
||||||
|
vcat = vdog
|
||||||
|
|
||||||
|
# XXX: The next two cases seem incosistent, perhaps we should change the rules
|
||||||
|
accept:
|
||||||
|
# truncating copies are allowed
|
||||||
|
var vanimal: Animal = vdog
|
||||||
|
vanimal = vdog
|
||||||
|
|
||||||
|
reject:
|
||||||
|
# truncating copies are not allowed with arrays
|
||||||
|
var vanimalArray: array[2, Animal]
|
||||||
|
var vdogArray = [vdog, vdog]
|
||||||
|
vanimalArray = vdogArray
|
||||||
|
|
||||||
|
accept:
|
||||||
|
# a more explicit version of a truncating copy that
|
||||||
|
# should probably always remain allowed
|
||||||
|
var vnextnimal: Animal = Animal(vdog)
|
||||||
|
|
||||||
|
proc wantsRefSeq(x: seq[AnimalRef]) = discard
|
||||||
|
|
||||||
|
accept:
|
||||||
|
wantsCovariantSeq1(@[AnimalRef(dog), AnimalRef(dog)])
|
||||||
|
wantsCovariantSeq1(@[AnimalRef(cat), AnimalRef(dog)])
|
||||||
|
wantsCovariantSeq1(@[AnimalRef(cat), dog])
|
||||||
|
wantsCovariantSeq1(@[cat, dog])
|
||||||
|
|
||||||
|
wantsCovariantSeq2(@[AnimalRef(dog), AnimalRef(dog)])
|
||||||
|
wantsCovariantSeq2(@[AnimalRef(cat), AnimalRef(dog)])
|
||||||
|
wantsCovariantSeq2(@[AnimalRef(cat), dog])
|
||||||
|
wantsCovariantSeq2(@[cat, dog])
|
||||||
|
|
||||||
|
wantsCovariantSeq3(@[AnimalRef(dog), AnimalRef(dog)])
|
||||||
|
wantsCovariantSeq3(@[AnimalRef(cat), AnimalRef(dog)])
|
||||||
|
wantsCovariantSeq3(@[AnimalRef(cat), dog])
|
||||||
|
wantsCovariantSeq3(@[cat, dog])
|
||||||
|
|
||||||
|
wantsCovariantOperArray([cat, dog])
|
||||||
|
|
||||||
|
acceptWithCovariance:
|
||||||
|
wantsCovariantSeq1(@[cat, cat])
|
||||||
|
wantsCovariantSeq2(@[dog, makeDerivedRef("dog X")])
|
||||||
|
# XXX: wantsCovariantSeq3(@[cat, cat])
|
||||||
|
|
||||||
|
wantsCovariantOperArray(@[cat, cat])
|
||||||
|
wantsCovariantOperArray([dog, dog])
|
||||||
|
else:
|
||||||
|
echo "cat"
|
||||||
|
echo "cat"
|
||||||
|
echo "dog"
|
||||||
|
echo "dog X"
|
||||||
|
echo "cat"
|
||||||
|
echo "cat"
|
||||||
|
echo "dog"
|
||||||
|
echo "dog"
|
||||||
|
|
||||||
|
var dogRefs = @[dog, dog]
|
||||||
|
var dogRefsArray = [dog, dog]
|
||||||
|
var animalRefs = @[dog, cat]
|
||||||
|
|
||||||
|
accept:
|
||||||
|
modifiesDerivedArray(dogRefsArray)
|
||||||
|
modifiesDerivedSeq(dogRefs)
|
||||||
|
|
||||||
|
reject modifiesCovariantSeq(dogRefs)
|
||||||
|
reject modifiesCovariantSeq(addr(dogRefs))
|
||||||
|
reject modifiesCovariantSeq(dogRefs.addr)
|
||||||
|
|
||||||
|
reject modifiesCovariantArray([dog, dog])
|
||||||
|
reject modifiesCovariantArray(dogRefsArray)
|
||||||
|
reject modifiesCovariantArray(addr(dogRefsArray))
|
||||||
|
reject modifiesCovariantArray(dogRefsArray.addr)
|
||||||
|
|
||||||
|
var dogValues = @[vdog, vdog]
|
||||||
|
var dogValuesArray = [vdog, vdog]
|
||||||
|
var animalValues = @[Animal(vdog), Animal(vcat)]
|
||||||
|
var animalValuesArray = [Animal(vdog), Animal(vcat)]
|
||||||
|
|
||||||
|
wantsNonCovariantSeq animalValues
|
||||||
|
wantsNonCovariantArray animalValuesArray
|
||||||
|
|
||||||
|
reject wantsNonCovariantSeq(dogRefs)
|
||||||
|
reject modifiesCovariantOperArray(dogRefs)
|
||||||
|
reject wantsNonCovariantArray(dogRefsArray)
|
||||||
|
reject wantsNonCovariantSeq(dogValues)
|
||||||
|
reject wantsNonCovariantArray(dogValuesArray)
|
||||||
|
reject modifiesValueArray()
|
||||||
|
|
||||||
|
modifiesDerivedOperArray dogRefs
|
||||||
|
reject modifiesDerivedOperArray(dogValues)
|
||||||
|
reject modifiesDerivedOperArray(animalRefs)
|
||||||
|
|
||||||
|
wantsNonCovariantOperArray animalValues
|
||||||
|
reject wantsNonCovariantOperArray(animalRefs)
|
||||||
|
reject wantsNonCovariantOperArray(dogRefs)
|
||||||
|
reject wantsNonCovariantOperArray(dogValues)
|
||||||
|
|
||||||
|
var animalRefSeq: seq[ref Animal]
|
||||||
|
|
||||||
|
accept:
|
||||||
|
animalRefSeq = @[AnimalRef(dog), AnimalRef(dog)]
|
||||||
|
animalRefSeq = @[AnimalRef(cat), dog]
|
||||||
|
|
||||||
|
acceptWithCovariance:
|
||||||
|
animalRefSeq = @[makeDerivedRef("dog 1"), makeDerivedRef("dog 2")]
|
||||||
|
wantsCovariantSeq1(animalRefSeq)
|
||||||
|
else:
|
||||||
|
echo "dog 1"
|
||||||
|
echo "dog 2"
|
||||||
|
|
||||||
|
var pdog: ptr Dog
|
||||||
|
var pcat: ptr Cat
|
||||||
|
|
||||||
|
proc wantsPointer(x: ptr Animal) =
|
||||||
|
discard
|
||||||
|
|
||||||
|
accept:
|
||||||
|
wantsPointer pdog
|
||||||
|
wantsPointer pcat
|
||||||
|
|
||||||
|
# covariance should be disabled when var is involved
|
||||||
|
proc wantsVarPointer1(x: var ptr Animal) =
|
||||||
|
discard
|
||||||
|
|
||||||
|
proc wantsVarPointer2(x: var AnimalPtr) =
|
||||||
|
discard
|
||||||
|
|
||||||
|
reject wantsVarPointer1(pdog)
|
||||||
|
reject wantsVarPointer2(pcat)
|
||||||
|
|
||||||
|
# covariance may be allowed for certain extern types
|
||||||
|
|
||||||
|
{.emit: """
|
||||||
|
template <class T> struct FN { typedef void (*type)(T); };
|
||||||
|
template <class T> struct ARR { typedef T DataType[2]; DataType data; };
|
||||||
|
""".}
|
||||||
|
|
||||||
|
type
|
||||||
|
MyPtr {.importcpp: "'0 *"} [out T] = object
|
||||||
|
|
||||||
|
MySeq {.importcpp: "ARR<'0>", nodecl} [out T] = object
|
||||||
|
data: array[2, T]
|
||||||
|
|
||||||
|
MyAction {.importcpp: "FN<'0>::type"} [in T] = object
|
||||||
|
|
||||||
|
var
|
||||||
|
cAnimal: MyPtr[Animal]
|
||||||
|
cDog: MyPtr[Dog]
|
||||||
|
cCat: MyPtr[Cat]
|
||||||
|
|
||||||
|
cAnimalFn: MyAction[Animal]
|
||||||
|
cCatFn: MyAction[Cat]
|
||||||
|
cDogFn: MyAction[Dog]
|
||||||
|
|
||||||
|
cRefAnimalFn: MyAction[ref Animal]
|
||||||
|
cRefCatFn: MyAction[ref Cat]
|
||||||
|
cRefDogFn: MyAction[ref Dog]
|
||||||
|
|
||||||
|
accept:
|
||||||
|
cAnimal = cDog
|
||||||
|
cAnimal = cCat
|
||||||
|
|
||||||
|
cDogFn = cAnimalFn
|
||||||
|
cCatFn = cAnimalFn
|
||||||
|
|
||||||
|
cRefDogFn = cRefAnimalFn
|
||||||
|
cRefCatFn = cRefAnimalFn
|
||||||
|
|
||||||
|
reject: cDogFn = cRefAnimalFn
|
||||||
|
reject: cCatFn = cRefAnimalFn
|
||||||
|
|
||||||
|
reject: cCat = cDog
|
||||||
|
reject: cAnimalFn = cDogFn
|
||||||
|
reject: cAnimalFn = cCatFn
|
||||||
|
reject: cRefAnimalFn = cRefDogFn
|
||||||
|
reject: cRefAnimalFn = cRefCatFn
|
||||||
|
reject: cRefAnimalFn = cDogFn
|
||||||
|
|
||||||
|
var
|
||||||
|
ptrPtrDog: ptr ptr Dog
|
||||||
|
ptrPtrAnimal: ptr ptr Animal
|
||||||
|
|
||||||
|
reject: ptrPtrDog = ptrPtrAnimal
|
||||||
|
|
||||||
|
# Try to break the rules by introducing some tricky
|
||||||
|
# double indirection types:
|
||||||
|
var
|
||||||
|
cPtrRefAnimal: MyPtr[ref Animal]
|
||||||
|
cPtrRefDog: MyPtr[ref Dog]
|
||||||
|
|
||||||
|
cPtrAliasRefAnimal: MyPtr[RefAlias[Animal]]
|
||||||
|
cPtrAliasRefDog: MyPtr[RefAlias[Dog]]
|
||||||
|
|
||||||
|
cDoublePtrAnimal: MyPtr[MyPtr[Animal]]
|
||||||
|
cDoublePtrDog: MyPtr[MyPtr[Dog]]
|
||||||
|
|
||||||
|
reject: cPtrRefAnimal = cPtrRefDog
|
||||||
|
reject: cDoublePtrAnimal = cDoublePtrDog
|
||||||
|
reject: cRefAliasPtrAnimal = cRefAliasPtrDog
|
||||||
|
reject: cPtrRefAnimal = cRefAliasPtrDog
|
||||||
|
reject: cPtrAliasRefAnimal = cPtrRefDog
|
||||||
|
|
||||||
|
var
|
||||||
|
# Array and Sequence types are covariant only
|
||||||
|
# when instantiated with ref or ptr types:
|
||||||
|
cAnimals: MySeq[ref Animal]
|
||||||
|
cDogs: MySeq[ref Dog]
|
||||||
|
|
||||||
|
# "User-defined" pointer types should be OK too:
|
||||||
|
cAnimalPtrSeq: MySeq[MyPtr[Animal]]
|
||||||
|
cDogPtrSeq: MySeq[MyPtr[Dog]]
|
||||||
|
|
||||||
|
# Value types shouldn't work:
|
||||||
|
cAnimalValues: MySeq[Animal]
|
||||||
|
cDogValues: MySeq[Dog]
|
||||||
|
|
||||||
|
# Double pointer types should not work either:
|
||||||
|
cAnimalRefPtrSeq: MySeq[ref MyPtr[Animal]]
|
||||||
|
cDogRefPtrSeq: MySeq[ref MyPtr[Dog]]
|
||||||
|
cAnimalPtrPtrSeq: MySeq[ptr ptr Animal]
|
||||||
|
cDogPtrPtrSeq: MySeq[ptr ptr Dog]
|
||||||
|
|
||||||
|
accept:
|
||||||
|
cAnimals = cDogs
|
||||||
|
cAnimalPtrSeq = cDogPtrSeq
|
||||||
|
|
||||||
|
reject: cAnimalValues = cDogValues
|
||||||
|
reject: cAnimalRefPtrSeq = cDogRefPtrSeq
|
||||||
|
reject: cAnimalPtrPtrSeq = cDogPtrPtrSeq
|
||||||
|
|
||||||
|
proc wantsAnimalSeq(x: MySeq[Animal]) = discard
|
||||||
|
proc wantsAnimalRefSeq(x: MySeq[ref Animal]) = discard
|
||||||
|
proc modifiesAnimalRefSeq(x: var MySeq[ref Animal]) = discard
|
||||||
|
proc usesAddressOfAnimalRefSeq(x: ptr MySeq[ref Animal]) = discard
|
||||||
|
|
||||||
|
accept wantsAnimalSeq(cAnimalValues)
|
||||||
|
reject wantsAnimalSeq(cDogValues)
|
||||||
|
reject wantsAnimalSeq(cAnimals)
|
||||||
|
|
||||||
|
reject wantsAnimalRefSeq(cAnimalValues)
|
||||||
|
reject wantsAnimalRefSeq(cDogValues)
|
||||||
|
accept wantsAnimalRefSeq(cAnimals)
|
||||||
|
accept wantsAnimalRefSeq(cDogs)
|
||||||
|
|
||||||
|
reject modifiesAnimalRefSeq(cAnimalValues)
|
||||||
|
reject modifiesAnimalRefSeq(cDogValues)
|
||||||
|
accept modifiesAnimalRefSeq(cAnimals)
|
||||||
|
reject modifiesAnimalRefSeq(cDogs)
|
||||||
|
|
||||||
|
reject usesAddressOfAnimalRefSeq(addr cAnimalValues)
|
||||||
|
reject usesAddressOfAnimalRefSeq(addr cDogValues)
|
||||||
|
accept usesAddressOfAnimalRefSeq(addr cAnimals)
|
||||||
|
reject usesAddressOfAnimalRefSeq(addr cDogs)
|
||||||
|
|
||||||
26
tests/errmsgs/tinvalidinout.nim
Normal file
26
tests/errmsgs/tinvalidinout.nim
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
discard """
|
||||||
|
cmd: "nim check $file"
|
||||||
|
errormsg: "The `in` modifier can be used only with imported types"
|
||||||
|
nimout: '''
|
||||||
|
tinvalidinout.nim(14, 7) Error: The `out` modifier can be used only with imported types
|
||||||
|
tinvalidinout.nim(17, 9) Error: The `in` modifier can be used only with imported types
|
||||||
|
tinvalidinout.nim(18, 9) Error: The `in` modifier can be used only with imported types
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
Foo {.header: "foo.h", importcpp.} [in T] = object
|
||||||
|
|
||||||
|
Bar[out X] = object
|
||||||
|
x: int
|
||||||
|
|
||||||
|
proc f1[in T](x: T) = discard
|
||||||
|
proc f2[in T](x: T) {.importc: "f", header: "foo.h"}
|
||||||
|
|
||||||
|
var
|
||||||
|
f: Foo[int]
|
||||||
|
b: Bar[string]
|
||||||
|
|
||||||
|
f1 f
|
||||||
|
f2 b
|
||||||
|
|
||||||
27
tests/generics/t5570.nim
Normal file
27
tests/generics/t5570.nim
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
discard """
|
||||||
|
nimout: "type uint32\ntype uint32"
|
||||||
|
output: "(weight: 17.0, color: 100)"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
type
|
||||||
|
BaseFruit[T] = object of RootObj
|
||||||
|
color: T
|
||||||
|
|
||||||
|
Banana[T] = object of BaseFruit[uint32]
|
||||||
|
weight: T
|
||||||
|
|
||||||
|
macro printTypeName(typ: typed): untyped =
|
||||||
|
echo "type ", getType(typ).repr
|
||||||
|
|
||||||
|
proc setColor[K](self: var BaseFruit[K], c: int) =
|
||||||
|
printTypeName(self.color)
|
||||||
|
self.color = uint32(c)
|
||||||
|
|
||||||
|
var x: Banana[float64]
|
||||||
|
x.weight = 17
|
||||||
|
printTypeName(x.color)
|
||||||
|
x.setColor(100)
|
||||||
|
echo x
|
||||||
|
|
||||||
18
tests/generics/t5602_inheritence.nim
Normal file
18
tests/generics/t5602_inheritence.nim
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
discard """
|
||||||
|
output: "seq[float]\n0"
|
||||||
|
"""
|
||||||
|
|
||||||
|
# https://github.com/nim-lang/Nim/issues/5602
|
||||||
|
|
||||||
|
import typetraits
|
||||||
|
|
||||||
|
type
|
||||||
|
Foo[T] = object of RootObj
|
||||||
|
Bar[T] = object of Foo[seq[T]]
|
||||||
|
|
||||||
|
proc p[T](f: Foo[T]): T =
|
||||||
|
echo T.name
|
||||||
|
|
||||||
|
var s: Bar[float]
|
||||||
|
echo p(s).len # the bug was: p(s) should return seq[float], but returns float instead
|
||||||
|
|
||||||
30
tests/generics/t5643.nim
Normal file
30
tests/generics/t5643.nim
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
type
|
||||||
|
Matrix*[M, N: static[int], T: SomeReal] = object
|
||||||
|
data: ref array[N * M, T]
|
||||||
|
|
||||||
|
Matrix64*[M, N: static[int]] = Matrix[M, N, float64]
|
||||||
|
|
||||||
|
proc zeros64(M,N: static[int]): Matrix64[M,N] =
|
||||||
|
new result.data
|
||||||
|
for i in 0 .. < (M * N):
|
||||||
|
result.data[i] = 0'f64
|
||||||
|
|
||||||
|
proc bar*[M,N: static[int], T](a: Matrix[M,N,T], b: Matrix[M,N,T]) =
|
||||||
|
discard
|
||||||
|
|
||||||
|
let a = zeros64(2,2)
|
||||||
|
bar(a,a)
|
||||||
|
# https://github.com/nim-lang/Nim/issues/5643
|
||||||
|
#
|
||||||
|
# The test case was failing here, because the compiler failed to
|
||||||
|
# detect the two matrix instantiations as the same type.
|
||||||
|
#
|
||||||
|
# The root cause was that the `T` type variable is a different
|
||||||
|
# type after the first Matrix type has been matched.
|
||||||
|
#
|
||||||
|
# Sigmatch was failing to match the second version of `T`, but
|
||||||
|
# due to some complex interplay between tyOr, tyTypeDesc and
|
||||||
|
# tyGenericParam this was allowed to went through. The generic
|
||||||
|
# instantiation of the second matrix was incomplete and the
|
||||||
|
# generic cache lookup failed, producing two separate types.
|
||||||
|
|
||||||
31
tests/generics/t5683.nim
Normal file
31
tests/generics/t5683.nim
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
discard """
|
||||||
|
output: "perm: 22 det: 22"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type Matrix[M,N: static[int]] = array[M, array[N, float]]
|
||||||
|
|
||||||
|
proc det[M,N](a: Matrix[M,N]): int = N*10 + M
|
||||||
|
proc perm[M,N](a: Matrix[M,N]): int = M*10 + N
|
||||||
|
|
||||||
|
const
|
||||||
|
a = [ [1.0, 2.0]
|
||||||
|
, [3.0, 4.0]
|
||||||
|
]
|
||||||
|
|
||||||
|
echo "perm: ", a.perm, " det: ", a.det
|
||||||
|
|
||||||
|
# This tests multiple instantiations of a generic
|
||||||
|
# proc involving static params:
|
||||||
|
type
|
||||||
|
Vector64*[N: static[int]] = ref array[N, float64]
|
||||||
|
Array64[N: static[int]] = array[N, float64]
|
||||||
|
|
||||||
|
proc vector*[N: static[int]](xs: Array64[N]): Vector64[N] =
|
||||||
|
new result
|
||||||
|
for i in 0 .. < N:
|
||||||
|
result[i] = xs[i]
|
||||||
|
|
||||||
|
let v1 = vector([1.0, 2.0, 3.0, 4.0, 5.0])
|
||||||
|
let v2 = vector([1.0, 2.0, 3.0, 4.0, 5.0])
|
||||||
|
let v3 = vector([1.0, 2.0, 3.0, 4.0])
|
||||||
|
|
||||||
68
tests/generics/tbindoncevsbindmany.nim
Normal file
68
tests/generics/tbindoncevsbindmany.nim
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
template accept(x) =
|
||||||
|
static: assert(compiles(x))
|
||||||
|
|
||||||
|
template reject(x) =
|
||||||
|
static: assert(not compiles(x))
|
||||||
|
|
||||||
|
type
|
||||||
|
ObjectWithNumber = concept obj
|
||||||
|
obj.number is int
|
||||||
|
|
||||||
|
Foo[T] = object
|
||||||
|
x: T
|
||||||
|
|
||||||
|
type A = object
|
||||||
|
anumber: int
|
||||||
|
|
||||||
|
type B = object
|
||||||
|
bnumber: int
|
||||||
|
|
||||||
|
proc number(a: A): int = a.anumber
|
||||||
|
proc number(b: B): int = b.bnumber
|
||||||
|
|
||||||
|
proc notDistincConcept1(a: ObjectWithNumber, b: ObjectWithNumber) = discard
|
||||||
|
proc notDistincConcept2(a, b: ObjectWithNumber) = discard
|
||||||
|
proc distinctConcept1(a, b: distinct ObjectWithNumber) = discard
|
||||||
|
proc distinctConcept2(a: ObjectWithNumber, b: distinct ObjectWithNumber) = discard
|
||||||
|
proc distinctConcept3(a: distinct ObjectWithNumber, b: ObjectWithNumber) = discard
|
||||||
|
proc distinctConcept4(a: distinct ObjectWithNumber, b: distinct ObjectWithNumber) = discard
|
||||||
|
|
||||||
|
var a = A(anumber: 5)
|
||||||
|
var b = B(bnumber: 6)
|
||||||
|
|
||||||
|
accept notDistincConcept1(a, a)
|
||||||
|
accept notDistincConcept1(b, b)
|
||||||
|
reject notDistincConcept2(a, b)
|
||||||
|
|
||||||
|
accept notDistincConcept2(a, a)
|
||||||
|
accept notDistincConcept2(b, b)
|
||||||
|
reject notDistincConcept2(a, b)
|
||||||
|
|
||||||
|
accept distinctConcept1(a, b)
|
||||||
|
accept distinctConcept2(a, b)
|
||||||
|
accept distinctConcept3(a, b)
|
||||||
|
accept distinctConcept4(a, b)
|
||||||
|
|
||||||
|
proc nonDistincGeneric1(a: Foo, b: Foo) = discard
|
||||||
|
proc nonDistincGeneric2(a, b: Foo) = discard
|
||||||
|
proc distinctGeneric1(a, b: distinct Foo) = discard
|
||||||
|
proc distinctGeneric2(a: distinct Foo, b: Foo) = discard
|
||||||
|
proc distinctGeneric3(a: Foo, b: distinct Foo) = discard
|
||||||
|
proc distinctGeneric4(a: distinct Foo, b: distinct Foo) = discard
|
||||||
|
|
||||||
|
var f1 = Foo[int](x: 10)
|
||||||
|
var f2 = Foo[string](x: "x")
|
||||||
|
|
||||||
|
accept nonDistincGeneric1(f1, f1)
|
||||||
|
accept nonDistincGeneric1(f2, f2)
|
||||||
|
reject nonDistincGeneric1(f1, f2)
|
||||||
|
|
||||||
|
accept nonDistincGeneric2(f1, f1)
|
||||||
|
accept nonDistincGeneric2(f2, f2)
|
||||||
|
reject nonDistincGeneric2(f1, f2)
|
||||||
|
|
||||||
|
accept distinctGeneric1(f1, f1)
|
||||||
|
accept distinctGeneric2(f1, f1)
|
||||||
|
accept distinctGeneric3(f1, f1)
|
||||||
|
accept distinctGeneric4(f1, f1)
|
||||||
|
|
||||||
78
tests/generics/tfakecovariance.nim
Normal file
78
tests/generics/tfakecovariance.nim
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
template accept(x) =
|
||||||
|
static: assert(compiles(x))
|
||||||
|
|
||||||
|
template reject(x) =
|
||||||
|
static: assert(not compiles(x))
|
||||||
|
|
||||||
|
type
|
||||||
|
BaseObj = object of RootObj
|
||||||
|
DerivedObj = object of BaseObj
|
||||||
|
NonDerivedObj = object
|
||||||
|
|
||||||
|
Container[T] = object
|
||||||
|
|
||||||
|
var base: BaseObj
|
||||||
|
var derived: DerivedObj
|
||||||
|
var nonDerived: NonDerivedObj
|
||||||
|
|
||||||
|
var baseContainer: Container[BaseObj]
|
||||||
|
var derivedContainer: Container[DerivedObj]
|
||||||
|
var nonDerivedContainer: Container[NonDerivedObj]
|
||||||
|
|
||||||
|
# We can fake covariance by listing some specific derived types that
|
||||||
|
# will be allowed with our overload. This is not a real covariance,
|
||||||
|
# because there will be multiple instantiations of the proc, but for
|
||||||
|
# many purposes, it will suffice:
|
||||||
|
|
||||||
|
proc wantsSpecificContainers(c: Container[BaseObj or DerivedObj]) = discard
|
||||||
|
|
||||||
|
accept wantsSpecificContainers(baseContainer)
|
||||||
|
accept wantsSpecificContainers(derivedContainer)
|
||||||
|
|
||||||
|
reject wantsSpecificContainers(nonDerivedContainer)
|
||||||
|
reject wantsSpecificContainers(derived)
|
||||||
|
|
||||||
|
# Now, let's make a more general solution able to catch all derived types:
|
||||||
|
|
||||||
|
type
|
||||||
|
DerivedFrom[T] = concept type D
|
||||||
|
var derived: ref D
|
||||||
|
var base: ref T = derived
|
||||||
|
|
||||||
|
proc wantsDerived(x: DerivedFrom[BaseObj]) = discard
|
||||||
|
|
||||||
|
accept wantsDerived(base)
|
||||||
|
accept wantsDerived(derived)
|
||||||
|
|
||||||
|
reject wantsDerived(nonDerived)
|
||||||
|
reject wantsDerived(baseContainer)
|
||||||
|
|
||||||
|
proc wantsDerivedContainer(c: Container[DerivedFrom[BaseObj]]) = discard
|
||||||
|
|
||||||
|
accept wantsDerivedContainer(baseContainer)
|
||||||
|
accept wantsDerivedContainer(derivedContainer)
|
||||||
|
|
||||||
|
reject wantsDerivedContainer(nonDerivedContainer)
|
||||||
|
|
||||||
|
# The previous solutions were solving the problem for a single overload.
|
||||||
|
# Let's solve it for multiple overloads by introducing a converter:
|
||||||
|
|
||||||
|
type
|
||||||
|
OtherContainer[T] = object
|
||||||
|
|
||||||
|
proc wantsBaseContainer1(c: OtherContainer[BaseObj]) = discard
|
||||||
|
proc wantsBaseContainer2(c: OtherContainer[BaseObj]) = discard
|
||||||
|
|
||||||
|
converter derivedToBase(c: OtherContainer[DerivedFrom[BaseObj]]): OtherContainer[BaseObj] = discard
|
||||||
|
|
||||||
|
block:
|
||||||
|
var baseContainer: OtherContainer[BaseObj]
|
||||||
|
var derivedContainer: OtherContainer[DerivedObj]
|
||||||
|
var nonDerivedContainer: OtherContainer[NonDerivedObj]
|
||||||
|
|
||||||
|
accept wantsBaseContainer1(derivedContainer)
|
||||||
|
reject wantsBaseContainer1(nonDerivedContainer)
|
||||||
|
|
||||||
|
accept wantsBaseContainer2(derivedContainer)
|
||||||
|
reject wantsBaseContainer2(nonDerivedContainer)
|
||||||
|
|
||||||
39
tests/generics/tgenericconst.nim
Normal file
39
tests/generics/tgenericconst.nim
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
@[1, 2]
|
||||||
|
@[3, 4]
|
||||||
|
1
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# https://github.com/nim-lang/Nim/issues/5756
|
||||||
|
|
||||||
|
type
|
||||||
|
Vec*[N : static[int]] = object
|
||||||
|
x: int
|
||||||
|
arr*: array[N, int32]
|
||||||
|
|
||||||
|
Mat*[M,N: static[int]] = object
|
||||||
|
x: int
|
||||||
|
arr*: array[M, Vec[N]]
|
||||||
|
|
||||||
|
proc vec2*(x,y:int32) : Vec[2] =
|
||||||
|
result.arr = [x,y]
|
||||||
|
result.x = 10
|
||||||
|
|
||||||
|
proc mat2*(a,b: Vec[2]): Mat[2,2] =
|
||||||
|
result.arr = [a,b]
|
||||||
|
result.x = 20
|
||||||
|
|
||||||
|
const M = mat2(vec2(1, 2), vec2(3, 4))
|
||||||
|
|
||||||
|
let m1 = M
|
||||||
|
echo @(m1.arr[0].arr)
|
||||||
|
echo @(m1.arr[1].arr)
|
||||||
|
|
||||||
|
proc foo =
|
||||||
|
let m2 = M
|
||||||
|
echo m1.arr[0].arr[0]
|
||||||
|
|
||||||
|
foo()
|
||||||
|
|
||||||
28
tests/generics/tmapping_generic_alias.nim
Normal file
28
tests/generics/tmapping_generic_alias.nim
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
discard """
|
||||||
|
output: '''type(c) = GenAlias[system.int]
|
||||||
|
T = int
|
||||||
|
seq[int]
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typetraits
|
||||||
|
|
||||||
|
type
|
||||||
|
Gen[T] = object
|
||||||
|
x: T
|
||||||
|
|
||||||
|
GenAlias[T] = Gen[seq[T]]
|
||||||
|
|
||||||
|
proc f1[T](x: Gen[T]) =
|
||||||
|
echo T.name
|
||||||
|
|
||||||
|
proc f2[T](x: GenAlias[T]) =
|
||||||
|
echo "type(c) = ", type(x).name
|
||||||
|
echo "T = ", T.name
|
||||||
|
f1 x
|
||||||
|
|
||||||
|
let
|
||||||
|
y = Gen[seq[int]](x: @[10])
|
||||||
|
|
||||||
|
f2 y
|
||||||
|
|
||||||
28
tests/generics/tparam_binding.nim
Normal file
28
tests/generics/tparam_binding.nim
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
discard """
|
||||||
|
errormsg: "got (ref Matrix[2, 2, system.float], ref Matrix[2, 1, system.float])"
|
||||||
|
line: 27
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
Matrix[M,N: static[int]; T: SomeReal] = distinct array[0..(M*N - 1), T]
|
||||||
|
|
||||||
|
let a = new Matrix[2,2,float]
|
||||||
|
let b = new Matrix[2,1,float]
|
||||||
|
|
||||||
|
proc foo[M,N: static[int],T](a: ref Matrix[M, N, T], b: ref Matrix[M, N, T])=
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo(a, a)
|
||||||
|
|
||||||
|
proc bar[M,N: static[int],T](a: ref Matrix[M, M, T], b: ref Matrix[M, N, T])=
|
||||||
|
discard
|
||||||
|
|
||||||
|
bar(a, b)
|
||||||
|
bar(a, a)
|
||||||
|
|
||||||
|
proc baz[M,N: static[int],T](a: ref Matrix[N, N, T], b: ref Matrix[M, N, T])=
|
||||||
|
discard
|
||||||
|
|
||||||
|
baz(a, a)
|
||||||
|
baz(a, b)
|
||||||
|
|
||||||
20
tests/generics/tptrinheritance.nim
Normal file
20
tests/generics/tptrinheritance.nim
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
type NSPasteboardItem* = ptr object
|
||||||
|
type NSPasteboard* = ptr object
|
||||||
|
type NSArrayAbstract = ptr object {.inheritable.}
|
||||||
|
type NSMutableArrayAbstract = ptr object of NSArrayAbstract
|
||||||
|
type NSArray*[T] = ptr object of NSArrayAbstract
|
||||||
|
type NSMutableArray*[T] = ptr object of NSArray[T]
|
||||||
|
|
||||||
|
proc newMutableArrayAbstract*(): NSMutableArrayAbstract = discard
|
||||||
|
|
||||||
|
template newMutableArray*(T: typedesc): NSMutableArray[T] =
|
||||||
|
cast[NSMutableArray[T]](newMutableArrayAbstract())
|
||||||
|
|
||||||
|
proc writeObjects*(p: NSPasteboard, o: NSArray[NSPasteboardItem]) = discard
|
||||||
|
|
||||||
|
let a = newMutableArray NSPasteboardItem
|
||||||
|
var x: NSMutableArray[NSPasteboardItem]
|
||||||
|
var y: NSArray[NSPasteboardItem] = x
|
||||||
|
|
||||||
|
writeObjects(nil, a)
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
output: '''true
|
output: '''
|
||||||
true
|
true
|
||||||
true
|
true
|
||||||
true
|
true
|
||||||
|
|
@ -14,10 +14,18 @@ true
|
||||||
true
|
true
|
||||||
true
|
true
|
||||||
true
|
true
|
||||||
true'''
|
true
|
||||||
|
true
|
||||||
|
3
|
||||||
|
2
|
||||||
|
12
|
||||||
|
Event { name: 'click: test' }
|
||||||
|
Event { name: 'reloaded: test' }
|
||||||
|
Event { name: 'updates: test' }
|
||||||
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import macros, jsffi
|
import macros, jsffi, jsconsole
|
||||||
|
|
||||||
# Tests for JsObject
|
# Tests for JsObject
|
||||||
# Test JsObject []= and []
|
# Test JsObject []= and []
|
||||||
|
|
@ -55,8 +63,8 @@ block:
|
||||||
block:
|
block:
|
||||||
proc test(): bool =
|
proc test(): bool =
|
||||||
let obj = newJsObject()
|
let obj = newJsObject()
|
||||||
obj.`?!$` = proc(x, y, z: int, t: string): string = t & $(x + y + z)
|
obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z)
|
||||||
obj.`?!$`(1, 2, 3, "Result is: ").to(string) == "Result is: 6"
|
obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == "Result is: 6"
|
||||||
echo test()
|
echo test()
|
||||||
|
|
||||||
# Test JsObject []()
|
# Test JsObject []()
|
||||||
|
|
@ -265,3 +273,47 @@ block:
|
||||||
let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever))
|
let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever))
|
||||||
obj.onWhatever(1) == 10
|
obj.onWhatever(1) == 10
|
||||||
echo test()
|
echo test()
|
||||||
|
|
||||||
|
block:
|
||||||
|
{.emit: "function jsProc(n) { return n; }" .}
|
||||||
|
proc jsProc(x: int32): JsObject {.importc: "jsProc".}
|
||||||
|
|
||||||
|
proc test() =
|
||||||
|
var x = jsProc(1)
|
||||||
|
var y = jsProc(2)
|
||||||
|
console.log x + y
|
||||||
|
console.log ++x
|
||||||
|
|
||||||
|
x += jsProc(10)
|
||||||
|
console.log x
|
||||||
|
|
||||||
|
test()
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
block:
|
||||||
|
{.emit:
|
||||||
|
"""
|
||||||
|
function Event(name) { this.name = name; }
|
||||||
|
function on(eventName, eventHandler) { eventHandler(new Event(eventName + ": test")); }
|
||||||
|
var jslib = { "on": on, "subscribe": on };
|
||||||
|
"""
|
||||||
|
.}
|
||||||
|
|
||||||
|
type Event = object
|
||||||
|
name: cstring
|
||||||
|
|
||||||
|
proc on(event: cstring, handler: proc) {.importc: "on".}
|
||||||
|
var jslib {.importc: "jslib", nodecl.}: JsObject
|
||||||
|
|
||||||
|
on("click") do (e: Event):
|
||||||
|
console.log e
|
||||||
|
|
||||||
|
jslib.on "reloaded" do:
|
||||||
|
console.log jsarguments[0]
|
||||||
|
|
||||||
|
# this test case is different from the above, because
|
||||||
|
# `subscribe` is not overloaded in the current scope
|
||||||
|
jslib.subscribe "updates":
|
||||||
|
console.log jsarguments[0]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
|
|
||||||
import macros
|
import macros
|
||||||
|
|
||||||
macro match*(s: cstring|string; pos: int; sections: untyped): untyped =
|
macro match*(s: cstring|string; pos: int; sections: varargs[untyped]): untyped =
|
||||||
for sec in sections.children:
|
for sec in sections:
|
||||||
expectKind sec, nnkOfBranch
|
expectKind sec, nnkOfBranch
|
||||||
expectLen sec, 2
|
expectLen sec, 2
|
||||||
result = newStmtList()
|
result = newStmtList()
|
||||||
|
|
|
||||||
513
tests/parser/tpostexprblocks.nim
Normal file
513
tests/parser/tpostexprblocks.nim
Normal file
|
|
@ -0,0 +1,513 @@
|
||||||
|
discard """
|
||||||
|
nimout: '''
|
||||||
|
StmtList
|
||||||
|
Ident !"foo"
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
Ident !"x"
|
||||||
|
Command
|
||||||
|
Ident !"foo"
|
||||||
|
Ident !"x"
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
StrLit test
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
StrLit test
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Command
|
||||||
|
Ident !"foo"
|
||||||
|
StrLit test
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Command
|
||||||
|
Ident !"foo"
|
||||||
|
StrLit test
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Command
|
||||||
|
Ident !"foo"
|
||||||
|
IntLit 1
|
||||||
|
Par
|
||||||
|
Infix
|
||||||
|
Ident !"+"
|
||||||
|
IntLit 2
|
||||||
|
IntLit 3
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Command
|
||||||
|
Ident !"foo"
|
||||||
|
IntLit 1
|
||||||
|
Par
|
||||||
|
Infix
|
||||||
|
Ident !"+"
|
||||||
|
IntLit 2
|
||||||
|
IntLit 3
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
Do
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
FormalParams
|
||||||
|
Empty
|
||||||
|
IdentDefs
|
||||||
|
Ident !"x"
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
Do
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
FormalParams
|
||||||
|
Empty
|
||||||
|
IdentDefs
|
||||||
|
Ident !"x"
|
||||||
|
Ident !"int"
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
Do
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
FormalParams
|
||||||
|
Ident !"int"
|
||||||
|
IdentDefs
|
||||||
|
Ident !"x"
|
||||||
|
Ident !"int"
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Command
|
||||||
|
Ident !"foo"
|
||||||
|
Ident !"x"
|
||||||
|
Do
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
FormalParams
|
||||||
|
Empty
|
||||||
|
IdentDefs
|
||||||
|
Ident !"y"
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Else
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Else
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Command
|
||||||
|
Ident !"foo"
|
||||||
|
Ident !"x"
|
||||||
|
Do
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
FormalParams
|
||||||
|
Empty
|
||||||
|
IdentDefs
|
||||||
|
Ident !"y"
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Do
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
FormalParams
|
||||||
|
Ident !"int"
|
||||||
|
IdentDefs
|
||||||
|
Ident !"z"
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Do
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
FormalParams
|
||||||
|
Ident !"int"
|
||||||
|
IdentDefs
|
||||||
|
Ident !"w"
|
||||||
|
Ident !"int"
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Else
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
Ident !"x"
|
||||||
|
Call
|
||||||
|
Ident !"bar"
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Else
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
VarSection
|
||||||
|
IdentDefs
|
||||||
|
Ident !"a"
|
||||||
|
Empty
|
||||||
|
Ident !"foo"
|
||||||
|
VarSection
|
||||||
|
IdentDefs
|
||||||
|
Ident !"a"
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
VarSection
|
||||||
|
IdentDefs
|
||||||
|
Ident !"a"
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
Ident !"x"
|
||||||
|
VarSection
|
||||||
|
IdentDefs
|
||||||
|
Ident !"a"
|
||||||
|
Empty
|
||||||
|
Command
|
||||||
|
Ident !"foo"
|
||||||
|
Ident !"x"
|
||||||
|
VarSection
|
||||||
|
IdentDefs
|
||||||
|
Ident !"a"
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
VarSection
|
||||||
|
IdentDefs
|
||||||
|
Ident !"a"
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
VarSection
|
||||||
|
IdentDefs
|
||||||
|
Ident !"a"
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Else
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
VarSection
|
||||||
|
IdentDefs
|
||||||
|
Ident !"a"
|
||||||
|
Empty
|
||||||
|
Command
|
||||||
|
Ident !"foo"
|
||||||
|
Ident !"x"
|
||||||
|
Do
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
FormalParams
|
||||||
|
Empty
|
||||||
|
IdentDefs
|
||||||
|
Ident !"y"
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Else
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Asgn
|
||||||
|
Ident !"a"
|
||||||
|
Ident !"foo"
|
||||||
|
Asgn
|
||||||
|
Ident !"a"
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
Asgn
|
||||||
|
Ident !"a"
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
Ident !"x"
|
||||||
|
Asgn
|
||||||
|
Ident !"a"
|
||||||
|
Command
|
||||||
|
Ident !"foo"
|
||||||
|
Ident !"x"
|
||||||
|
Asgn
|
||||||
|
Ident !"a"
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Asgn
|
||||||
|
Ident !"a"
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Asgn
|
||||||
|
Ident !"a"
|
||||||
|
Call
|
||||||
|
Ident !"foo"
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Else
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Asgn
|
||||||
|
Ident !"a"
|
||||||
|
Command
|
||||||
|
Ident !"foo"
|
||||||
|
Ident !"x"
|
||||||
|
Do
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
FormalParams
|
||||||
|
Empty
|
||||||
|
IdentDefs
|
||||||
|
Ident !"y"
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
Empty
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Else
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
Call
|
||||||
|
DotExpr
|
||||||
|
Ident !"result"
|
||||||
|
Ident !"add"
|
||||||
|
BracketExpr
|
||||||
|
Call
|
||||||
|
Ident !"quote"
|
||||||
|
StmtList
|
||||||
|
DiscardStmt
|
||||||
|
Empty
|
||||||
|
IntLit 0
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
dumpTree:
|
||||||
|
# simple calls
|
||||||
|
foo
|
||||||
|
foo()
|
||||||
|
foo(x)
|
||||||
|
foo x
|
||||||
|
|
||||||
|
foo:
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo do:
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo("test"):
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo("test") do:
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo "test":
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo "test" do:
|
||||||
|
discard
|
||||||
|
|
||||||
|
# more complicated calls
|
||||||
|
foo 1, (2+3):
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo 1, (2+3) do:
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo do (x):
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo do (x: int):
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo do (x: int) -> int:
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo x do (y):
|
||||||
|
discard
|
||||||
|
|
||||||
|
# extra blocks
|
||||||
|
foo:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo do:
|
||||||
|
discard
|
||||||
|
do:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
foo x do (y):
|
||||||
|
discard
|
||||||
|
do (z) -> int:
|
||||||
|
discard
|
||||||
|
do (w: int) -> int:
|
||||||
|
discard
|
||||||
|
do:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
# call with blocks as a param
|
||||||
|
foo(x, bar do:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
)
|
||||||
|
|
||||||
|
# introduce a variable
|
||||||
|
var a = foo
|
||||||
|
var a = foo()
|
||||||
|
var a = foo(x)
|
||||||
|
var a = foo x
|
||||||
|
|
||||||
|
var a = foo:
|
||||||
|
discard
|
||||||
|
|
||||||
|
var a = foo do:
|
||||||
|
discard
|
||||||
|
|
||||||
|
var a = foo do:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
var a = foo x do (y):
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
# assignments
|
||||||
|
a = foo
|
||||||
|
a = foo()
|
||||||
|
a = foo(x)
|
||||||
|
a = foo x
|
||||||
|
|
||||||
|
a = foo:
|
||||||
|
discard
|
||||||
|
|
||||||
|
a = foo do:
|
||||||
|
discard
|
||||||
|
|
||||||
|
a = foo do:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
a = foo x do (y):
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
# some edge cases
|
||||||
|
result.add((quote do:
|
||||||
|
discard
|
||||||
|
)[0])
|
||||||
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
discard """
|
discard """
|
||||||
output: '''{"age": 12, "bio": "\u042F Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"}
|
output: '''{"age": 12, "bio": "\u042F Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"}
|
||||||
true
|
true
|
||||||
true'''
|
true
|
||||||
|
alpha 100
|
||||||
|
omega 200
|
||||||
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import marshal
|
import marshal
|
||||||
|
|
@ -83,3 +86,22 @@ var instance1 = Person(name: "Cletus", age: 12,
|
||||||
echo($$instance1)
|
echo($$instance1)
|
||||||
echo(to[Person]($$instance1).bio == instance1.bio)
|
echo(to[Person]($$instance1).bio == instance1.bio)
|
||||||
echo(to[Person]($$instance1).blob == instance1.blob)
|
echo(to[Person]($$instance1).blob == instance1.blob)
|
||||||
|
|
||||||
|
# bug 5757
|
||||||
|
|
||||||
|
type
|
||||||
|
Something = object
|
||||||
|
x: string
|
||||||
|
y: int
|
||||||
|
|
||||||
|
var data1 = """{"x": "alpha", "y": 100}"""
|
||||||
|
var data2 = """{"x": "omega", "y": 200}"""
|
||||||
|
|
||||||
|
var r = to[Something](data1)
|
||||||
|
|
||||||
|
echo r.x, " ", r.y
|
||||||
|
|
||||||
|
r = to[Something](data2)
|
||||||
|
|
||||||
|
echo r.x, " ", r.y
|
||||||
|
|
||||||
|
|
|
||||||
13
tests/template/tgenerictemplates.nim
Normal file
13
tests/template/tgenerictemplates.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
type
|
||||||
|
SomeObj = object of RootObj
|
||||||
|
|
||||||
|
Foo[T, U] = object
|
||||||
|
x: T
|
||||||
|
y: U
|
||||||
|
|
||||||
|
template someTemplate[T](): tuple[id: int32, obj: T] =
|
||||||
|
var result: tuple[id: int32, obj: T] = (0'i32, T())
|
||||||
|
result
|
||||||
|
|
||||||
|
let ret = someTemplate[SomeObj]()
|
||||||
|
|
||||||
|
|
@ -59,14 +59,13 @@ template wrap(body: typed): untyped =
|
||||||
|
|
||||||
macro makeProc(): typed =
|
macro makeProc(): typed =
|
||||||
# Make a template tree
|
# Make a template tree
|
||||||
result = (quote do:
|
result = quote do:
|
||||||
proc someProc* =
|
proc someProc* =
|
||||||
wrap do:
|
wrap do:
|
||||||
let x = 123
|
let x = 123
|
||||||
# Implicit conversion here
|
# Implicit conversion here
|
||||||
let s: string = x
|
let s: string = x
|
||||||
echo s
|
echo s
|
||||||
)
|
|
||||||
|
|
||||||
makeProc()
|
makeProc()
|
||||||
|
|
||||||
|
|
|
||||||
6
tests/types/t5640.nim
Normal file
6
tests/types/t5640.nim
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
type
|
||||||
|
vecBase[I: static[int]] = distinct array[I, float32]
|
||||||
|
vec2* = vecBase[2]
|
||||||
|
|
||||||
|
var v = vec2([0.0'f32, 0.0'f32])
|
||||||
|
|
||||||
21
tests/types/t5648.nim
Normal file
21
tests/types/t5648.nim
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
discard """
|
||||||
|
output: "ptr Foo"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typetraits
|
||||||
|
|
||||||
|
type Foo = object
|
||||||
|
bar*: int
|
||||||
|
|
||||||
|
proc main() =
|
||||||
|
var f = create(Foo)
|
||||||
|
f.bar = 3
|
||||||
|
echo f.type.name
|
||||||
|
|
||||||
|
discard realloc(f, 0)
|
||||||
|
|
||||||
|
var g = Foo()
|
||||||
|
g.bar = 3
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
||||||
22
tests/types/thard_tyforward.nim
Normal file
22
tests/types/thard_tyforward.nim
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
type
|
||||||
|
Bar[T] = Foo[T, T]
|
||||||
|
Baz[T] = proc (x: Foo[T, T])
|
||||||
|
|
||||||
|
GenericAlias[T] = Foo[T]
|
||||||
|
GenericAlias2[T] = Foo[Baz[T]]
|
||||||
|
|
||||||
|
Concrete1 = Foo[int, float]
|
||||||
|
Concrete2 = proc(x: proc(a: Foo[int, float]))
|
||||||
|
|
||||||
|
Foo[T, U] = object
|
||||||
|
x: T
|
||||||
|
y: U
|
||||||
|
|
||||||
|
var
|
||||||
|
x1: Bar[float]
|
||||||
|
x2: Baz[int]
|
||||||
|
x3: Concrete1
|
||||||
|
x4: Concrete2
|
||||||
|
x5: GenericAlias[int]
|
||||||
|
x6: GenericAlias2[string]
|
||||||
|
|
||||||
|
|
@ -33,13 +33,13 @@ proc getSupporters(self: BountySource): Future[JsonNode] {.async.} =
|
||||||
let response = await self.client.get(apiUrl &
|
let response = await self.client.get(apiUrl &
|
||||||
"/supporters?order=monthly&per_page=200&team_slug=" & self.team)
|
"/supporters?order=monthly&per_page=200&team_slug=" & self.team)
|
||||||
doAssert response.status.startsWith($Http200)
|
doAssert response.status.startsWith($Http200)
|
||||||
return parseJson(response.body)
|
return parseJson(await response.body)
|
||||||
|
|
||||||
proc getGithubUser(username: string): Future[JsonNode] {.async.} =
|
proc getGithubUser(username: string): Future[JsonNode] {.async.} =
|
||||||
let client = newAsyncHttpClient()
|
let client = newAsyncHttpClient()
|
||||||
let response = await client.get(githubApiUrl & "/users/" & username)
|
let response = await client.get(githubApiUrl & "/users/" & username)
|
||||||
if response.status.startsWith($Http200):
|
if response.status.startsWith($Http200):
|
||||||
return parseJson(response.body)
|
return parseJson(await response.body)
|
||||||
else:
|
else:
|
||||||
echo("Could not get Github user: ", username, ". ", response.status)
|
echo("Could not get Github user: ", username, ". ", response.status)
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue