Merge branch 'zahary' into araq2

This commit is contained in:
Andreas Rumpf
2017-05-16 17:32:18 +02:00
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
nfIsRef # this node is a 'ref' node; used for the VM
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]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 30)
tfVarargs, # procedure has C styled varargs
# tyArray type represeting a varargs list
tfNoSideEffect, # procedure type does not allow side effects
tfFinal, # is the object final?
tfInheritable, # is the object inheritable?
@@ -1346,6 +1348,9 @@ proc initIdTable*(x: var TIdTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc newIdTable*: TIdTable =
initIdTable(result)
proc resetIdTable*(x: var TIdTable) =
x.counter = 0
# clear and set to old initial size:

View File

@@ -70,6 +70,8 @@ proc debug*(n: PNode) {.deprecated.}
template mdbg*: bool {.dirty.} =
when compiles(c.module):
c.module.fileIdx == gProjectMainIdx
elif compiles(c.c.module):
c.c.module.fileIdx == gProjectMainIdx
elif compiles(m.c.module):
m.c.module.fileIdx == gProjectMainIdx
elif compiles(cl.c.module):
@@ -79,6 +81,8 @@ template mdbg*: bool {.dirty.} =
p.lex.fileIdx == gProjectMainIdx
else:
p.module.module.fileIdx == gProjectMainIdx
elif compiles(m.module.fileIdx):
m.module.fileIdx == gProjectMainIdx
elif compiles(L.fileIdx):
L.fileIdx == gProjectMainIdx
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:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
return
let ty = skipTypes(dest.t, abstractRange)
let ty = skipTypes(dest.t, abstractRange + tyUserTypeClasses)
case ty.kind
of tyRef:
genRefAssign(p, dest, src, flags)
@@ -756,7 +756,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
genRecordFieldAux(p, e, d, a)
var r = rdLoc(a)
var f = e.sons[1].sym
let ty = skipTypes(a.t, abstractInst)
let ty = skipTypes(a.t, abstractInst + tyUserTypeClasses)
if ty.kind == tyTuple:
# we found a unique tuple type which lacks field information
# so we use Field$i

View File

@@ -164,7 +164,7 @@ proc mapType(typ: PType): TCTypeKind =
of tySet: result = mapSetType(typ)
of tyOpenArray, tyArray, tyVarargs: result = ctArray
of tyObject, tyTuple: result = ctStruct
of tyUserTypeClass, tyUserTypeClassInst:
of tyUserTypeClasses:
internalAssert typ.isResolvedUserTypeClass
return mapType(typ.lastSon)
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 =
let origType = t
var t = skipTypes(origType, irrelevantForBackend)
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
let sig = hashType(origType)
result = m.typeInfoMarker.getOrDefault(sig)
@@ -1131,6 +1131,9 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
of tyStatic:
if t.n != nil: result = genTypeInfo(m, lastSon t)
else: internalError("genTypeInfo(" & $t.kind & ')')
of tyUserTypeClasses:
internalAssert t.isResolvedUserTypeClass
return genTypeInfo(m, t.lastSon)
of tyProc:
if t.callConv != ccClosure:
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)
for i in 1 .. givenRegularParams:
result.addSon n.sons[i]
result.addSon n[i]
# handle parameters with default values, which were
# 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 parseStmtPragma(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
proc getTok(p: var TParser) =
@@ -194,7 +196,6 @@ proc newIdentNodeP(ident: PIdent, p: TParser): PNode =
proc parseExpr(p: var TParser): PNode
proc parseStmt(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 isSigilLike(tok: TToken): bool {.inline.} =
@@ -365,7 +366,10 @@ proc colonOrEquals(p: var TParser, a: PNode): PNode =
proc exprColonEqExpr(p: var TParser): PNode =
#| exprColonEqExpr = expr (':'|'=' expr)?
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) =
#| exprList = expr ^+ comma
@@ -520,7 +524,9 @@ proc parsePar(p: var TParser): PNode =
result.add(parseStmtPragma(p))
elif p.tok.tokType != tkParRi:
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
let asgn = newNodeP(nkAsgn, p)
getTok(p)
@@ -669,7 +675,6 @@ proc namedParams(p: var TParser, callee: PNode,
# progress guaranteed
exprColonEqExprListAux(p, endTok, result)
proc parseMacroColon(p: var TParser, x: PNode): PNode
proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
#| | doBlocks
@@ -696,14 +701,6 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
result = namedParams(p, result, nkCall, tkParRi)
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
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:
# progress guaranteed
result = dotExpr(p, result)
@@ -735,10 +732,7 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
if p.tok.tokType != tkComma: break
getTok(p)
optInd(p, x)
if p.tok.tokType == tkDo:
parseDoBlocks(p, result)
else:
result = parseMacroColon(p, result)
result = postExprBlocks(p, result)
break
else:
break
@@ -977,16 +971,9 @@ proc parseDoBlock(p: var TParser; info: TLineInfo): PNode =
let params = parseParamList(p, retColon=false)
let pragmas = optPragmas(p)
colcom(p, result)
result = newProcNode(nkDo, info, parseStmt(p),
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))
result = parseStmt(p)
if params.kind != nkEmpty:
result = newProcNode(nkDo, info, result, params = params, pragmas = pragmas)
proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
#| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
@@ -1162,49 +1149,75 @@ proc makeCall(n: PNode): PNode =
result = newNodeI(nkCall, n.info)
result.add n
proc parseMacroColon(p: var TParser, x: PNode): PNode =
#| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' exprList ':' stmt
#| | IND{=} 'else' ':' stmt )*
proc postExprBlocks(p: var TParser, x: PNode): PNode =
#| postExprBlocks = ':' stmt? ( IND{=} doBlock
#| | IND{=} 'of' exprList ':' stmt
#| | IND{=} 'elif' expr ':' stmt
#| | IND{=} 'except' exprList ':' stmt
#| | IND{=} 'else' ':' stmt )*
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)
getTok(p)
skipComment(p, result)
let stmtList = newNodeP(nkStmtList, p)
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
let body = parseStmt(p)
stmtList.add body
#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:
var stmtList = newNodeP(nkStmtList, p)
stmtList.add parseStmt(p)
# to keep backwards compatibility (see tests/vm/tstringnil)
result.add stmtList[0]
else:
result.add stmtList
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):
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 =
#| exprStmt = simpleExpr
@@ -1219,12 +1232,7 @@ proc parseExprStmt(p: var TParser): PNode =
getTok(p)
optInd(p, result)
var b = parseExpr(p)
if p.tok.tokType == tkColon and p.tok.indent < 0:
if b.kind != nkEmpty:
let call = makeCall(b)
call.add parseDoBlock(p, parLineInfo(p))
parseDoBlocks(p, call)
b = call
b = postExprBlocks(p, b)
addSon(result, a)
addSon(result, b)
else:
@@ -1247,11 +1255,7 @@ proc parseExprStmt(p: var TParser): PNode =
optInd(p, result)
else:
result = a
if p.tok.tokType == tkDo and p.tok.indent < 0:
result = makeCall(result)
parseDoBlocks(p, result)
return result
result = parseMacroColon(p, result)
result = postExprBlocks(p, result)
proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
result = parseExpr(p)
@@ -1341,7 +1345,9 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
# NL terminates:
addSon(result, ast.emptyNode)
else:
addSon(result, parseExpr(p))
var e = parseExpr(p)
e = postExprBlocks(p, e)
addSon(result, e)
proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
#| condStmt = expr colcom stmt COMMENT?
@@ -1893,14 +1899,7 @@ proc parseVariable(p: var TParser): PNode =
#| variable = (varTuple / identColonEquals) colonBody? indAndComment
if p.tok.tokType == tkParLe: result = parseVarTuple(p)
else: result = parseIdentColonEquals(p, {withPragma})
if p.tok.tokType == tkColon and p.tok.indent < 0:
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
result{-1} = postExprBlocks(p, result{-1})
indAndComment(p, result)
proc parseBind(p: var TParser, k: TNodeKind): PNode =

