Merge branch 'zahary' into araq2

This commit is contained in:
Andreas Rumpf 2017-05-16 17:32:18 +02:00
commit 503f780676
39 changed files with 1473 additions and 262 deletions

View file

@ -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: 30)
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?
@ -1346,6 +1348,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:

View file

@ -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:

View file

@ -267,7 +267,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)
@ -756,7 +756,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

View file

@ -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")

View file

@ -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

View file

@ -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,7 +366,10 @@ 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)
result = colonOrEquals(p, a) if p.tok.tokType == tkDo:
result = postExprBlocks(p, a)
else:
result = colonOrEquals(p, a)
proc exprList(p: var TParser, endTok: TTokType, result: PNode) = proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
#| exprList = expr ^+ comma #| exprList = expr ^+ comma
@ -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{=} 'elif' expr ':' stmt #| | IND{=} 'of' exprList ':' stmt
#| | IND{=} 'except' exprList ':' stmt #| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'else' ':' stmt )* #| | IND{=} 'except' exprList ':' 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))
# progress guaranteed
while sameInd(p):
var b: PNode
case p.tok.tokType
of tkOf:
b = newNodeP(nkOfBranch, p)
exprList(p, tkColon, b)
of tkElif:
b = newNodeP(nkElifBranch, p)
getTok(p)
optInd(p, b)
addSon(b, parseExpr(p))
of tkExcept:
b = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, b)
of tkElse:
b = newNodeP(nkElse, p)
getTok(p)
else: break
eat(p, tkColon)
addSon(b, parseStmt(p))
addSon(stmtList, b)
if b.kind == nkElse: break
if stmtList.len == 1 and stmtList[0].kind == nkStmtList:
# to keep backwards compatibility (see tests/vm/tstringnil) # to keep backwards compatibility (see tests/vm/tstringnil)
result.add stmtList[0] if stmtList[0].kind == nkStmtList: stmtList = stmtList[0]
else:
result.add stmtList 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):
var nextBlock: PNode
let nextToken = p.tok.tokType
if nextToken == tkDo:
let info = parLineInfo(p)
getTok(p)
nextBlock = parseDoBlock(p, info)
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:
nextBlock = newNodeP(nkExceptBranch, p)
exprList(p, tkColon, nextBlock)
of tkElse:
nextBlock = newNodeP(nkElse, p)
getTok(p)
else: break
eat(p, tkColon)
nextBlock.addSon parseStmt(p)
nextBlock.flags.incl nfBlockArg
result.add nextBlock
if nextBlock.kind == nkElse: break
else:
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?
@ -1893,14 +1899,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 =

View file

@ -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()

View file

@ -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,10 +47,11 @@ 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:
# we cannot check for 'void' in macros ... if n.kind != nkStmtList:
localError(n.info, errExprXHasNoType, # we cannot check for 'void' in macros ...
renderTree(result, {renderNoComments})) localError(n.info, errExprXHasNoType,
result.typ = errorType(c) renderTree(result, {renderNoComments}))
result.typ = errorType(c)
else: else:
if efNoProcvarCheck notin flags: semProcvarCheck(c, result) if efNoProcvarCheck notin flags: semProcvarCheck(c, result)
if result.typ.kind == tyVar: result = newDeref(result) if result.typ.kind == tyVar: result = newDeref(result)
@ -1155,6 +1156,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 +1716,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 +1724,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,
@ -2325,8 +2331,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

View file

@ -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)

View file

@ -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

View file

@ -851,9 +851,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:
assert s.typ != nil if t.kind in {tyProc, tyGenericInst} and not t.isMetaType:
if s.typ.kind != tyAlias: assignType(s.typ, t)
s.typ.id = t.id
elif t.kind in {tyObject, tyEnum, tyDistinct}:
assert s.typ != nil
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)
@ -1063,13 +1066,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
@ -1174,7 +1170,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:
@ -1655,7 +1652,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]

View file

@ -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

View file

