diff options
-rw-r--r-- | compiler/ast.nim | 6 | ||||
-rw-r--r-- | compiler/ccgcalls.nim | 20 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 4 | ||||
-rw-r--r-- | compiler/destroyer.nim | 177 | ||||
-rw-r--r-- | compiler/dfa.nim | 2 | ||||
-rw-r--r-- | compiler/evaltempl.nim | 14 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 5 | ||||
-rw-r--r-- | compiler/lookups.nim | 2 | ||||
-rw-r--r-- | compiler/sem.nim | 11 | ||||
-rw-r--r-- | compiler/semexprs.nim | 4 | ||||
-rw-r--r-- | compiler/semfold.nim | 8 | ||||
-rw-r--r-- | compiler/seminst.nim | 2 | ||||
-rw-r--r-- | compiler/semmagic.nim | 2 | ||||
-rw-r--r-- | compiler/semstmts.nim | 47 | ||||
-rw-r--r-- | compiler/semtypes.nim | 10 | ||||
-rw-r--r-- | koch.nim | 2 | ||||
-rw-r--r-- | lib/pure/asyncdispatch.nim | 213 | ||||
-rw-r--r-- | lib/pure/includes/asynccommon.nim | 211 | ||||
-rw-r--r-- | tests/destructor/tmatrix.nim | 22 | ||||
-rw-r--r-- | tests/destructor/tmove_objconstr.nim | 47 | ||||
-rw-r--r-- | tests/errmsgs/t9908_01.nim | 10 | ||||
-rw-r--r-- | tests/errmsgs/t9908_02.nim | 10 | ||||
-rw-r--r-- | tests/misc/tsizeof2.nim | 2 | ||||
-rw-r--r-- | tests/modules/m9627/a.nim | 1 | ||||
-rw-r--r-- | tests/modules/m9627/b.nim | 1 | ||||
-rw-r--r-- | tests/modules/t9627.nim | 7 | ||||
-rw-r--r-- | tests/pragmas/tused.nim | 6 | ||||
-rw-r--r-- | tests/template/tparams_gensymed.nim | 40 |
28 files changed, 546 insertions, 340 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 40a05e6bf..0247acb03 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1087,9 +1087,6 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym, result.id = getID() when debugIds: registerId(result) - #if result.id == 77131: - # writeStacktrace() - # echo name.s proc isMetaType*(t: PType): bool = return t.kind in tyMetaTypes or @@ -1261,6 +1258,9 @@ proc `$`*(x: TLockLevel): string = elif x.ord == UnknownLockLevel.ord: result = "<unknown>" else: result = $int16(x) +proc `$`*(s: PSym): string = + result = s.name.s & "@" & $s.id + proc newType*(kind: TTypeKind, owner: PSym): PType = new(result) result.kind = kind diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index b23cd598e..d177e1f88 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -63,26 +63,6 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, add(pl, ~");$n") line(p, cpsStmts, pl) -proc isInCurrentFrame(p: BProc, n: PNode): bool = - # checks if `n` is an expression that refers to the current frame; - # this does not work reliably because of forwarding + inlining can break it - case n.kind - of nkSym: - if n.sym.kind in {skVar, skResult, skTemp, skLet} and p.prc != nil: - result = p.prc.id == n.sym.owner.id - of nkDotExpr, nkBracketExpr: - if skipTypes(n.sons[0].typ, abstractInst).kind notin {tyVar,tyLent,tyPtr,tyRef}: - result = isInCurrentFrame(p, n.sons[0]) - of nkHiddenStdConv, nkHiddenSubConv, nkConv: - result = isInCurrentFrame(p, n.sons[1]) - of nkHiddenDeref, nkDerefExpr: - # what about: var x = addr(y); callAsOpenArray(x[])? - # *shrug* ``addr`` is unsafe anyway. - result = false - of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: - result = isInCurrentFrame(p, n.sons[0]) - else: discard - proc genBoundsCheck(p: BProc; arr, a, b: TLoc) proc openArrayLoc(p: BProc, n: PNode): Rope = diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 59ef05f9c..cab2c78f5 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -850,7 +850,6 @@ proc genUncheckedArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc initLocExpr(p, x, a) initLocExpr(p, y, b) - var ty = skipTypes(a.t, abstractVarRange + abstractPtrs + tyUserTypeClasses) d.inheritLocation(a) putIntoDest(p, d, n, ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage) @@ -884,7 +883,6 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) = var a, b: TLoc initLocExpr(p, x, a) initLocExpr(p, y, b) - var ty = skipTypes(a.t, abstractVarRange) inheritLocation(d, a) putIntoDest(p, d, n, ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage) @@ -1402,7 +1400,6 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = else: var i: TLoc getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) - let oldCode = p.s(cpsStmts) linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", i.r, L.rope) initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap) elem.r = ropecg(p.module, "$1$3[$2]", rdLoc(d), rdLoc(i), dataField(p)) @@ -2576,7 +2573,6 @@ proc genConstObjConstr(p: BProc; n: PNode): Rope = proc genConstSimpleList(p: BProc, n: PNode): Rope = var length = sonsLen(n) result = rope("{") - let t = n.typ.skipTypes(abstractInst) for i in countup(0, length - 2): addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])]) if length > 0: diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index 51ad26f2c..407204e51 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -116,7 +116,7 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, - strutils, options, dfa, lowerings, tables, modulegraphs, + strutils, options, dfa, lowerings, tables, modulegraphs, msgs, lineinfos, parampatterns const @@ -127,20 +127,11 @@ type owner: PSym g: ControlFlowGraph jumpTargets: IntSet - tmpObj: PType - tmp: PSym destroys, topLevelVars: PNode - toDropBit: Table[int, PSym] graph: ModuleGraph emptyNode: PNode otherRead: PNode -proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = - # XXX why are temps fields in an object here? - let f = newSym(skField, getIdent(c.graph.cache, ":d" & $c.tmpObj.n.len), c.owner, info) - f.typ = typ - rawAddField c.tmpObj, f - result = rawDirectAccess(c.tmp, f) proc isHarmlessVar*(s: PSym; c: Con): bool = # 's' is harmless if it used only once and its @@ -329,22 +320,11 @@ proc genDestroy(c: Con; t: PType; dest: PNode): PNode = proc addTopVar(c: var Con; v: PNode) = c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode) -proc dropBit(c: var Con; s: PSym): PSym = - result = c.toDropBit.getOrDefault(s.id) - assert result != nil - -proc registerDropBit(c: var Con; s: PSym) = - let result = newSym(skTemp, getIdent(c.graph.cache, s.name.s & "_AliveBit"), c.owner, s.info) - result.typ = getSysType(c.graph, s.info, tyBool) - let trueVal = newIntTypeNode(nkIntLit, 1, result.typ) - c.topLevelVars.add newTree(nkIdentDefs, newSymNode result, c.emptyNode, trueVal) - c.toDropBit[s.id] = result - # generate: - # if not sinkParam_AliveBit: `=destroy`(sinkParam) - let t = s.typ.skipTypes({tyGenericInst, tyAlias, tySink}) - if t.destructor != nil: - c.destroys.add newTree(nkIfStmt, - newTree(nkElifBranch, newSymNode result, genDestroy(c, t, newSymNode s))) +proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode = + let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info) + sym.typ = typ + result = newSymNode(sym) + c.addTopVar(result) proc p(n: PNode; c: var Con): PNode @@ -355,16 +335,6 @@ template recurse(n, dest) = proc isSinkParam(s: PSym): bool {.inline.} = result = s.kind == skParam and s.typ.kind == tySink -proc destructiveMoveSink(n: PNode; c: var Con): PNode = - # generate: (chckMove(sinkParam_AliveBit); sinkParam_AliveBit = false; sinkParam) - result = newNodeIT(nkStmtListExpr, n.info, n.typ) - let bit = newSymNode dropBit(c, n.sym) - if optMoveCheck in c.owner.options: - result.add callCodegenProc(c.graph, "chckMove", bit.info, bit) - result.add newTree(nkAsgn, bit, - newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool))) - result.add n - proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode = result = newNodeI(nkCall, n.info) result.add(newSymNode(createMagic(c.graph, magicname, m))) @@ -395,6 +365,12 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode = result.add genWasMoved(n, c) result.add tempAsNode +proc sinkParamIsLastReadCheck(c: var Con, s: PNode) = + assert s.kind == nkSym and s.sym.kind == skParam + if not isLastRead(s, c): + localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s & + "` is already consumed at " & toFileLineCol(c. graph.config, s.info)) + proc passCopyToSink(n: PNode; c: var Con): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) let tmp = getTemp(c, n.typ, n.info) @@ -411,6 +387,11 @@ proc passCopyToSink(n: PNode; c: var Con): PNode = result.add tmp proc pArg(arg: PNode; c: var Con; isSink: bool): PNode = + template pArgIfTyped(arg_part: PNode): PNode = + # typ is nil if we are in if/case expr branch with noreturn + if arg_part.typ == nil: p(arg_part, c) + else: pArg(arg_part, c, isSink) + if isSink: if arg.kind in nkCallKinds: # recurse but skip the call expression in order to prevent @@ -421,17 +402,53 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode = result.add arg[0] for i in 1..<arg.len: result.add pArg(arg[i], c, i < L and parameters[i].kind == tySink) - elif arg.kind in {nkObjConstr, nkCharLit..nkFloat128Lit}: + elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkBracket, nkCharLit..nkFloat128Lit}: discard "object construction to sink parameter: nothing to do" result = arg + elif arg.kind == nkSym and isSinkParam(arg.sym): + # Sinked params can be consumed only once. We need to reset the memory + # to disable the destructor which we have not elided + sinkParamIsLastReadCheck(c, arg) + result = destructiveMoveVar(arg, c) elif arg.kind == nkSym and arg.sym.kind in InterestingSyms and isLastRead(arg, c): - # if x is a variable and it its last read we eliminate its - # destructor invokation, but don't. We need to reset its memory - # to disable its destructor which we have not elided: + # it is the last read, can be sinked. We need to reset the memory + # to disable the destructor which we have not elided result = destructiveMoveVar(arg, c) - elif arg.kind == nkSym and isSinkParam(arg.sym): - # mark the sink parameter as used: - result = destructiveMoveSink(arg, c) + elif arg.kind in {nkBlockExpr, nkBlockStmt}: + result = copyNode(arg) + result.add arg[0] + result.add pArg(arg[1], c, isSink) + elif arg.kind == nkStmtListExpr: + result = copyNode(arg) + for i in 0..arg.len-2: + result.add p(arg[i], c) + result.add pArg(arg[^1], c, isSink) + elif arg.kind in {nkIfExpr, nkIfStmt}: + result = copyNode(arg) + for i in 0..<arg.len: + var branch = copyNode(arg[i]) + if arg[i].kind in {nkElifBranch, nkElifExpr}: + branch.add p(arg[i][0], c) + branch.add pArgIfTyped(arg[i][1]) + else: + branch.add pArgIfTyped(arg[i][0]) + result.add branch + elif arg.kind == nkCaseStmt: + result = copyNode(arg) + result.add p(arg[0], c) + for i in 1..<arg.len: + var branch: PNode + if arg[i].kind == nkOfbranch: + branch = arg[i] # of branch conditions are constants + branch[^1] = pArgIfTyped(arg[i][^1]) + elif arg[i].kind in {nkElifBranch, nkElifExpr}: + branch = copyNode(arg[i]) + branch.add p(arg[i][0], c) + branch.add pArgIfTyped(arg[i][1]) + else: + branch = copyNode(arg[i]) + branch.add pArgIfTyped(arg[i][0]) + result.add branch else: # an object that is not temporary but passed to a 'sink' parameter # results in a copy. @@ -440,6 +457,11 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode = result = p(arg, c) proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = + template moveOrCopyIfTyped(ri_part: PNode): PNode = + # typ is nil if we are in if/case expr branch with noreturn + if ri_part.typ == nil: p(ri_part, c) + else: moveOrCopy(dest, ri_part, c) + case ri.kind of nkCallKinds: result = genSink(c, dest.typ, dest, ri) @@ -454,7 +476,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = result.add ri2 of nkBracketExpr: if ri[0].kind == nkSym and isUnpackedTuple(ri[0].sym): - # unpacking of tuple: move out the elements + # unpacking of tuple: move out the elements result = genSink(c, dest.typ, dest, ri) else: result = genCopy(c, dest.typ, dest, ri) @@ -464,6 +486,45 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = for i in 0..ri.len-2: result.add p(ri[i], c) result.add moveOrCopy(dest, ri[^1], c) + of nkBlockExpr, nkBlockStmt: + result = newNodeI(nkBlockStmt, ri.info) + result.add ri[0] ## add label + result.add moveOrCopy(dest, ri[1], c) + of nkIfExpr, nkIfStmt: + result = newNodeI(nkIfStmt, ri.info) + for i in 0..<ri.len: + var branch = copyNode(ri[i]) + if ri[i].kind in {nkElifBranch, nkElifExpr}: + branch.add p(ri[i][0], c) + branch.add moveOrCopyIfTyped(ri[i][1]) + else: + branch.add moveOrCopyIfTyped(ri[i][0]) + result.add branch + of nkCaseStmt: + result = newNodeI(nkCaseStmt, ri.info) + result.add p(ri[0], c) + for i in 1..<ri.len: + var branch: PNode + if ri[i].kind == nkOfbranch: + branch = ri[i] # of branch conditions are constants + branch[^1] = moveOrCopyIfTyped(ri[i][^1]) + elif ri[i].kind in {nkElifBranch, nkElifExpr}: + branch = copyNode(ri[i]) + branch.add p(ri[i][0], c) + branch.add moveOrCopyIfTyped(ri[i][1]) + else: + branch = copyNode(ri[i]) + branch.add moveOrCopyIfTyped(ri[i][0]) + result.add branch + of nkBracket: + # array constructor + result = genSink(c, dest.typ, dest, ri) + let ri2 = copyTree(ri) + for i in 0..<ri.len: + # everything that is passed to an array constructor is consumed, + # so these all act like 'sink' parameters: + ri2[i] = pArg(ri[i], c, isSink = true) + result.add ri2 of nkObjConstr: result = genSink(c, dest.typ, dest, ri) let ri2 = copyTree(ri) @@ -484,14 +545,17 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = ri2[i] = pArg(ri[i], c, isSink = true) result.add ri2 of nkSym: - if ri.sym.kind != skParam and isLastRead(ri, c): + if isSinkParam(ri.sym): # Rule 3: `=sink`(x, z); wasMoved(z) + sinkParamIsLastReadCheck(c, ri) var snk = genSink(c, dest.typ, dest, ri) - snk.add p(ri, c) + snk.add ri + result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved)) + elif ri.sym.kind != skParam and isLastRead(ri, c): + # Rule 3: `=sink`(x, z); wasMoved(z) + var snk = genSink(c, dest.typ, dest, ri) + snk.add ri result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved)) - elif isSinkParam(ri.sym): - result = genSink(c, dest.typ, dest, ri) - result.add destructiveMoveSink(ri, c) else: result = genCopy(c, dest.typ, dest, ri) result.add p(ri, c) @@ -512,14 +576,15 @@ proc p(n: PNode; c: var Con): PNode = if it.kind == nkVarTuple and hasDestructor(ri.typ): let x = lowerTupleUnpacking(c.graph, it, c.owner) result.add p(x, c) - elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isUnpackedTuple(it[0].sym): + elif it.kind == nkIdentDefs and hasDestructor(it[0].typ): for j in 0..L-2: let v = it[j] doAssert v.kind == nkSym # move the variable declaration to the top of the frame: c.addTopVar v # make sure it's destroyed at the end of the proc: - c.destroys.add genDestroy(c, v.typ, v) + if not isUnpackedTuple(it[0].sym): + c.destroys.add genDestroy(c, v.typ, v) if ri.kind != nkEmpty: let r = moveOrCopy(v, ri, c) result.add r @@ -566,12 +631,8 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = echo "injecting into ", n var c: Con c.owner = owner - c.tmp = newSym(skTemp, getIdent(g.cache, ":d"), owner, n.info) - c.tmpObj = createObj(g, owner, n.info) - c.tmp.typ = c.tmpObj c.destroys = newNodeI(nkStmtList, n.info) c.topLevelVars = newNodeI(nkVarSection, n.info) - c.toDropBit = initTable[int, PSym]() c.graph = g c.emptyNode = newNodeI(nkEmpty, n.info) let cfg = constructCfg(owner, n) @@ -586,10 +647,10 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = let params = owner.typ.n for i in 1 ..< params.len: let param = params[i].sym - if param.typ.kind == tySink: registerDropBit(c, param) + if param.typ.kind == tySink: + c.destroys.add genDestroy(c, param.typ.skipTypes({tyGenericInst, tyAlias, tySink}), params[i]) + let body = p(n, c) - if c.tmp.typ.n.len > 0: - c.addTopVar(newSymNode c.tmp) result = newNodeI(nkStmtList, n.info) if c.topLevelVars.len > 0: result.add c.topLevelVars diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 415cc4ab3..cd32d95d5 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -272,7 +272,7 @@ proc genReturn(c: var Con; n: PNode) = c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len) const - InterestingSyms = {skVar, skResult, skLet} + InterestingSyms = {skVar, skResult, skLet, skParam} proc genUse(c: var Con; n: PNode) = var n = n diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 09a1cd436..0f9220102 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -37,18 +37,21 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = case templ.kind of nkSym: var s = templ.sym - if s.owner.id == c.owner.id: + if s.owner == nil or s.owner.id == c.owner.id: if s.kind == skParam and sfGenSym notin s.flags: handleParam actual.sons[s.position] - elif s.kind == skGenericParam or - s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam: + elif (s.owner != nil) and (s.kind == skGenericParam or + s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam): handleParam actual.sons[s.owner.typ.len + s.position - 1] else: internalAssert c.config, sfGenSym in s.flags or s.kind == skType var x = PSym(idTableGet(c.mapping, s)) if x == nil: x = copySym(s) - x.owner = c.genSymOwner + # sem'check needs to set the owner properly later, see bug #9476 + x.owner = nil # c.genSymOwner + #if x.kind == skParam and x.owner.kind == skModule: + # internalAssert c.config, false idTablePut(c.mapping, s, x) result.add newSymNode(x, if c.instLines: actual.info else: templ.info) else: @@ -173,6 +176,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; initIdTable(ctx.mapping) let body = tmpl.getBody + #echo "instantion of ", renderTree(body, {renderIds}) if isAtom(body): result = newNodeI(nkPar, body.info) evalTemplateAux(body, args, ctx, result) @@ -189,5 +193,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; evalTemplateAux(body.sons[i], args, ctx, result) result.flags.incl nfFromTemplate result = wrapInComesFrom(n.info, tmpl, result) + #if ctx.debugActive: + # echo "instantion of ", renderTree(result, {renderIds}) dec(conf.evalTemplateCounter) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 874cb4bd0..ddde1be31 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -407,11 +407,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = obj.n[0].sym.id = -s.id else: addField(obj, s, c.graph.cache) - # but always return because the rest of the proc is only relevant when - # ow != owner: - return # direct or indirect dependency: - if (innerProc and s.typ.callConv == ccClosure) or interestingVar(s): + elif (innerProc and s.typ.callConv == ccClosure) or interestingVar(s): discard """ proc outer() = var x: int diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 2fb4e5241..db03ac2e0 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -169,7 +169,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) = getSymRepr(c.config, s)) inc missingImpls elif {sfUsed, sfExported} * s.flags == {}: - if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}: + if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam, skEnumField}: # XXX: implicit type params are currently skTypes # maybe they can be made skGenericParam as well. if s.typ != nil and tfImplicitTypeParam notin s.typ.flags and diff --git a/compiler/sem.nim b/compiler/sem.nim index 924e53b66..8332af346 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -207,11 +207,12 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = if result.kind notin {kind, skTemp}: localError(c.config, n.info, "cannot use symbol of kind '" & $result.kind & "' as a '" & $kind & "'") - if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}: - # declarative context, so produce a fresh gensym: - result = copySym(result) - result.ast = n.sym.ast - put(c.p, n.sym, result) + when false: + if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}: + # declarative context, so produce a fresh gensym: + result = copySym(result) + result.ast = n.sym.ast + put(c.p, n.sym, result) # when there is a nested proc inside a template, semtmpl # will assign a wrong owner during the first pass over the # template; we must fix it here: see #909 diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 08917cb29..ddec457a1 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1083,6 +1083,8 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = # XXX see the hack in sigmatch.nim ... return s.typ.n elif sfGenSym in s.flags: + # the owner should have been set by now by addParamOrResult + internalAssert c.config, s.owner != nil if c.p.wasForwarded: # gensym'ed parameters that nevertheless have been forward declared # need a special fixup: @@ -2289,6 +2291,8 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode = var labl = newSymG(skLabel, n.sons[0], c) if sfGenSym notin labl.flags: addDecl(c, labl) + elif labl.owner == nil: + labl.owner = c.p.owner n.sons[0] = newSymNode(labl, n.sons[0].info) suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym) styleCheckDef(c.config, labl) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 5ec702257..df6298eb0 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -626,6 +626,14 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode = # It doesn't matter if the argument is const or not for mLengthArray. # This fixes bug #544. result = newIntNodeT(lengthOrd(g.config, n.sons[1].typ), n, g) + of mSizeOf: + let size = getSize(g.config, n[1].typ) + if size >= 0: + result = newIntNode(nkIntLit, size) + result.info = n.info + result.typ = getSysType(g, n.info, tyInt) + else: + result = nil of mAstToStr: result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, g) of mConStrStr: diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 17f61c7dd..09991048e 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -116,7 +116,7 @@ proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) = var x = PSym(idTableGet(symMap, s)) if x != nil: n.sym = x - elif s.owner.kind == skPackage: + elif s.owner == nil or s.owner.kind == skPackage: #echo "copied this ", s.name.s x = copySym(s) x.owner = owner diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index df2c084a1..7e61854b8 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -321,8 +321,6 @@ proc semOf(c: PContext, n: PNode): PNode = proc magicsAfterOverloadResolution(c: PContext, n: PNode, flags: TExprFlags): PNode = ## This is the preferred code point to implement magics. - ## This function basically works like a macro, with the difference - ## that it is implemented in the compiler and not on the nimvm. ## ``c`` the current module, a symbol table to a very good approximation ## ``n`` the ast like it would be passed to a real macro ## ``flags`` Some flags for more contextual information on how the diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 48aa75528..04fe91cfb 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -497,8 +497,10 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var v = semIdentDef(c, a.sons[j], symkind) styleCheckDef(c.config, v) onDef(a[j].info, v) - if sfGenSym notin v.flags and not isDiscardUnderscore(v): - addInterfaceDecl(c, v) + if sfGenSym notin v.flags: + if not isDiscardUnderscore(v): addInterfaceDecl(c, v) + else: + if v.owner == nil: v.owner = c.p.owner when oKeepVariableNames: if c.inUnrolledContext > 0: v.flags.incl(sfShadowed) else: @@ -573,6 +575,7 @@ proc semConst(c: PContext, n: PNode): PNode = setVarType(c, v, typ) v.ast = def # no need to copy if sfGenSym notin v.flags: addInterfaceDecl(c, v) + elif v.owner == nil: v.owner = getCurrOwner(c) var b = newNodeI(nkConstDef, a.info) if importantComments(c.config): b.comment = a.comment addSon(b, newSymNode(v)) @@ -616,6 +619,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = v.typ = iterBase n.sons[0] = newSymNode(v) if sfGenSym notin v.flags: addForVarDecl(c, v) + elif v.owner == nil: v.owner = getCurrOwner(c) else: localError(c.config, n.info, errWrongNumberOfVariables) elif length-2 != sonsLen(iter): @@ -626,8 +630,9 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal) v.typ = iter.sons[i] n.sons[i] = newSymNode(v) - if sfGenSym notin v.flags and not isDiscardUnderscore(v): - addForVarDecl(c, v) + if sfGenSym notin v.flags: + if not isDiscardUnderscore(v): addForVarDecl(c, v) + elif v.owner == nil: v.owner = getCurrOwner(c) inc(c.p.nestedLoopCounter) openScope(c) n.sons[length-1] = semExprBranch(c, n.sons[length-1], flags) @@ -922,6 +927,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = s = typsym # add it here, so that recursive types are possible: if sfGenSym notin s.flags: addInterfaceDecl(c, s) + elif s.owner == nil: s.owner = getCurrOwner(c) if name.kind == nkPragmaExpr: a.sons[0].sons[0] = newSymNode(s) @@ -1620,7 +1626,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, else: s.typ.callConv = lastOptionEntry(c).defaultCC # add it here, so that recursive procs are possible: - if sfGenSym in s.flags: discard + if sfGenSym in s.flags: + if s.owner == nil: s.owner = getCurrOwner(c) elif kind in OverloadableSyms: if not typeIsDetermined: addInterfaceOverloadableSymAt(c, oldScope, s) @@ -1836,17 +1843,33 @@ proc semMacroDef(c: PContext, n: PNode): PNode = if n.sons[bodyPos].kind == nkEmpty: localError(c.config, n.info, errImplOfXexpected % s.name.s) +proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult: PNode) = + var f = checkModuleName(c.config, it) + if f != InvalidFileIDX: + if containsOrIncl(c.includedFiles, f.int): + localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f)) + else: + addSon(includeStmtResult, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f), {})) + excl(c.includedFiles, f.int) + proc evalInclude(c: PContext, n: PNode): PNode = result = newNodeI(nkStmtList, n.info) addSon(result, n) for i in countup(0, sonsLen(n) - 1): - var f = checkModuleName(c.config, n.sons[i]) - if f != InvalidFileIDX: - if containsOrIncl(c.includedFiles, f.int): - localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f)) - else: - addSon(result, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f), {})) - excl(c.includedFiles, f.int) + var imp: PNode + let it = n.sons[i] + if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket: + let sep = it[0] + let dir = it[1] + imp = newNodeI(nkInfix, it.info) + imp.add sep + imp.add dir + imp.add sep # dummy entry, replaced in the loop + for x in it[2]: + imp.sons[2] = x + incMod(c, n, imp, result) + else: + incMod(c, n, it, result) proc setLine(n: PNode, info: TLineInfo) = for i in 0 ..< safeLen(n): setLine(n.sons[i], info) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index a011a8fc8..f4ff97ba4 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -90,6 +90,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = if sonsLen(v) == 2: strVal = v.sons[1] # second tuple part is the string value if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}: + if not isOrdinalType(v.sons[0].typ): + localError(c.config, v.sons[0].info, errOrdinalTypeExpected) x = getOrdValue(v.sons[0]) # first tuple part is the ordinal else: localError(c.config, strVal.info, errStringLiteralExpected) @@ -99,6 +101,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = strVal = v x = counter else: + if not isOrdinalType(v.typ): + localError(c.config, v.info, errOrdinalTypeExpected) x = getOrdValue(v) if i != 1: if x != counter: incl(result.flags, tfEnumHasHoles) @@ -821,7 +825,11 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = a.typ = nn.typ addDecl(c, a) else: - if sfGenSym notin param.flags: addDecl(c, param) + if sfGenSym in param.flags: + # bug #XXX, fix the gensym'ed parameters owner: + if param.owner == nil: + param.owner = getCurrOwner(c) + else: addDecl(c, param) template shouldHaveMeta(t) = internalAssert c.config, tfHasMeta in t.flags diff --git a/koch.nim b/koch.nim index 9a8d38a79..bd10224b6 100644 --- a/koch.nim +++ b/koch.nim @@ -79,6 +79,7 @@ template withDir(dir, body) = finally: setCurrentdir(old) +let origDir = getCurrentDir() setCurrentDir(getAppDir()) proc tryExec(cmd: string): bool = @@ -415,6 +416,7 @@ proc temp(args: string) = let nimexec = findNim() exec(nimexec & " c -d:debug --debugger:native " & bootArgs & " " & (d / "compiler" / "nim"), 125) copyExe(output, finalDest) + setCurrentDir(origDir) if programArgs.len > 0: exec(finalDest & " " & programArgs) proc xtemp(cmd: string) = diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index aef4f1ce6..36319a317 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1513,8 +1513,217 @@ proc poll*(timeout = 500) = ## `epoll`:idx: or `kqueue`:idx: primitive only once. discard runOnce(timeout) -# Common procedures between current and upcoming asyncdispatch -include includes/asynccommon +template createAsyncNativeSocketImpl(domain, sockType, protocol) = + let handle = newNativeSocket(domain, sockType, protocol) + if handle == osInvalidSocket: + return osInvalidSocket.AsyncFD + handle.setBlocking(false) + when defined(macosx) and not defined(nimdoc): + handle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1) + result = handle.AsyncFD + register(result) + +proc createAsyncNativeSocket*(domain: cint, sockType: cint, + protocol: cint): AsyncFD = + createAsyncNativeSocketImpl(domain, sockType, protocol) + +proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET, + sockType: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP): AsyncFD = + createAsyncNativeSocketImpl(domain, sockType, protocol) + +proc newAsyncNativeSocket*(domain: cint, sockType: cint, + protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} = + createAsyncNativeSocketImpl(domain, sockType, protocol) + +proc newAsyncNativeSocket*(domain: Domain = Domain.AF_INET, + sockType: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP): AsyncFD + {.deprecated: "use createAsyncNativeSocket instead".} = + createAsyncNativeSocketImpl(domain, sockType, protocol) + +when defined(windows) or defined(nimdoc): + proc bindToDomain(handle: SocketHandle, domain: Domain) = + # Extracted into a separate proc, because connect() on Windows requires + # the socket to be initially bound. + template doBind(saddr) = + if bindAddr(handle, cast[ptr SockAddr](addr(saddr)), + sizeof(saddr).SockLen) < 0'i32: + raiseOSError(osLastError()) + + if domain == Domain.AF_INET6: + var saddr: Sockaddr_in6 + saddr.sin6_family = uint16(toInt(domain)) + doBind(saddr) + else: + var saddr: Sockaddr_in + saddr.sin_family = uint16(toInt(domain)) + doBind(saddr) + + proc doConnect(socket: AsyncFD, addrInfo: ptr AddrInfo): Future[void] = + let retFuture = newFuture[void]("doConnect") + result = retFuture + + var ol = PCustomOverlapped() + GC_ref(ol) + ol.data = CompletionData(fd: socket, cb: + proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) = + if not retFuture.finished: + if errcode == OSErrorCode(-1): + retFuture.complete() + else: + retFuture.fail(newException(OSError, osErrorMsg(errcode))) + ) + + let ret = connectEx(socket.SocketHandle, addrInfo.ai_addr, + cint(addrInfo.ai_addrlen), nil, 0, nil, + cast[POVERLAPPED](ol)) + if ret: + # Request to connect completed immediately. + retFuture.complete() + # We don't deallocate ``ol`` here because even though this completed + # immediately poll will still be notified about its completion and it + # will free ``ol``. + else: + let lastError = osLastError() + if lastError.int32 != ERROR_IO_PENDING: + # With ERROR_IO_PENDING ``ol`` will be deallocated in ``poll``, + # and the future will be completed/failed there, too. + GC_unref(ol) + retFuture.fail(newException(OSError, osErrorMsg(lastError))) +else: + proc doConnect(socket: AsyncFD, addrInfo: ptr AddrInfo): Future[void] = + let retFuture = newFuture[void]("doConnect") + result = retFuture + + proc cb(fd: AsyncFD): bool = + let ret = SocketHandle(fd).getSockOptInt( + cint(SOL_SOCKET), cint(SO_ERROR)) + if ret == 0: + # We have connected. + retFuture.complete() + return true + elif ret == EINTR: + # interrupted, keep waiting + return false + else: + retFuture.fail(newException(OSError, osErrorMsg(OSErrorCode(ret)))) + return true + + let ret = connect(socket.SocketHandle, + addrInfo.ai_addr, + addrInfo.ai_addrlen.Socklen) + if ret == 0: + # Request to connect completed immediately. + retFuture.complete() + else: + let lastError = osLastError() + if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS: + addWrite(socket, cb) + else: + retFuture.fail(newException(OSError, osErrorMsg(lastError))) + +template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped, + protocol: Protocol = IPPROTO_RAW) = + ## Iterates through the AddrInfo linked list asynchronously + ## until the connection can be established. + const shouldCreateFd = not declared(fd) + + when shouldCreateFd: + let sockType = protocol.toSockType() + + var fdPerDomain: array[low(Domain).ord..high(Domain).ord, AsyncFD] + for i in low(fdPerDomain)..high(fdPerDomain): + fdPerDomain[i] = osInvalidSocket.AsyncFD + template closeUnusedFds(domainToKeep = -1) {.dirty.} = + for i, fd in fdPerDomain: + if fd != osInvalidSocket.AsyncFD and i != domainToKeep: + fd.closeSocket() + + var lastException: ref Exception + var curAddrInfo = addrInfo + var domain: Domain + when shouldCreateFd: + var curFd: AsyncFD + else: + var curFd = fd + proc tryNextAddrInfo(fut: Future[void]) {.gcsafe.} = + if fut == nil or fut.failed: + if fut != nil: + lastException = fut.readError() + + while curAddrInfo != nil: + let domainOpt = curAddrInfo.ai_family.toKnownDomain() + if domainOpt.isSome: + domain = domainOpt.unsafeGet() + break + curAddrInfo = curAddrInfo.ai_next + + if curAddrInfo == nil: + freeAddrInfo(addrInfo) + when shouldCreateFd: + closeUnusedFds() + if lastException != nil: + retFuture.fail(lastException) + else: + retFuture.fail(newException( + IOError, "Couldn't resolve address: " & address)) + return + + when shouldCreateFd: + curFd = fdPerDomain[ord(domain)] + if curFd == osInvalidSocket.AsyncFD: + try: + curFd = newAsyncNativeSocket(domain, sockType, protocol) + except: + freeAddrInfo(addrInfo) + closeUnusedFds() + raise getCurrentException() + when defined(windows): + curFd.SocketHandle.bindToDomain(domain) + fdPerDomain[ord(domain)] = curFd + + doConnect(curFd, curAddrInfo).callback = tryNextAddrInfo + curAddrInfo = curAddrInfo.ai_next + else: + freeAddrInfo(addrInfo) + when shouldCreateFd: + closeUnusedFds(ord(domain)) + retFuture.complete(curFd) + else: + retFuture.complete() + + tryNextAddrInfo(nil) + +proc dial*(address: string, port: Port, + protocol: Protocol = IPPROTO_TCP): Future[AsyncFD] = + ## Establishes connection to the specified ``address``:``port`` pair via the + ## specified protocol. The procedure iterates through possible + ## resolutions of the ``address`` until it succeeds, meaning that it + ## seamlessly works with both IPv4 and IPv6. + ## Returns the async file descriptor, registered in the dispatcher of + ## the current thread, ready to send or receive data. + let retFuture = newFuture[AsyncFD]("dial") + result = retFuture + let sockType = protocol.toSockType() + + let aiList = getAddrInfo(address, port, Domain.AF_UNSPEC, sockType, protocol) + asyncAddrInfoLoop(aiList, noFD, protocol) + +proc connect*(socket: AsyncFD, address: string, port: Port, + domain = Domain.AF_INET): Future[void] = + let retFuture = newFuture[void]("connect") + result = retFuture + + when defined(windows): + verifyPresence(socket) + else: + assert getSockDomain(socket.SocketHandle) == domain + + let aiList = getAddrInfo(address, port, domain) + when defined(windows): + socket.SocketHandle.bindToDomain(domain) + asyncAddrInfoLoop(aiList, socket) proc sleepAsync*(ms: int | float): Future[void] = ## Suspends the execution of the current async procedure for the next diff --git a/lib/pure/includes/asynccommon.nim b/lib/pure/includes/asynccommon.nim deleted file mode 100644 index 13887acc9..000000000 --- a/lib/pure/includes/asynccommon.nim +++ /dev/null @@ -1,211 +0,0 @@ -template createAsyncNativeSocketImpl(domain, sockType, protocol) = - let handle = newNativeSocket(domain, sockType, protocol) - if handle == osInvalidSocket: - return osInvalidSocket.AsyncFD - handle.setBlocking(false) - when defined(macosx) and not defined(nimdoc): - handle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1) - result = handle.AsyncFD - register(result) - -proc createAsyncNativeSocket*(domain: cint, sockType: cint, - protocol: cint): AsyncFD = - createAsyncNativeSocketImpl(domain, sockType, protocol) - -proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET, - sockType: SockType = SOCK_STREAM, - protocol: Protocol = IPPROTO_TCP): AsyncFD = - createAsyncNativeSocketImpl(domain, sockType, protocol) - -proc newAsyncNativeSocket*(domain: cint, sockType: cint, - protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} = - createAsyncNativeSocketImpl(domain, sockType, protocol) - -proc newAsyncNativeSocket*(domain: Domain = Domain.AF_INET, - sockType: SockType = SOCK_STREAM, - protocol: Protocol = IPPROTO_TCP): AsyncFD - {.deprecated: "use createAsyncNativeSocket instead".} = - createAsyncNativeSocketImpl(domain, sockType, protocol) - -when defined(windows) or defined(nimdoc): - proc bindToDomain(handle: SocketHandle, domain: Domain) = - # Extracted into a separate proc, because connect() on Windows requires - # the socket to be initially bound. - template doBind(saddr) = - if bindAddr(handle, cast[ptr SockAddr](addr(saddr)), - sizeof(saddr).SockLen) < 0'i32: - raiseOSError(osLastError()) - - if domain == Domain.AF_INET6: - var saddr: Sockaddr_in6 - saddr.sin6_family = uint16(toInt(domain)) - doBind(saddr) - else: - var saddr: Sockaddr_in - saddr.sin_family = uint16(toInt(domain)) - doBind(saddr) - - proc doConnect(socket: AsyncFD, addrInfo: ptr AddrInfo): Future[void] = - let retFuture = newFuture[void]("doConnect") - result = retFuture - - var ol = PCustomOverlapped() - GC_ref(ol) - ol.data = CompletionData(fd: socket, cb: - proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) = - if not retFuture.finished: - if errcode == OSErrorCode(-1): - retFuture.complete() - else: - retFuture.fail(newException(OSError, osErrorMsg(errcode))) - ) - - let ret = connectEx(socket.SocketHandle, addrInfo.ai_addr, - cint(addrInfo.ai_addrlen), nil, 0, nil, - cast[POVERLAPPED](ol)) - if ret: - # Request to connect completed immediately. - retFuture.complete() - # We don't deallocate ``ol`` here because even though this completed - # immediately poll will still be notified about its completion and it - # will free ``ol``. - else: - let lastError = osLastError() - if lastError.int32 != ERROR_IO_PENDING: - # With ERROR_IO_PENDING ``ol`` will be deallocated in ``poll``, - # and the future will be completed/failed there, too. - GC_unref(ol) - retFuture.fail(newException(OSError, osErrorMsg(lastError))) -else: - proc doConnect(socket: AsyncFD, addrInfo: ptr AddrInfo): Future[void] = - let retFuture = newFuture[void]("doConnect") - result = retFuture - - proc cb(fd: AsyncFD): bool = - let ret = SocketHandle(fd).getSockOptInt( - cint(SOL_SOCKET), cint(SO_ERROR)) - if ret == 0: - # We have connected. - retFuture.complete() - return true - elif ret == EINTR: - # interrupted, keep waiting - return false - else: - retFuture.fail(newException(OSError, osErrorMsg(OSErrorCode(ret)))) - return true - - let ret = connect(socket.SocketHandle, - addrInfo.ai_addr, - addrInfo.ai_addrlen.Socklen) - if ret == 0: - # Request to connect completed immediately. - retFuture.complete() - else: - let lastError = osLastError() - if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS: - addWrite(socket, cb) - else: - retFuture.fail(newException(OSError, osErrorMsg(lastError))) - -template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped, - protocol: Protocol = IPPROTO_RAW) = - ## Iterates through the AddrInfo linked list asynchronously - ## until the connection can be established. - const shouldCreateFd = not declared(fd) - - when shouldCreateFd: - let sockType = protocol.toSockType() - - var fdPerDomain: array[low(Domain).ord..high(Domain).ord, AsyncFD] - for i in low(fdPerDomain)..high(fdPerDomain): - fdPerDomain[i] = osInvalidSocket.AsyncFD - template closeUnusedFds(domainToKeep = -1) {.dirty.} = - for i, fd in fdPerDomain: - if fd != osInvalidSocket.AsyncFD and i != domainToKeep: - fd.closeSocket() - - var lastException: ref Exception - var curAddrInfo = addrInfo - var domain: Domain - when shouldCreateFd: - var curFd: AsyncFD - else: - var curFd = fd - proc tryNextAddrInfo(fut: Future[void]) {.gcsafe.} = - if fut == nil or fut.failed: - if fut != nil: - lastException = fut.readError() - - while curAddrInfo != nil: - let domainOpt = curAddrInfo.ai_family.toKnownDomain() - if domainOpt.isSome: - domain = domainOpt.unsafeGet() - break - curAddrInfo = curAddrInfo.ai_next - - if curAddrInfo == nil: - freeAddrInfo(addrInfo) - when shouldCreateFd: - closeUnusedFds() - if lastException != nil: - retFuture.fail(lastException) - else: - retFuture.fail(newException( - IOError, "Couldn't resolve address: " & address)) - return - - when shouldCreateFd: - curFd = fdPerDomain[ord(domain)] - if curFd == osInvalidSocket.AsyncFD: - try: - curFd = newAsyncNativeSocket(domain, sockType, protocol) - except: - freeAddrInfo(addrInfo) - closeUnusedFds() - raise getCurrentException() - when defined(windows): - curFd.SocketHandle.bindToDomain(domain) - fdPerDomain[ord(domain)] = curFd - - doConnect(curFd, curAddrInfo).callback = tryNextAddrInfo - curAddrInfo = curAddrInfo.ai_next - else: - freeAddrInfo(addrInfo) - when shouldCreateFd: - closeUnusedFds(ord(domain)) - retFuture.complete(curFd) - else: - retFuture.complete() - - tryNextAddrInfo(nil) - -proc dial*(address: string, port: Port, - protocol: Protocol = IPPROTO_TCP): Future[AsyncFD] = - ## Establishes connection to the specified ``address``:``port`` pair via the - ## specified protocol. The procedure iterates through possible - ## resolutions of the ``address`` until it succeeds, meaning that it - ## seamlessly works with both IPv4 and IPv6. - ## Returns the async file descriptor, registered in the dispatcher of - ## the current thread, ready to send or receive data. - let retFuture = newFuture[AsyncFD]("dial") - result = retFuture - let sockType = protocol.toSockType() - - let aiList = getAddrInfo(address, port, Domain.AF_UNSPEC, sockType, protocol) - asyncAddrInfoLoop(aiList, noFD, protocol) - -proc connect*(socket: AsyncFD, address: string, port: Port, - domain = Domain.AF_INET): Future[void] = - let retFuture = newFuture[void]("connect") - result = retFuture - - when defined(windows): - verifyPresence(socket) - else: - assert getSockDomain(socket.SocketHandle) == domain - - let aiList = getAddrInfo(address, port, domain) - when defined(windows): - socket.SocketHandle.bindToDomain(domain) - asyncAddrInfoLoop(aiList, socket) diff --git a/tests/destructor/tmatrix.nim b/tests/destructor/tmatrix.nim index a16bfa37b..b89b41a4c 100644 --- a/tests/destructor/tmatrix.nim +++ b/tests/destructor/tmatrix.nim @@ -52,6 +52,8 @@ proc matrix*(m, n: int, s: float): Matrix = for i in 0 ..< m * n: result.data[i] = s +proc len(m: Matrix): int = m.n * m.m + proc `[]`*(m: Matrix, i, j: int): float {.inline.} = ## Get a single element. m.data[i * m.n + j] @@ -67,24 +69,26 @@ proc `[]=`*(m: var Matrix, i, j: int, s: float) = proc `-`*(m: sink Matrix): Matrix = ## Unary minus result = m - for i in 0 ..< m.m: - for j in 0 ..< m.n: - result[i, j] = -m[i, j] + for i in 0 ..< result.m: + for j in 0 ..< result.n: + result[i, j] = -result[i, j] proc `+`*(a: sink Matrix; b: Matrix): Matrix = ## ``C = A + B`` - assert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.") + doAssert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.") + doAssert(a.len == b.len) # non destructive use before sink is ok result = a - for i in 0 ..< a.m: - for j in 0 ..< a.n: - result[i, j] = a[i, j] + b[i, j] + for i in 0 ..< result.m: + for j in 0 ..< result.n: + result[i, j] = result[i, j] + b[i, j] proc `-`*(a: sink Matrix; b: Matrix): Matrix = ## ``C = A - B`` assert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.") + doAssert(a.len == b.len) # non destructive use before sink is ok result = a - for i in 0 ..< a.m: - for j in 0 ..< a.n: + for i in 0 ..< result.m: + for j in 0 ..< result.n: result[i, j] = a[i, j] - b[i, j] proc info = diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim index 26cc682b5..51aba1592 100644 --- a/tests/destructor/tmove_objconstr.nim +++ b/tests/destructor/tmove_objconstr.nim @@ -109,7 +109,19 @@ proc myfunc(x, y: int): (MySeqNonCopyable, MySeqNonCopyable) = proc myfunc2(x, y: int): tuple[a: MySeqNonCopyable, b:int, c:MySeqNonCopyable] = var cc = newMySeq(y, 5.0) - (a: newMySeq(x, 1.0), b:0, c: cc) + (a: case x: + of 1: + let (z1, z2) = myfunc(x,y) + z2 + elif x > 5: raise newException(ValueError, "new error") + else: newMySeq(x, 1.0), + b: 0, + c: block: + var tmp = if y > 0: move(cc) else: newMySeq(1, 3.0) + tmp[0] = 5 + tmp + ) + let (seq1, seq2) = myfunc(2, 3) doAssert seq1.len == 2 @@ -122,4 +134,35 @@ doAssert seq3.len == 2 doAssert seq3[0] == 1.0 var seq4, seq5: MySeqNonCopyable -(seq4, i, seq5) = myfunc2(2, 3) \ No newline at end of file +(seq4, i, seq5) = myfunc2(2, 3) + +seq4 = block: + var tmp = newMySeq(4, 1.0) + tmp[0] = 3.0 + tmp + +doAssert seq4[0] == 3.0 + +import macros + +seq4 = + if i > 0: newMySeq(2, 5.0) + elif i < -100: raise newException(ValueError, "Parse Error") + else: newMySeq(2, 3.0) + +seq4 = + case (char) i: + of 'A', {'W'..'Z'}: newMySeq(2, 5.0) + of 'B': quit(-1) + else: + let (x1, x2, x3) = myfunc2(2, 3) + x3 + + +#------------------------------------------------------------ +#-- Move into array constructor +#------------------------------------------------------------ + +var ii = 1 +let arr2 = [newMySeq(2, 5.0), if i > 1: newMySeq(3, 1.0) else: newMySeq(0, 0.0)] +var seqOfSeq2 = @[newMySeq(2, 5.0), newMySeq(3, 1.0)] diff --git a/tests/errmsgs/t9908_01.nim b/tests/errmsgs/t9908_01.nim new file mode 100644 index 000000000..b9d37b67b --- /dev/null +++ b/tests/errmsgs/t9908_01.nim @@ -0,0 +1,10 @@ +discard """ +errormsg: "ordinal type expected" +line: 10 +""" + +# https://github.com/nim-lang/Nim/issues/9908 + +type + X = enum + a = ("a", "b") diff --git a/tests/errmsgs/t9908_02.nim b/tests/errmsgs/t9908_02.nim new file mode 100644 index 000000000..7ff3d1ff7 --- /dev/null +++ b/tests/errmsgs/t9908_02.nim @@ -0,0 +1,10 @@ +discard """ +errormsg: "ordinal type expected" +line: 10 +""" + +# https://github.com/nim-lang/Nim/pull/9909#issuecomment-445519287 + +type + E = enum + myVal = 80.9 diff --git a/tests/misc/tsizeof2.nim b/tests/misc/tsizeof2.nim index 4252142d7..130f28e21 100644 --- a/tests/misc/tsizeof2.nim +++ b/tests/misc/tsizeof2.nim @@ -13,3 +13,5 @@ echo i # bug #9868 proc foo(a: SomeInteger): array[sizeof(a), byte] = discard + +discard foo(1) diff --git a/tests/modules/m9627/a.nim b/tests/modules/m9627/a.nim new file mode 100644 index 000000000..0dd32430e --- /dev/null +++ b/tests/modules/m9627/a.nim @@ -0,0 +1 @@ +var a = 10 diff --git a/tests/modules/m9627/b.nim b/tests/modules/m9627/b.nim new file mode 100644 index 000000000..2806a78ed --- /dev/null +++ b/tests/modules/m9627/b.nim @@ -0,0 +1 @@ +var b = 9 diff --git a/tests/modules/t9627.nim b/tests/modules/t9627.nim new file mode 100644 index 000000000..daba46374 --- /dev/null +++ b/tests/modules/t9627.nim @@ -0,0 +1,7 @@ +discard """ + output: "109" +""" + +include m9627 / [a, b] + +echo a, b diff --git a/tests/pragmas/tused.nim b/tests/pragmas/tused.nim index 83c62b7bb..dce854146 100644 --- a/tests/pragmas/tused.nim +++ b/tests/pragmas/tused.nim @@ -31,5 +31,11 @@ block: implementArithOpsNew(int) echoAdd 3, 5 +# issue #9896 +type + MyEnum {.used.} = enum + Val1, Val2, Val3 + + static: echo "compile end" diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim index da86d63dc..91fa26596 100644 --- a/tests/template/tparams_gensymed.nim +++ b/tests/template/tparams_gensymed.nim @@ -70,3 +70,43 @@ proc genericProc(x: any) = concreteProc(7) # This works genericProc(7) # This doesn't compile + +import tables + +# bug #9476 +proc getTypeInfo*(T: typedesc): pointer = + var dummy: T + getTypeInfo(dummy) + + +macro implementUnary(op: untyped): untyped = + result = newStmtList() + + template defineTable(tableSymbol) = + var tableSymbol = initTable[pointer, pointer]() + let tableSymbol = genSym(nskVar, "registeredProcs") + result.add(getAst(defineTable(tableSymbol))) + + template defineRegisterInstantiation(tableSym, regTemplSym, instSym, op) = + template regTemplSym*(T: typedesc) = + let ti = getTypeInfo(T) + + proc instSym(xOrig: int): int {.gensym, cdecl.} = + let x {.inject.} = xOrig + op + + tableSym[ti] = cast[pointer](instSym) + + let regTemplSymbol = ident("registerInstantiation") + let instSymbol = ident("instantiation") + result.add(getAst(defineRegisterInstantiation( + tableSymbol, regTemplSymbol, instSymbol, op + ))) + + echo result.repr + + +implementUnary(): x*x + +registerInstantiation(int) +registerInstantiation(float) |