View File

@@ -351,8 +351,8 @@ when false:
for i in 0 ..< n.safeLen:
resetSemFlag(n[i])
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
flags: TExprFlags): PNode =
proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
s: PSym, flags: TExprFlags): PNode =
## Semantically check the output of a macro.
## This involves processes such as re-checking the macro output for type
## 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)
c.friendModules.add(s.owner.getModule)
result = n
excl(n.flags, nfSem)
result = macroResult
excl(result.flags, nfSem)
#resetSemFlag n
if s.typ.sons[0] == nil:
result = semStmt(c, result)
@@ -378,13 +378,26 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
of tyStmt:
result = semStmt(c, result)
of tyTypeDesc:
if n.kind == nkStmtList: result.kind = nkStmtListType
if result.kind == nkStmtList: result.kind = nkStmtListType
var typ = semTypeNode(c, result, nil)
result.typ = makeTypeDesc(c, typ)
#result = symNodeFromType(c, typ, n.info)
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 = 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]))
dec(evalTemplateCounter)
discard c.friendModules.pop()
@@ -409,7 +422,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
# c.evalContext = c.createEvalContext(emStatic)
result = evalMacroCall(c.module, c.cache, n, nOrig, sym)
if efNoSemCheck notin flags:
result = semAfterMacroCall(c, result, sym, flags)
result = semAfterMacroCall(c, n, result, sym, flags)
result = wrapInComesFrom(nOrig.info, result)
popInfoContext()