@ -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,31 +312,32 @@ 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 dc != nil and sfFromGeneric notin newbody.deepCopy.flags: if cl.allowMetaTypes == false:
# 'deepCopy' needs to be instantiated for if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
# generics *when the type is constructed*: # 'deepCopy' needs to be instantiated for
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info, # generics *when the type is constructed*:
attachedDeepCopy, 1) newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
if bodyIsNew and newbody.typeInst == nil: attachedDeepCopy, 1)
#doassert newbody.typeInst == nil if bodyIsNew and newbody.typeInst == nil:
newbody.typeInst = result #doassert newbody.typeInst == nil
if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst: newbody.typeInst = result
# can come here for tyGenericInst too, see tests/metatype/ttypeor.nim if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst:
# need to look into this issue later # can come here for tyGenericInst too, see tests/metatype/ttypeor.nim
assert newbody.kind in {tyRef, tyPtr} # need to look into this issue later
assert newbody.lastSon.typeInst == nil assert newbody.kind in {tyRef, tyPtr}
newbody.lastSon.typeInst = result assert newbody.lastSon.typeInst == nil
let asgn = newbody.assignment newbody.lastSon.typeInst = result
if asgn != nil and sfFromGeneric notin asgn.flags: let asgn = newbody.assignment
# '=' needs to be instantiated for generics when the type is constructed: if asgn != nil and sfFromGeneric notin asgn.flags:
newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info, # '=' needs to be instantiated for generics when the type is constructed:
attachedAsgn, 1) newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
let methods = skipTypes(bbody, abstractPtrs).methods attachedAsgn, 1)
for col, meth in items(methods): let methods = skipTypes(bbody, abstractPtrs).methods
# we instantiate the known methods belonging to that type, this causes for col, meth in items(methods):
# them to be registered and that's enough, so we 'discard' the result. # we instantiate the known methods belonging to that type, this causes
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info, # them to be registered and that's enough, so we 'discard' the result.
attachedAsgn, col) discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
attachedAsgn, col)
proc eraseVoidParams*(t: PType) = proc eraseVoidParams*(t: PType) =
# transform '(): void' into '()' because old parts of the compiler really # transform '(): void' into '()' because old parts of the compiler really
@ -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)

View file

@ -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:

View file