View File

@@ -16,7 +16,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
styleCheckUse(n.info, s)
pushInfoContext(n.info)
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()
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
@@ -47,10 +47,11 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
#raiseRecoverableError("")
result = errorNode(c, n)
if result.typ == nil or result.typ == enforceVoidContext:
# we cannot check for 'void' in macros ...
localError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
if n.kind != nkStmtList:
# we cannot check for 'void' in macros ...
localError(n.info, errExprXHasNoType,
renderTree(result, {renderNoComments}))
result.typ = errorType(c)
else:
if efNoProcvarCheck notin flags: semProcvarCheck(c, 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
return nil
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})
var check: PNode = nil
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
# each interpolation. We'll pass this template to getAst.
var
doBlk = n{-1}
quotedBlock = n{-1}
op = if n.len == 3: expectString(c, n[1]) else: "``"
quotes = newSeq[PNode](1)
# the quotes will be added to a nkCall statement
@@ -1721,20 +1724,23 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
ids = newSeq[PNode]()
# this will store the generated param names
if doBlk.kind != nkDo:
if quotedBlock.kind != nkStmtList:
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:
doBlk.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
doBlk[paramsPos].add getSysSym("typed").newSymNode # return type
dummyTemplate.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
dummyTemplate[paramsPos].add getSysSym("typed").newSymNode # return type
ids.add getSysSym("untyped").newSymNode # params type
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]
result = newNode(nkCall, n.info, @[
getMagicSym(mExpandToAst).newSymNode,
@@ -2325,8 +2331,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkCurly: result = semSetConstr(c, n)
of nkBracket: result = semArrayConstr(c, n, flags)
of nkObjConstr: result = semObjConstr(c, n, flags)
of nkLambda: result = semLambda(c, n, flags)
of nkDo: result = semDo(c, n, flags)
of nkLambdaKinds: result = semLambda(c, n, flags)
of nkDerefExpr: result = semDeref(c, n)
of nkAddr:
result = n

View File

@@ -121,12 +121,13 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
localError(n.info, errWrongNumberOfVariables)
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}:
localError(n.info, errGenerated, "no object or tuple type")
return result
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):
typeMismatch(call.sons[i].info, tupleTypeA, tupleTypeB)

View File

@@ -36,7 +36,8 @@ proc rawPushProcCon(c: PContext, owner: PSym) =
c.p = x
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
if params.len > 1:
let arg = params[1].sym

View File

@@ -851,9 +851,12 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
# type aliases are hard:
var t = semTypeNode(c, x, nil)
assert t != nil
if t.kind in {tyObject, tyEnum, tyDistinct}:
assert s.typ != nil
if s.typ.kind != tyAlias:
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
assignType(s.typ, t)
s.typ.id = t.id # same id
checkConstructedType(s.info, s.typ)
@@ -1063,13 +1066,6 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
popOwner(c)
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 =
var n = n
@@ -1174,7 +1170,8 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
var objB = t.sons[2]
while true:
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
if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB):
if obj.assignment.isNil:
@@ -1655,7 +1652,11 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
else: discard
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 = 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 n = if n[0].kind == nkBracket: n[0] else: n
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)
var isNilable = false
# 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}:
message n[i].info, errGenerated, "region needs to be an object type"
addSonSkipIntLit(result, region)
addSonSkipIntLit(result, base)
addSonSkipIntLit(result, t)
#if not isNilable: result.flags.incl tfNotNil
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])
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,
allowMetaTypes = true)
result = liftingWalk(expanded, true)
of tyUserTypeClasses, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), true))
of tyUserTypeClasses, tyBuiltInTypeClass, tyCompositeTypeClass,
tyAnd, tyOr, tyNot:
result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), false))
of tyGenericParam:
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 =
result = semTypeNode(c, n, nil)
n.typ = makeTypeDesc(c, result)
proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) =
var

View File

@@ -9,10 +9,10 @@
# 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
tfInstClearedFlags = {tfHasMeta}
tfInstClearedFlags = {tfHasMeta, tfUnresolved}
proc checkPartialConstructedType(info: TLineInfo, t: PType) =
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?
# See the notes for PActor in handleGenericInvocation
return
if not sameFlags(inst, key):
continue
block matchType:
for j in 1 .. high(key.sons):
# 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 =
# XXX: relying on allowMetaTypes is a kludge
result = copyType(t, t.owner, cl.allowMetaTypes)
if cl.allowMetaTypes: return
result.flags.incl tfFromGeneric
if not (t.kind in tyMetaTypes or
(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))
else:
result = searchInstTypes(t)
if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
for i in countup(1, sonsLen(t) - 1):
var x = t.sons[i]
if x.kind == tyGenericParam:
if x.kind in {tyGenericParam}:
x = lookupTypeVar(cl, x)
if x != nil:
if header == t: header = instCopyType(cl, t)
@@ -307,31 +312,32 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
rawAddSon(result, newbody)
checkPartialConstructedType(cl.info, newbody)
let dc = newbody.deepCopy
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
# 'deepCopy' needs to be instantiated for
# generics *when the type is constructed*:
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
attachedDeepCopy, 1)
if bodyIsNew and newbody.typeInst == nil:
#doassert newbody.typeInst == nil
newbody.typeInst = result
if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst:
# can come here for tyGenericInst too, see tests/metatype/ttypeor.nim
# need to look into this issue later
assert newbody.kind in {tyRef, tyPtr}
assert newbody.lastSon.typeInst == nil
newbody.lastSon.typeInst = result
let asgn = newbody.assignment
if asgn != nil and sfFromGeneric notin asgn.flags:
# '=' needs to be instantiated for generics when the type is constructed:
newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
attachedAsgn, 1)
let methods = skipTypes(bbody, abstractPtrs).methods
for col, meth in items(methods):
# we instantiate the known methods belonging to that type, this causes
# them to be registered and that's enough, so we 'discard' the result.
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
attachedAsgn, col)
if cl.allowMetaTypes == false:
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
# 'deepCopy' needs to be instantiated for
# generics *when the type is constructed*:
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
attachedDeepCopy, 1)
if bodyIsNew and newbody.typeInst == nil:
#doassert newbody.typeInst == nil
newbody.typeInst = result
if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst:
# can come here for tyGenericInst too, see tests/metatype/ttypeor.nim
# need to look into this issue later
assert newbody.kind in {tyRef, tyPtr}
assert newbody.lastSon.typeInst == nil
newbody.lastSon.typeInst = result
let asgn = newbody.assignment
if asgn != nil and sfFromGeneric notin asgn.flags:
# '=' needs to be instantiated for generics when the type is constructed:
newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
attachedAsgn, 1)
let methods = skipTypes(bbody, abstractPtrs).methods
for col, meth in items(methods):
# we instantiate the known methods belonging to that type, this causes
# them to be registered and that's enough, so we 'discard' the result.
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
attachedAsgn, col)
proc eraseVoidParams*(t: PType) =
# 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)
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,
t: PType): untyped =
generateTypeInstance(p, pt, arg.info, t)

View File

@@ -154,7 +154,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
else:
c.hashSym(t.sym)
return
of tyAlias, tyGenericInst:
of tyAlias, tyGenericInst, tyUserTypeClasses:
c.hashType t.lastSon, flags
return
else:
@@ -201,16 +201,6 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
of tyRef, tyPtr, tyGenericBody, tyVar:
c.hashType t.lastSon, flags
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:
c.hashTree(t.n)
of tyTuple:

View File