@ -26,7 +26,7 @@ type
sym*: PSym sym*: PSym
unmatchedVarParam*: int unmatchedVarParam*: int
diagnostics*: seq[string] diagnostics*: seq[string]
CandidateErrors* = seq[CandidateError] CandidateErrors* = seq[CandidateError]
TCandidate* = object TCandidate* = object
@ -68,7 +68,7 @@ type
# future. # future.
mutabilityProblem*: uint8 # tyVar mismatch mutabilityProblem*: uint8 # tyVar mismatch
inheritancePenalty: int # to prefer closest father object type inheritancePenalty: int # to prefer closest father object type
TTypeRelation* = enum # order is important! TTypeRelation* = enum # order is important!
isNone, isConvertible, isNone, isConvertible,
isIntConv, isIntConv,
@ -177,6 +177,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 +192,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 +235,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 +264,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)
@ -639,7 +647,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
makeTypeDesc(c, typ) makeTypeDesc(c, typ)
typeParams.safeAdd((param, typ)) typeParams.safeAdd((param, typ))
addDecl(c, param) addDecl(c, param)
for param in typeClass.n[0]: for param in typeClass.n[0]:
@ -676,7 +684,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
flags: TExprFlags = {} flags: TExprFlags = {}
collectDiagnostics = m.diagnostics != nil or collectDiagnostics = m.diagnostics != nil or
sfExplain in typeClass.sym.flags sfExplain in typeClass.sym.flags
if collectDiagnostics: if collectDiagnostics:
oldWriteHook = writelnHook oldWriteHook = writelnHook
# XXX: we can't write to m.diagnostics directly, because # XXX: we can't write to m.diagnostics directly, because
@ -688,13 +696,13 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
let msg = s.replace("Error:", errorPrefix) let msg = s.replace("Error:", errorPrefix)
if oldWriteHook != nil: oldWriteHook msg if oldWriteHook != nil: oldWriteHook msg
diagnostics.add msg diagnostics.add msg
var checkedBody = c.semTryExpr(c, body.copyTree, flags) var checkedBody = c.semTryExpr(c, body.copyTree, flags)
if collectDiagnostics: if collectDiagnostics:
writelnHook = oldWriteHook writelnHook = oldWriteHook
for msg in diagnostics: m.diagnostics.safeAdd msg for msg in diagnostics: m.diagnostics.safeAdd msg
if checkedBody == nil: return nil if checkedBody == nil: return nil
# The inferrable type params have been identified during the semTryExpr above. # The inferrable type params have been identified during the semTryExpr above.
@ -739,14 +747,14 @@ 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
# #
# Preconditions: # Preconditions:
# #
# * The input of this proc must be semantized # * The input of this proc must be semantized
# - all templates should be expanded # - all templates should be expanded
# - aby constant folding possible should already be performed # - aby constant folding possible should already be performed
# #
@ -754,64 +762,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)
return nil 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 false
proc failureToInferStaticParam(n: PNode) = proc failureToInferStaticParam(n: PNode) =
let staticParam = n.findUnresolvedStatic let staticParam = n.findUnresolvedStatic
@ -825,13 +838,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,9 +852,9 @@ 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}:
@ -1049,18 +1059,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
result = typeRel(c, f.sons[1].skipTypes({tyTypeDesc}), result = typeRel(c, f.sons[1].skipTypes({tyTypeDesc}),
a.sons[1].skipTypes({tyTypeDesc})) a.sons[1].skipTypes({tyTypeDesc}))
if result < isGeneric: return isNone if result < isGeneric: 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:
result = isNone if lengthOrd(fRange) != lengthOrd(aRange):
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
@ -1204,9 +1217,51 @@ 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:
for i in 1 .. rootf.sonsLen-2:
let ff = rootf.sons[i]
let aa = roota.sons[i]
result = typeRel(c, ff, aa)
if result notin {isEqual, isGeneric}: return isNone
# if ff.kind == tyRange and result != isEqual: 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 +1272,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,13 +1395,14 @@ 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:
var matched = matchUserTypeClass(c.c, c, f, aOrig) considerPreviousT:
if matched != nil: var matched = matchUserTypeClass(c.c, c, f, aOrig)
bindConcreteTypeToUserTypeClass(matched, a) if matched != nil:
put(c, f, matched) bindConcreteTypeToUserTypeClass(matched, a)
result = isGeneric if doBind: put(c, f, matched)
else: result = isGeneric
result = isNone else:
result = isNone
of tyCompositeTypeClass: of tyCompositeTypeClass:
considerPreviousT: considerPreviousT:
@ -1357,6 +1420,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 +1440,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, false)
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 +1655,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 +1795,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 +2085,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 +2164,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:

View file

@ -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})

View file

@ -1606,6 +1606,12 @@ 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 idx = macroSym.typ.len + i
yield (gp[i].sym, call.sons[idx])
var evalMacroCounter: int var evalMacroCounter: int
proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode, proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,

View file

@ -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))
@ -206,7 +257,7 @@ macro `.()`*(obj: JsObject, field: static[cstring],
result[1].add args[idx].copyNimTree result[1].add args[idx].copyNimTree
macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V], macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
field: static[cstring]): V = field: static[cstring]): V =
## Experimental dot accessor (get) for type JsAssoc. ## Experimental dot accessor (get) for type JsAssoc.
## Returns the value of a property of name `field` from a JsObject `x`. ## Returns the value of a property of name `field` from a JsObject `x`.
var importString: string var importString: string
@ -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

View file

@ -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"

View 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
View 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)

View 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()

View file

@ -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

View 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)

27
tests/generics/t5570.nim Normal file
View 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

View 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
View 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
View 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])

View 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)

View 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

View 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)

View 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: ptr NSArray[NSPasteboardItem]) = discard
let a = newMutableArray NSPasteboardItem
var x: NSMutableArray[NSPasteboardItem]
var y: NSArray[NSPasteboardItem] = x
writeObjects(nil, a)

View file

@ -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]

View file

@ -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()

View 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])

View file

@ -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
View 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
View 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 Executable file
View 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]