@@ -26,7 +26,7 @@ type
sym*: PSym
unmatchedVarParam*: int
diagnostics*: seq[string]
CandidateErrors* = seq[CandidateError]
TCandidate* = object
@@ -68,7 +68,7 @@ type
# future.
mutabilityProblem*: uint8 # tyVar mismatch
inheritancePenalty: int # to prefer closest father object type
TTypeRelation* = enum # order is important!
isNone, isConvertible,
isIntConv,
@@ -177,6 +177,13 @@ proc sumGeneric(t: PType): int =
tyOpenArray, tyVarargs, tySet, tyRange, tySequence, tyGenericBody:
t = t.lastSon
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:
t = t.sons[0]
inc result
@@ -185,8 +192,8 @@ proc sumGeneric(t: PType): int =
t = t.lastSon
if t.kind == tyEmpty: break
inc result
of tyGenericInvocation, tyTuple, tyProc:
result += ord(t.kind == tyGenericInvocation)
of tyGenericInvocation, tyTuple, tyProc, tyAnd:
result += ord(t.kind in {tyGenericInvocation, tyAnd})
for i in 0 .. <t.len:
if t.sons[i] != nil:
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
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 =
result = a.exactMatches - b.exactMatches
if result != 0: return
@@ -248,14 +264,6 @@ proc cmpCandidates*(a, b: TCandidate): int =
if result != 0: return
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 =
if arg.kind in nkSymChoices:
result = typeToString(arg[0].typ, prefer)
@@ -639,7 +647,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
makeTypeDesc(c, typ)
typeParams.safeAdd((param, typ))
addDecl(c, param)
for param in typeClass.n[0]:
@@ -676,7 +684,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
flags: TExprFlags = {}
collectDiagnostics = m.diagnostics != nil or
sfExplain in typeClass.sym.flags
if collectDiagnostics:
oldWriteHook = writelnHook
# 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)
if oldWriteHook != nil: oldWriteHook msg
diagnostics.add msg
var checkedBody = c.semTryExpr(c, body.copyTree, flags)
if collectDiagnostics:
writelnHook = oldWriteHook
for msg in diagnostics: m.diagnostics.safeAdd msg
if checkedBody == nil: return nil
# The inferrable type params have been identified during the semTryExpr above.
@@ -739,14 +747,14 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode,
allowMetaTypes = allowUnresolved)
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,
# capable of deriving the value of a static parameter in
# expressions such as (N + 5) / 2 = rhs
#
# Preconditions:
#
# * The input of this proc must be semantized
# * The input of this proc must be semantized
# - all templates should be expanded
# - aby constant folding possible should already be performed
#
@@ -754,64 +762,69 @@ proc inferStaticParam*(lhs: PNode, rhs: BiggestInt): PType =
#
# Result:
#
# The proc will return the inferred static type with the `n` field
# populated with the inferred value.
#
# `nil` will be returned if the inference was not possible
# The proc will return true if the static types was successfully
# inferred. The result will be bound to the original static type
# in the TCandidate.
#
if lhs.kind in nkCallKinds and lhs[0].kind == nkSym:
case lhs[0].sym.magic
of mUnaryLt:
return inferStaticParam(lhs[1], rhs + 1)
return inferStaticParam(c, lhs[1], rhs + 1)
of mAddI, mAddU, mInc, mSucc:
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:
return inferStaticParam(lhs[1], rhs - lhs[2].intVal)
return inferStaticParam(c, lhs[1], rhs - lhs[2].intVal)
of mDec, mSubI, mSubU, mPred:
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:
return inferStaticParam(lhs[1], rhs + lhs[2].intVal)
return inferStaticParam(c, lhs[1], rhs + lhs[2].intVal)
of mMulI, mMulU:
if lhs[1].kind == nkIntLit:
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:
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:
if lhs[1].kind == nkIntLit:
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:
return inferStaticParam(lhs[1], lhs[2].intVal * rhs)
return inferStaticParam(c, lhs[1], lhs[2].intVal * rhs)
of mShlI:
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:
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:
return inferStaticParam(lhs[1], -rhs)
return inferStaticParam(c, lhs[1], -rhs)
of mUnaryPlusI, mToInt, mToBiggestInt:
return inferStaticParam(lhs[1], rhs)
return inferStaticParam(c, lhs[1], rhs)
else: discard
elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and lhs.typ.n == nil:
lhs.typ.n = newIntNode(nkIntLit, rhs)
return lhs.typ
return nil
var inferred = newTypeWithSons(c.c, tyStatic, lhs.typ.sons)
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 false
proc failureToInferStaticParam(n: PNode) =
let staticParam = n.findUnresolvedStatic
@@ -825,13 +838,10 @@ proc inferStaticsInRange(c: var TCandidate,
allowUnresolved = true)
let upperBound = tryResolvingStaticExpr(c, inferred.n[1],
allowUnresolved = true)
template doInferStatic(c: var TCandidate, e: PNode, r: BiggestInt) =
template doInferStatic(e: PNode, r: BiggestInt) =
var exp = e
var rhs = r
var inferred = inferStaticParam(exp, rhs)
if inferred != nil:
put(c, inferred, inferred)
if inferStaticParam(c, exp, rhs):
return isGeneric
else:
failureToInferStaticParam exp
@@ -842,9 +852,9 @@ proc inferStaticsInRange(c: var TCandidate,
return isGeneric
else:
return isNone
doInferStatic(c, upperBound, lengthOrd(concrete) + lowerBound.intVal - 1)
doInferStatic(upperBound, lengthOrd(concrete) + lowerBound.intVal - 1)
elif upperBound.kind == nkIntLit:
doInferStatic(c, lowerBound, upperBound.intVal + 1 - lengthOrd(concrete))
doInferStatic(lowerBound, upperBound.intVal + 1 - lengthOrd(concrete))
template subtypeCheck() =
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}),
a.sons[1].skipTypes({tyTypeDesc}))
if result < isGeneric: return isNone
if fRange.rangeHasUnresolvedStatic:
return inferStaticsInRange(c, fRange, a)
elif c.c.inTypeClass > 0 and aRange.rangeHasUnresolvedStatic:
return inferStaticsInRange(c, aRange, f)
elif lengthOrd(fRange) != lengthOrd(a):
result = isNone
else:
if lengthOrd(fRange) != lengthOrd(aRange):
result = isNone
else: discard
of tyOpenArray, tyVarargs:
# varargs[expr] is special too but handled earlier. So we only need to
# handle varargs[stmt] which is the same as varargs[typed]:
if f.kind == tyVarargs:
if tfVarargs in a.flags:
return typeRel(c, f.base, a.lastSon)
if tfOldSchoolExprStmt in f.sons[0].flags:
if f.sons[0].kind == tyExpr: 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:
if a.kind == f.kind: result = isEqual
of tyGenericInst, tyAlias:
of tyAlias:
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:
considerPreviousT:
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:
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
if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
@@ -1333,13 +1395,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if f.isResolvedUserTypeClass:
result = typeRel(c, f.lastSon, a)
else:
var matched = matchUserTypeClass(c.c, c, f, aOrig)
if matched != nil:
bindConcreteTypeToUserTypeClass(matched, a)
put(c, f, matched)
result = isGeneric
else:
result = isNone
considerPreviousT:
var matched = matchUserTypeClass(c.c, c, f, aOrig)
if matched != nil:
bindConcreteTypeToUserTypeClass(matched, a)
if doBind: put(c, f, matched)
result = isGeneric
else:
result = isNone
of tyCompositeTypeClass:
considerPreviousT:
@@ -1357,6 +1420,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if result != isNone:
put(c, f, a)
result = isGeneric
of tyGenericParam:
var x = PType(idTableGet(c.bindings, f))
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
c.typedescMatched = true
var aa = a
while aa.kind in {tyTypeDesc, tyGenericParam} and
aa.len > 0:
while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0:
aa = lastSon(aa)
if aa.kind == tyGenericParam:
return isGeneric
result = typeRel(c, f.base, aa)
if result > isGeneric: result = isGeneric
else:
result = isNone
else:
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}:
let concrete = concreteType(c, a)
if concrete == nil: return isNone
@@ -1590,6 +1655,10 @@ proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
of isEqual: inc(m.exactMatches)
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,
argSemantized, argOrig: PNode): PNode =
var
@@ -1726,6 +1795,14 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
inc(m.genericMatches)
m.fauxMatch = a.kind
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)
# check for a base type match, which supports varargs[T] without []
# constructor in a call:
@@ -2008,6 +2085,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
#assert(container == nil)
if container.isNil:
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
container.typ.flags.incl tfVarargs
else:
incrIndexType(container.typ)
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 & "'")
return nil
var f = dc.typ.sons[col]
if op == attachedDeepCopy:
if f.kind in {tyRef, tyPtr}: f = f.lastSon
else:

View File

@@ -886,6 +886,9 @@ proc isGenericAlias*(t: PType): bool =
proc skipGenericAlias*(t: PType): PType =
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 =
template cycleCheck() =
# 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:
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
var a = skipTypes(x, {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
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
proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,

View File

@@ -78,6 +78,10 @@ type
## Statically typed wrapper around a JavaScript object.
NotString = concept c
c isnot string
js* = JsObject
var jsarguments* {.importc: "arguments", nodecl}: JsObject
## JavaScript's arguments pseudo-variable
# New
proc newJsObject*: JsObject {. importcpp: "{@}" .}
@@ -93,18 +97,64 @@ proc hasOwnProperty*(x: JsObject, prop: cstring): bool
proc jsTypeOf*(x: JsObject): cstring {. importcpp: "typeof(#)" .}
## 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
proc to*(x: JsObject, T: typedesc): T {. importcpp: "(#)" .}
## Converts a JsObject `x` to type `T`.
proc toJs*[T](val: T): JsObject {. importcpp: "(#)" .}
## 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 .}
## 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 .}
## 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
{. importcpp: getImpl .}
## 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 .}
helper(`obj`, `value`)
macro `.()`*(obj: JsObject, field: static[cstring],
args: varargs[JsObject, toJs]): JsObject =
macro `.()`*(obj: JsObject,
field: static[cstring],
args: varargs[JsObject, jsFromAst]): JsObject =
## Experimental "method call" operator for type JsObject.
## 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,
@@ -196,9 +247,9 @@ macro `.()`*(obj: JsObject, field: static[cstring],
if not mangledNames.hasKey($field):
mangledNames[$field] = $mangleJsName(field)
importString = "#." & mangledNames[$field] & "(@)"
result = quote do:
result = quote:
proc helper(o: JsObject): JsObject
{. importcpp: `importString`, gensym .}
{. importcpp: `importString`, gensym, discardable .}
helper(`obj`)
for idx in 0 ..< args.len:
let paramName = newIdentNode(!("param" & $idx))
@@ -206,7 +257,7 @@ macro `.()`*(obj: JsObject, field: static[cstring],
result[1].add args[idx].copyNimTree
macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
field: static[cstring]): V =
field: static[cstring]): V =
## Experimental dot accessor (get) for type JsAssoc.
## Returns the value of a property of name `field` from a JsObject `x`.
var importString: string
@@ -222,7 +273,8 @@ macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
helper(`obj`)
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.
## Sets the value of a property of name `field` in a JsObject `x` to `value`.
var importString: string
@@ -238,7 +290,8 @@ macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
helper(`obj`, `value`)
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.
## 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

View File

@@ -7,7 +7,7 @@ discard """
import macros
macro mixer(n: typed): untyped =
expectKind(n, nnkCharLit)
expectKind(n[0], nnkCharLit)
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
# https://github.com/nim-lang/Nim/issues/2018
type ProtocolFollower = generic
type ProtocolFollower = concept
true # not a particularly involved protocol
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 """
output: '''true
output: '''
true
true
true
@@ -14,10 +14,18 @@ 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
# Test JsObject []= and []
@@ -55,8 +63,8 @@ block:
block:
proc test(): bool =
let obj = newJsObject()
obj.`?!$` = proc(x, y, z: int, t: string): string = t & $(x + y + z)
obj.`?!$`(1, 2, 3, "Result is: ").to(string) == "Result is: 6"
obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z)
obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == "Result is: 6"
echo test()
# Test JsObject []()
@@ -265,3 +273,47 @@ block:
let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever))
obj.onWhatever(1) == 10
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
macro match*(s: cstring|string; pos: int; sections: untyped): untyped =
for sec in sections.children:
macro match*(s: cstring|string; pos: int; sections: varargs[untyped]): untyped =
for sec in sections:
expectKind sec, nnkOfBranch
expectLen sec, 2
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 =
# Make a template tree
result = (quote do:
result = quote do:
proc someProc* =
wrap do:
let x = 123
# Implicit conversion here
let s: string = x
echo s
)
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]