diff --git a/changelog.md b/changelog.md index e17b24b428..1310b6ae3f 100644 --- a/changelog.md +++ b/changelog.md @@ -14,6 +14,11 @@ rounding guarantees (via the ## Standard library additions and changes +[//]: # "Additions:" +- `setutils.symmetricDifference` along with its operator version + `` setutils.`-+-` `` and in-place version `setutils.toggle` have been added + to more efficiently calculate the symmetric difference of bitsets. + [//]: # "Changes:" - `std/math` The `^` symbol now supports floating-point as exponent in addition to the Natural type. diff --git a/compiler/ast.nim b/compiler/ast.nim index 9708252f0e..5ff986776c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -491,7 +491,7 @@ type mAnd, mOr, mImplies, mIff, mExists, mForall, mOld, mEqStr, mLeStr, mLtStr, - mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, + mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mXorSet, mConStrStr, mSlice, mDotDot, # this one is only necessary to give nice compile time warnings mFields, mFieldPairs, mOmpParFor, @@ -559,7 +559,7 @@ const mStrToStr, mEnumToStr, mAnd, mOr, mEqStr, mLeStr, mLtStr, - mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, + mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mXorSet, mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mInSet, mRepr, mOpenArrayToSeq} diff --git a/compiler/cbuilderdecls.nim b/compiler/cbuilderdecls.nim index 1c54a85eb3..d17869ac80 100644 --- a/compiler/cbuilderdecls.nim +++ b/compiler/cbuilderdecls.nim @@ -89,6 +89,17 @@ template addTypedef(builder: var Builder, name: string, typeBody: typed) = builder.add(name) builder.add(";\n") +template addArrayTypedef(builder: var Builder, name: string, len: int, typeBody: typed) = + ## adds an array typedef declaration to the builder with name `name`, + ## length `len`, and element type as built in `typeBody` + builder.add("typedef ") + typeBody + builder.add(" ") + builder.add(name) + builder.add("[") + builder.addInt(len) + builder.add("];\n") + type StructInitializerKind = enum siOrderedStruct ## struct constructor, but without named fields on C diff --git a/compiler/cbuilderexprs.nim b/compiler/cbuilderexprs.nim index f381944ecc..0fda722ce5 100644 --- a/compiler/cbuilderexprs.nim +++ b/compiler/cbuilderexprs.nim @@ -1,4 +1,5 @@ # XXX make complex ones like bitOr use builder instead +# XXX add stuff like NI, NIM_NIL as constants proc ptrType(t: Snippet): Snippet = t & "*" diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 3f4e4ff763..c954e6057b 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2044,7 +2044,7 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) = proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = const - lookupOpr: array[mLeSet..mMinusSet, string] = [ + lookupOpr: array[mLeSet..mXorSet, string] = [ "for ($1 = 0; $1 < $2; $1++) { $n" & " $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & " if (!$3) break;}$n", @@ -2054,7 +2054,8 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = "if ($3) $3 = (#nimCmpMem($4, $5, $2) != 0);$n", "&", "|", - "& ~"] + "& ~", + "^"] var a, b: TLoc var i: TLoc var setType = skipTypes(e[1].typ, abstractVar) @@ -2085,6 +2086,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mMulSet: binaryExpr(p, e, d, "($1 & $2)") of mPlusSet: binaryExpr(p, e, d, "($1 | $2)") of mMinusSet: binaryExpr(p, e, d, "($1 & ~ $2)") + of mXorSet: binaryExpr(p, e, d, "($1 ^ $2)") of mInSet: genInOp(p, e, d) else: internalError(p.config, e.info, "genSetOp()") @@ -2112,7 +2114,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = var a = initLocExpr(p, e[1]) var b = initLocExpr(p, e[2]) putIntoDest(p, d, e, ropecg(p.module, "(#nimCmpMem($1, $2, $3)==0)", [a.rdCharLoc, b.rdCharLoc, size])) - of mMulSet, mPlusSet, mMinusSet: + of mMulSet, mPlusSet, mMinusSet, mXorSet: # we inline the simple for loop for better code generation: i = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) # our counter a = initLocExpr(p, e[1]) @@ -2548,7 +2550,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mSetLengthStr: genSetLengthStr(p, e, d) of mSetLengthSeq: genSetLengthSeq(p, e, d) of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet, - mInSet: + mInSet, mXorSet: genSetOp(p, e, d, op) of mNewString, mNewStringOfCap, mExit, mParseBiggestFloat: var opr = e[0].sym diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 2337c70e63..361475e55e 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -373,6 +373,7 @@ proc getTypePre(m: BModule; typ: PType; sig: SigHash): Rope = if result == "": result = cacheGetType(m.typeCache, sig) proc addForwardStructFormat(m: BModule; structOrUnion: Rope, typename: Rope) = + # XXX should be no-op in NIFC if m.compileToCpp: m.s[cfsForwardTypes].addf "$1 $2;$n", [structOrUnion, typename] else: @@ -923,17 +924,28 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes (sfImportc in t.sym.flags and t.sym.magic == mNone)): m.typeCache[sig] = result var size: int + var typedef = newBuilder("") if firstOrd(m.config, t) < 0: - m.s[cfsTypes].addf("typedef NI32 $1;$n", [result]) + typedef.addTypedef(name = result): + typedef.add("NI32") size = 4 else: size = int(getSize(m.config, t)) case size - of 1: m.s[cfsTypes].addf("typedef NU8 $1;$n", [result]) - of 2: m.s[cfsTypes].addf("typedef NU16 $1;$n", [result]) - of 4: m.s[cfsTypes].addf("typedef NI32 $1;$n", [result]) - of 8: m.s[cfsTypes].addf("typedef NI64 $1;$n", [result]) + of 1: + typedef.addTypedef(name = result): + typedef.add("NU8") + of 2: + typedef.addTypedef(name = result): + typedef.add("NU16") + of 4: + typedef.addTypedef(name = result): + typedef.add("NI32") + of 8: + typedef.addTypedef(name = result): + typedef.add("NI64") else: internalError(m.config, t.sym.info, "getTypeDescAux: enum") + m.s[cfsTypes].add(typedef) when false: let owner = hashOwner(t.sym) if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner): @@ -993,7 +1005,10 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes m.typeCache[sig] = result if not isImportedType(t): let foo = getTypeDescAux(m, t.elementType, check, kind) - m.s[cfsTypes].addf("typedef $1 $2[1];$n", [foo, result]) + var typedef = newBuilder("") + typedef.addArrayTypedef(name = result, len = 1): + typedef.add(foo) + m.s[cfsTypes].add(typedef) of tyArray: var n: BiggestInt = toInt64(lengthOrd(m.config, t)) if n <= 0: n = 1 # make an array of at least one element @@ -1001,8 +1016,10 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes m.typeCache[sig] = result if not isImportedType(t): let e = getTypeDescAux(m, t.elementType, check, kind) - m.s[cfsTypes].addf("typedef $1 $2[$3];$n", - [e, result, rope(n)]) + var typedef = newBuilder("") + typedef.addArrayTypedef(name = result, len = n): + typedef.add(e) + m.s[cfsTypes].add(typedef) of tyObject, tyTuple: let tt = origTyp.skipTypes({tyDistinct}) if isImportedCppType(t) and tt.kind == tyGenericInst: @@ -1048,7 +1065,8 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes # with the C macros for defining procs such as N_NIMCALL. We must # create a typedef for the type and use it in the proc signature: let typedefName = "TY" & $sig - m.s[cfsTypes].addf("typedef $1 $2;$n", [result, typedefName]) + m.s[cfsTypes].addTypedef(name = typedefName): + m.s[cfsTypes].add(result) m.typeCache[sig] = typedefName result = typedefName else: @@ -1076,9 +1094,12 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes if not isImportedType(t): let s = int(getSize(m.config, t)) case s - of 1, 2, 4, 8: m.s[cfsTypes].addf("typedef NU$2 $1;$n", [result, rope(s*8)]) - else: m.s[cfsTypes].addf("typedef NU8 $1[$2];$n", - [result, rope(getSize(m.config, t))]) + of 1, 2, 4, 8: + m.s[cfsTypes].addTypedef(name = result): + m.s[cfsTypes].add("NU" & rope(s*8)) + else: + m.s[cfsTypes].addArrayTypedef(name = result, len = s): + m.s[cfsTypes].add("NU8") of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyOwned, tyUserTypeClass, tyUserTypeClassInst, tyInferred: result = getTypeDescAux(m, skipModifier(t), check, kind) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 4523081a63..81cc40f3f6 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -170,3 +170,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasGenericsOpenSym3") defineSymbol("nimHasJsNoLambdaLifting") defineSymbol("nimHasDefaultFloatRoundtrip") + defineSymbol("nimHasXorSet") diff --git a/compiler/docgen.nim b/compiler/docgen.nim index d457528217..2b25ded7df 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -830,7 +830,7 @@ proc getName(n: PNode): string = of nkAccQuoted: result = "`" for i in 0.. 1: + if n[1].kind == nkSym: n[1].sym + elif n[1].kind in nkSymChoices + {nkOpenSym} and n[1].len != 0: + n[1][0].sym + else: nil + else: nil + if s != nil and s.kind in routineKinds: + # this is a failed generic instantiation + # semSubscript should already error but this is better for cascading errors + result = explicitGenericInstError(c, n) + else: + bracketNotFoundError(c, x, flags) + result = errorNode(c, n) proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode = # rewrite `[]=`(a, i, x) back to ``a[i] = x``. diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index b76696230d..3538ea83cd 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -200,6 +200,9 @@ proc matchGenericParams*(m: var TCandidate, binding: PNode, callee: PSym) = elif tfImplicitTypeParam in paramSym.typ.flags: # not a mismatch, but can't create sym m.state = csEmpty + m.firstMismatch.kind = kMissingGenericParam + m.firstMismatch.arg = i + 1 + m.firstMismatch.formal = paramSym return else: m.state = csNoMatch diff --git a/compiler/vm.nim b/compiler/vm.nim index 1be04a922d..f26d41324f 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1276,6 +1276,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = createSet(regs[ra]) move(regs[ra].node.sons, nimsets.diffSets(c.config, regs[rb].node, regs[rc].node).sons) + of opcXorSet: + decodeBC(rkNode) + createSet(regs[ra]) + move(regs[ra].node.sons, + nimsets.symdiffSets(c.config, regs[rb].node, regs[rc].node).sons) of opcConcatStr: decodeBC(rkNode) createStr regs[ra] diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 42e58c63b8..bfa589402a 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -100,7 +100,7 @@ type opcEqRef, opcEqNimNode, opcSameNodeType, opcXor, opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt, opcEqStr, opcEqCString, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet, - opcMulSet, opcPlusSet, opcMinusSet, opcConcatStr, + opcMulSet, opcPlusSet, opcMinusSet, opcXorSet, opcConcatStr, opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq, opcIsNil, opcOf, opcIs, opcParseFloat, opcConv, opcCast, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index a40f0afe47..59b8bf17f7 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1212,6 +1212,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}, m: TMag of mMulSet: genBinarySet(c, n, dest, opcMulSet) of mPlusSet: genBinarySet(c, n, dest, opcPlusSet) of mMinusSet: genBinarySet(c, n, dest, opcMinusSet) + of mXorSet: genBinarySet(c, n, dest, opcXorSet) of mConStrStr: genVarargsABC(c, n, dest, opcConcatStr) of mInSet: genBinarySet(c, n, dest, opcContainsSet) of mRepr: genUnaryABC(c, n, dest, opcRepr) diff --git a/lib/js/jscore.nim b/lib/js/jscore.nim index be353875c8..f8c201ad90 100644 --- a/lib/js/jscore.nim +++ b/lib/js/jscore.nim @@ -77,10 +77,10 @@ proc newDate*(): DateTime {. proc newDate*(date: int|string): DateTime {. importcpp: "new Date(#)".} -whenJsNoBigInt64: +when jsNoBigInt64: proc newDate*(date: int64): DateTime {. importcpp: "new Date(#)".} -do: +else: proc newDate*(date: int64): DateTime {. importcpp: "new Date(Number(#))".} diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index d85c84a486..ca3ca12757 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -1095,7 +1095,21 @@ proc setprotoent*(a1: cint) {.importc, header: "".} proc setservent*(a1: cint) {.importc, header: "".} when not defined(lwip): - proc poll*(a1: ptr TPollfd, a2: Tnfds, a3: int): cint {. + # Linux and Haiku emulate SVR4, which used unsigned long. + # Meanwhile, BSD derivatives had used unsigned int; we will use this + # for the else case, because it is more widely cloned than SVR4's + # behavior. + when defined(linux) or defined(haiku): + type + Tnfds* {.importc: "nfds_t", header: "".} = culong + elif defined(zephyr): + type + Tnfds* = distinct cint + else: + type + Tnfds* {.importc: "nfds_t", header: "".} = cuint + + proc poll*(a1: ptr TPollfd, a2: Tnfds, a3: cint): cint {. importc, header: "", sideEffect.} proc realpath*(name, resolved: cstring): cstring {. diff --git a/lib/posix/posix_haiku.nim b/lib/posix/posix_haiku.nim index ba579778fa..6e325cb659 100644 --- a/lib/posix/posix_haiku.nim +++ b/lib/posix/posix_haiku.nim @@ -519,8 +519,6 @@ type events*: cshort ## The input event flags (see below). revents*: cshort ## The output event flags (see below). - Tnfds* {.importc: "nfds_t", header: "".} = culong - var errno* {.importc, header: "".}: cint ## error variable h_errno* {.importc, header: "".}: cint diff --git a/lib/posix/posix_linux_amd64.nim b/lib/posix/posix_linux_amd64.nim index 8d11c507d7..7a9126abed 100644 --- a/lib/posix/posix_linux_amd64.nim +++ b/lib/posix/posix_linux_amd64.nim @@ -563,8 +563,6 @@ type events*: cshort ## The input event flags (see below). revents*: cshort ## The output event flags (see below). - Tnfds* {.importc: "nfds_t", header: "".} = culong - var errno* {.importc, header: "".}: cint ## error variable h_errno* {.importc, header: "".}: cint diff --git a/lib/posix/posix_macos_amd64.nim b/lib/posix/posix_macos_amd64.nim index 59c4c65509..2b5dea69f4 100644 --- a/lib/posix/posix_macos_amd64.nim +++ b/lib/posix/posix_macos_amd64.nim @@ -533,8 +533,6 @@ type events*: cshort ## The input event flags (see below). revents*: cshort ## The output event flags (see below). - Tnfds* {.importc: "nfds_t", header: "".} = cint - var errno* {.importc, header: "".}: cint ## error variable h_errno* {.importc, header: "".}: cint diff --git a/lib/posix/posix_nintendoswitch.nim b/lib/posix/posix_nintendoswitch.nim index b66563695c..fdc4e590e4 100644 --- a/lib/posix/posix_nintendoswitch.nim +++ b/lib/posix/posix_nintendoswitch.nim @@ -484,8 +484,6 @@ type events*: cshort ## The input event flags (see below). revents*: cshort ## The output event flags (see below). - Tnfds* {.importc: "nfds_t", header: "".} = culong - var errno* {.importc, header: "".}: cint ## error variable h_errno* {.importc, header: "".}: cint diff --git a/lib/posix/posix_openbsd_amd64.nim b/lib/posix/posix_openbsd_amd64.nim index 555980ed78..9244ce78cc 100644 --- a/lib/posix/posix_openbsd_amd64.nim +++ b/lib/posix/posix_openbsd_amd64.nim @@ -517,8 +517,6 @@ type events*: cshort ## The input event flags (see below). revents*: cshort ## The output event flags (see below). - Tnfds* {.importc: "nfds_t", header: "".} = cint - var errno* {.importc, header: "".}: cint ## error variable h_errno* {.importc, header: "".}: cint diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 9804ab0ba6..6301216d4c 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -604,13 +604,6 @@ when not defined(lwip): events*: cshort ## The input event flags (see below). revents*: cshort ## The output event flags (see below). - when defined(zephyr): - type - Tnfds* = distinct cint - else: - type - Tnfds* {.importc: "nfds_t", header: "".} = cint - var errno* {.importc, header: "".}: cint ## error variable h_errno* {.importc, header: "".}: cint diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 1038d55a1e..cce8d2dbf6 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -65,7 +65,7 @@ runnableExamples: ## * `sha1 module `_ for the SHA-1 checksum algorithm ## * `tables module `_ for hash tables -import std/private/since +import std/private/[since, jsutils] when defined(nimPreviewSlimSystem): import std/assertions @@ -518,17 +518,10 @@ proc hashFarm(s: openArray[byte]): uint64 {.inline.} = swap z, x len16 len16(v[0],w[0],mul) + shiftMix(y)*k0 + z, len16(v[1],w[1],mul) + x, mul -template jsNoInt64: untyped = - when defined js: - when compiles(compileOption("jsbigint64")): - when not compileOption("jsbigint64"): true - else: false - else: false - else: false -const sHash2 = (when defined(nimStringHash2) or jsNoInt64(): true else: false) +const sHash2 = defined(nimStringHash2) or jsNoBigInt64 template maybeFailJS_Number = - when jsNoInt64() and not defined(nimStringHash2): + when jsNoBigInt64 and not defined(nimStringHash2): {.error: "Must use `-d:nimStringHash2` when using `--jsbigint64:off`".} proc hash*(x: string): Hash = diff --git a/lib/pure/ioselects/ioselectors_poll.nim b/lib/pure/ioselects/ioselectors_poll.nim index 7c53471563..6f50a5234d 100644 --- a/lib/pure/ioselects/ioselectors_poll.nim +++ b/lib/pure/ioselects/ioselectors_poll.nim @@ -231,7 +231,7 @@ proc selectInto*[T](s: Selector[T], timeout: int, verifySelectParams(timeout) s.withPollLock(): - let count = posix.poll(addr(s.pollfds[0]), Tnfds(s.pollcnt), timeout) + let count = posix.poll(addr(s.pollfds[0]), Tnfds(s.pollcnt), cint(timeout)) if count < 0: result = 0 let err = osLastError() diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 8ca1ab8259..6fecb8b8ef 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -211,7 +211,7 @@ when defined(nimHasStyleChecks): when defined(posix) and not defined(lwip): from std/posix import TPollfd, POLLIN, POLLPRI, POLLOUT, POLLWRBAND, Tnfds - template monitorPollEvent(x: var SocketHandle, y: cint, timeout: int): int = + template monitorPollEvent(x: var SocketHandle, y, timeout: cint): int = var tpollfd: TPollfd tpollfd.fd = cast[cint](x) tpollfd.events = y @@ -222,14 +222,14 @@ proc timeoutRead(fd: var SocketHandle, timeout = 500): int = var fds = @[fd] selectRead(fds, timeout) else: - monitorPollEvent(fd, POLLIN or POLLPRI, timeout) + monitorPollEvent(fd, POLLIN or POLLPRI, cint(timeout)) proc timeoutWrite(fd: var SocketHandle, timeout = 500): int = when defined(windows) or defined(lwip): var fds = @[fd] selectWrite(fds, timeout) else: - monitorPollEvent(fd, POLLOUT or POLLWRBAND, timeout) + monitorPollEvent(fd, POLLOUT or POLLWRBAND, cint(timeout)) proc socketError*(socket: Socket, err: int = -1, async = false, lastError = (-1).OSErrorCode, diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 0ff5878a5c..35c3f4364c 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -79,24 +79,13 @@ when defined(nimPreviewSlimSystem): include system/inclrtl {.push debugger: off.} -template whenHasBigInt64(yes64, no64): untyped = - when defined(js): - when compiles(compileOption("jsbigint64")): - when compileOption("jsbigint64"): - yes64 - else: - no64 - else: - no64 - else: - yes64 -whenHasBigInt64: +when hasWorkingInt64: type Ui = uint64 const randMax = 18_446_744_073_709_551_615u64 -do: +else: type Ui = uint32 const randMax = 4_294_967_295u32 @@ -118,14 +107,14 @@ type ## generator are **not** thread-safe! a0, a1: Ui -whenHasBigInt64: +when hasWorkingInt64: const DefaultRandSeed = Rand( a0: 0x69B4C98CB8530805u64, a1: 0xFED1DD3004688D67CAu64) # racy for multi-threading but good enough for now: var state = DefaultRandSeed # global for backwards compatibility -do: +else: var state = Rand( a0: 0x69B4C98Cu32, a1: 0xFED1DD30u32) # global for backwards compatibility @@ -221,9 +210,9 @@ proc skipRandomNumbers*(s: var Rand) = doAssert vals == [501737, 497901, 500683, 500157] - whenHasBigInt64: + when hasWorkingInt64: const helper = [0xbeac0467eba5facbu64, 0xd86b048b86aa9922u64] - do: + else: const helper = [0xbeac0467u32, 0xd86b048bu32] var s0 = Ui 0 @@ -359,9 +348,9 @@ proc rand*[T: Ordinal or SomeFloat](r: var Rand; x: HSlice[T, T]): T = when T is SomeFloat: result = rand(r, x.b - x.a) + x.a else: # Integers and Enum types - whenJsNoBigInt64: + when jsNoBigInt64: result = cast[T](rand(r, cast[uint](x.b) - cast[uint](x.a)) + cast[uint](x.a)) - do: + else: result = cast[T](rand(r, cast[uint64](x.b) - cast[uint64](x.a)) + cast[uint64](x.a)) proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T = @@ -402,9 +391,9 @@ proc rand*[T: Ordinal](r: var Rand; t: typedesc[T]): T {.since: (1, 7, 1).} = elif T is bool: result = r.next < randMax div 2 else: - whenJsNoBigInt64: + when jsNoBigInt64: result = cast[T](r.next shr (sizeof(uint)*8 - sizeof(T)*8)) - do: + else: result = cast[T](r.next shr (sizeof(uint64)*8 - sizeof(T)*8)) proc rand*[T: Ordinal](t: typedesc[T]): T = diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 81be7db179..818e23b15b 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -998,9 +998,9 @@ func toHex*[T: SomeInteger](x: T, len: Positive): string = doAssert b.toHex(4) == "1001" doAssert toHex(62, 3) == "03E" doAssert toHex(-8, 6) == "FFFFF8" - whenJsNoBigInt64: + when jsNoBigInt64: toHexImpl(cast[BiggestUInt](x), len, x < 0) - do: + else: when T is SomeSignedInt: toHexImpl(cast[BiggestUInt](BiggestInt(x)), len, x < 0) else: @@ -1011,9 +1011,9 @@ func toHex*[T: SomeInteger](x: T): string = runnableExamples: doAssert toHex(1984'i64) == "00000000000007C0" doAssert toHex(1984'i16) == "07C0" - whenJsNoBigInt64: + when jsNoBigInt64: toHexImpl(cast[BiggestUInt](x), 2*sizeof(T), x < 0) - do: + else: when T is SomeSignedInt: toHexImpl(cast[BiggestUInt](BiggestInt(x)), 2*sizeof(T), x < 0) else: diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 1d498e8739..b2f30b7a30 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -215,27 +215,29 @@ when defined(nimPreviewSlimSystem): when defined(js): import std/jscore + import std/private/jsutils - # This is really bad, but overflow checks are broken badly for - # ints on the JS backend. See #6752. - {.push overflowChecks: off.} - proc `*`(a, b: int64): int64 = - system.`*`(a, b) - proc `*`(a, b: int): int = - system.`*`(a, b) - proc `+`(a, b: int64): int64 = - system.`+`(a, b) - proc `+`(a, b: int): int = - system.`+`(a, b) - proc `-`(a, b: int64): int64 = - system.`-`(a, b) - proc `-`(a, b: int): int = - system.`-`(a, b) - proc inc(a: var int, b: int) = - system.inc(a, b) - proc inc(a: var int64, b: int) = - system.inc(a, b) - {.pop.} + when jsNoBigInt64: + # This is really bad, but overflow checks are broken badly for + # ints on the JS backend. See #6752. + {.push overflowChecks: off.} + proc `*`(a, b: int64): int64 = + system.`*`(a, b) + proc `*`(a, b: int): int = + system.`*`(a, b) + proc `+`(a, b: int64): int64 = + system.`+`(a, b) + proc `+`(a, b: int): int = + system.`+`(a, b) + proc `-`(a, b: int64): int64 = + system.`-`(a, b) + proc `-`(a, b: int): int = + system.`-`(a, b) + proc inc(a: var int, b: int) = + system.inc(a, b) + proc inc(a: var int64, b: int) = + system.inc(a, b) + {.pop.} elif defined(posix): import std/posix diff --git a/lib/std/private/jsutils.nim b/lib/std/private/jsutils.nim index 5f79eab278..9ba36d1a1b 100644 --- a/lib/std/private/jsutils.nim +++ b/lib/std/private/jsutils.nim @@ -83,14 +83,21 @@ when defined(js): assert 9007199254740991.toJs.isSafeInteger assert not 9007199254740992.toJs.isSafeInteger -template whenJsNoBigInt64*(no64, yes64): untyped = +const jsNoBigInt64* = when defined(js): when compiles(compileOption("jsbigint64")): - when compileOption("jsbigint64"): - yes64 - else: - no64 + not compileOption("jsbigint64") else: - no64 + true else: - no64 + false + +const hasWorkingInt64* = + # equal to `not jsNoBigInt64`, but define it by itself anyway + when defined(js): + when compiles(compileOption("jsbigint64")): + compileOption("jsbigint64") + else: + false + else: + true diff --git a/lib/std/setutils.nim b/lib/std/setutils.nim index 8e7bc6a92d..32a2e88f2c 100644 --- a/lib/std/setutils.nim +++ b/lib/std/setutils.nim @@ -75,3 +75,31 @@ func `[]=`*[T](t: var set[T], key: T, val: bool) {.inline.} = s[a3] = true assert s == {a2, a3} if val: t.incl key else: t.excl key + +when defined(nimHasXorSet): + func symmetricDifference*[T](x, y: set[T]): set[T] {.magic: "XorSet".} = + ## This operator computes the symmetric difference of two sets, + ## equivalent to but more efficient than `x + y - x * y` or + ## `(x - y) + (y - x)`. + runnableExamples: + assert symmetricDifference({1, 2, 3}, {2, 3, 4}) == {1, 4} +else: + func symmetricDifference*[T](x, y: set[T]): set[T] {.inline.} = + result = x + y - (x * y) + +proc `-+-`*[T](x, y: set[T]): set[T] {.inline.} = + ## Operator alias for `symmetricDifference`. + runnableExamples: + assert {1, 2, 3} -+- {2, 3, 4} == {1, 4} + result = symmetricDifference(x, y) + +proc toggle*[T](x: var set[T], y: set[T]) {.inline.} = + ## Toggles the existence of each value of `y` in `x`. + ## If any element in `y` is also in `x`, it is excluded from `x`; + ## otherwise it is included. + ## Equivalent to `x = symmetricDifference(x, y)`. + runnableExamples: + var x = {1, 2, 3} + x.toggle({2, 3, 4}) + assert x == {1, 4} + x = symmetricDifference(x, y) diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 5599240fdb..ec1af2ea57 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -337,6 +337,18 @@ proc SetMinus(a, b: int): int {.compilerproc, asmNoStackFrame.} = return result; """.} +proc SetXor(a, b: int): int {.compilerproc, asmNoStackFrame.} = + {.emit: """ + var result = {}; + for (var elem in `a`) { + if (!`b`[elem]) { result[elem] = true; } + } + for (var elem in `b`) { + if (!`a`[elem]) { result[elem] = true; } + } + return result; + """.} + proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerproc.} = {.emit: """ if (`a` == `b`) return 0; diff --git a/tests/generics/tpointerprocs.nim b/tests/generics/tpointerprocs.nim index 2bcaf15b36..29c4f2954f 100644 --- a/tests/generics/tpointerprocs.nim +++ b/tests/generics/tpointerprocs.nim @@ -2,10 +2,17 @@ discard """ cmd: "nim check $options --hints:off $file" action: "reject" nimout:''' -tpointerprocs.nim(15, 11) Error: 'foo' doesn't have a concrete type, due to unspecified generic parameters. -tpointerprocs.nim(27, 11) Error: cannot instantiate: 'foo[int]'; got 1 typeof(s) but expected 2 -tpointerprocs.nim(27, 14) Error: expression 'foo[int]' has no type (or is ambiguous) -tpointerprocs.nim(28, 11) Error: expression 'bar' has no type (or is ambiguous) +tpointerprocs.nim(22, 11) Error: 'foo' doesn't have a concrete type, due to unspecified generic parameters. +tpointerprocs.nim(34, 14) Error: type mismatch: got +but expected one of: +proc foo(x: int | float; y: int or string): float + first type mismatch at position: 2 in generic parameters + missing generic parameter: y:type + +expression: foo[int] +tpointerprocs.nim(34, 14) Error: cannot instantiate: 'foo[int]' +tpointerprocs.nim(34, 14) Error: expression 'foo[int]' has no type (or is ambiguous) +tpointerprocs.nim(35, 11) Error: expression 'bar' has no type (or is ambiguous) ''' """ @@ -25,4 +32,4 @@ block: proc foo(x: int | float, y: int or string): float = result = 1.0 let bar = foo[int] - baz = bar \ No newline at end of file + baz = bar diff --git a/tests/int/tints.nim b/tests/int/tints.nim index 773e8ccad6..b85a66b01b 100644 --- a/tests/int/tints.nim +++ b/tests/int/tints.nim @@ -27,8 +27,7 @@ template test(opr, a, b, c: untyped): untyped = test(`+`, 12'i8, -13'i16, -1'i16) test(`shl`, 0b11, 0b100, 0b110000) -whenJsNoBigInt64: discard -do: +when hasWorkingInt64: test(`shl`, 0b11'i64, 0b100'i64, 0b110000'i64) when not defined(js): # mixed type shr needlessly complicates codegen with bigint @@ -39,25 +38,21 @@ test(`shl`, 0b11'i32, 0b100'i32, 0b110000'i32) test(`or`, 0xf0f0'i16, 0x0d0d'i16, 0xfdfd'i16) test(`and`, 0xf0f0'i16, 0xfdfd'i16, 0xf0f0'i16) -whenJsNoBigInt64: discard -do: +when hasWorkingInt64: test(`shr`, 0xffffffffffffffff'i64, 0x4'i64, 0xffffffffffffffff'i64) test(`shr`, 0xffff'i16, 0x4'i16, 0xffff'i16) test(`shr`, 0xff'i8, 0x4'i8, 0xff'i8) -whenJsNoBigInt64: discard -do: +when hasWorkingInt64: test(`shr`, 0xffffffff'i64, 0x4'i64, 0x0fffffff'i64) test(`shr`, 0xffffffff'i32, 0x4'i32, 0xffffffff'i32) -whenJsNoBigInt64: discard -do: +when hasWorkingInt64: test(`shl`, 0xffffffffffffffff'i64, 0x4'i64, 0xfffffffffffffff0'i64) test(`shl`, 0xffff'i16, 0x4'i16, 0xfff0'i16) test(`shl`, 0xff'i8, 0x4'i8, 0xf0'i8) -whenJsNoBigInt64: discard -do: +when hasWorkingInt64: test(`shl`, 0xffffffff'i64, 0x4'i64, 0xffffffff0'i64) test(`shl`, 0xffffffff'i32, 0x4'i32, 0xfffffff0'i32) diff --git a/tests/js/ttypedarray.nim b/tests/js/ttypedarray.nim index 4807cb1033..ec10170f61 100644 --- a/tests/js/ttypedarray.nim +++ b/tests/js/ttypedarray.nim @@ -10,8 +10,7 @@ proc main()= doAssert fn(array[2, uint8].default) == "Uint8Array" doAssert fn(array[2, byte].default) == "Uint8Array" doAssert fn(array[2, char].default) == "Uint8Array" - whenJsNoBigInt64: discard - do: + when not jsNoBigInt64: doAssert fn(array[2, uint64].default) == "BigUint64Array" doAssert fn([1'u8]) == "Uint8Array" doAssert fn([1'u16]) == "Uint16Array" diff --git a/tests/lexer/tunary_minus.nim b/tests/lexer/tunary_minus.nim index 5ec2b5c70e..48e8c0375a 100644 --- a/tests/lexer/tunary_minus.nim +++ b/tests/lexer/tunary_minus.nim @@ -61,8 +61,7 @@ template main = doAssert -2147483648'i32 == int32.low when int.sizeof > 4: doAssert -9223372036854775808 == int.low - whenJsNoBigInt64: discard - do: + when hasWorkingInt64: doAssert -9223372036854775808 == int64.low block: # check when a minus (-) is an unary op diff --git a/tests/overload/tambiguousexplicitgeneric.nim b/tests/overload/tambiguousexplicitgeneric.nim new file mode 100644 index 0000000000..cc6e3dbe40 --- /dev/null +++ b/tests/overload/tambiguousexplicitgeneric.nim @@ -0,0 +1,6 @@ +# related to issue #8064 + +import tables + +let x = values[int] #[tt.Error + ^ ambiguous identifier: 'values' -- use one of the following:]# diff --git a/tests/overload/texplicitgenericdiscard.nim b/tests/overload/texplicitgenericdiscard.nim new file mode 100644 index 0000000000..1a207849b6 --- /dev/null +++ b/tests/overload/texplicitgenericdiscard.nim @@ -0,0 +1,7 @@ +# issue #8064 + +import tables + +values[int] #[tt.Error +^ ambiguous identifier: 'values' -- use one of the following:]# +# this happens before discard check, so no discard error diff --git a/tests/pragmas/thintprocessing.nim b/tests/pragmas/thintprocessing.nim index c608bc6e42..943d921669 100644 --- a/tests/pragmas/thintprocessing.nim +++ b/tests/pragmas/thintprocessing.nim @@ -3,7 +3,7 @@ discard """ matrix: "--hint:processing" nimout: ''' compile start -.. +... warn_module.nim(6, 6) Hint: 'test' is declared but not used [XDeclaredButNotUsed] compile end ''' diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim index e425501f69..c881bbe7e7 100644 --- a/tests/stdlib/tjson.nim +++ b/tests/stdlib/tjson.nim @@ -314,8 +314,7 @@ block: # bug #17383 else: testRoundtrip(int.high): "9223372036854775807" testRoundtrip(uint.high): "18446744073709551615" - whenJsNoBigInt64: discard - do: + when hasWorkingInt64: testRoundtrip(int64.high): "9223372036854775807" testRoundtrip(uint64.high): "18446744073709551615" diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim index eb32f77575..272e2e6ee2 100644 --- a/tests/stdlib/trandom.nim +++ b/tests/stdlib/trandom.nim @@ -225,8 +225,9 @@ block: # same as above but use slice overload doAssert a3.type is a2.type test cast[uint](int.high) test cast[uint](int.high) + 1 - whenJsNoBigInt64: discard - do: + when hasWorkingInt64 and defined(js): + # weirdly this has to run only in JS for the final int32.high test + # to be the same between C/C++ and --jsbigint64:on test uint64.high test uint64.high - 1 test uint.high - 2 diff --git a/tests/stdlib/tsetutils.nim b/tests/stdlib/tsetutils.nim index c8498f23e0..c3338a3a27 100644 --- a/tests/stdlib/tsetutils.nim +++ b/tests/stdlib/tsetutils.nim @@ -44,6 +44,26 @@ template main = s[a2] = true s[a3] = true doAssert s == {a2, a3} + + block: # set symmetric difference (xor), https://github.com/nim-lang/RFCs/issues/554 + type T = set[range[0..15]] + let x: T = {1, 4, 5, 8, 9} + let y: T = {0, 2..6, 9} + let res = symmetricDifference(x, y) + doAssert res == {0, 1, 2, 3, 6, 8} + doAssert res == (x + y - x * y) + doAssert res == ((x - y) + (y - x)) + var z = x + doAssert z == {1, 4, 5, 8, 9} + doAssert z == x + z.toggle(y) + doAssert z == res + z.toggle(y) + doAssert z == x + z.toggle({1, 5}) + doAssert z == {4, 8, 9} + z.toggle({3, 8}) + doAssert z == {3, 4, 9} main() static: main() diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index 35f6bc669b..0cabff8335 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -527,8 +527,7 @@ template main() = block: # toHex doAssert(toHex(100i16, 32) == "00000000000000000000000000000064") - whenJsNoBigInt64: discard - do: + when hasWorkingInt64: doAssert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") doAssert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF") doAssert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF") @@ -550,9 +549,8 @@ template main() = doAssert(spaces(0) == "") block: # toBin, toOct - whenJsNoBigInt64: # bug #11369 - discard - do: + when hasWorkingInt64: + # bug #11369 var num: int64 = -1 doAssert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111" doAssert num.toOct(24) == "001777777777777777777777" @@ -773,8 +771,7 @@ bar block: # formatSize disableVm: - whenJsNoBigInt64: discard - do: + when hasWorkingInt64: doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231 doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" doAssert formatSize(4096) == "4KiB" diff --git a/tests/system/tdollars.nim b/tests/system/tdollars.nim index eabee81b38..1135694f8b 100644 --- a/tests/system/tdollars.nim +++ b/tests/system/tdollars.nim @@ -66,8 +66,7 @@ block: # `$`(SomeInteger) testType int testType bool - whenJsNoBigInt64: discard - do: + when hasWorkingInt64: testType uint64 testType int64 testType BiggestInt @@ -177,8 +176,7 @@ proc main()= res.addInt int64(i) doAssert res == "-9-8-7-6-5-4-3-2-10" - whenJsNoBigInt64: discard - do: + when hasWorkingInt64: test2 high(int64), "9223372036854775807" test2 low(int64), "-9223372036854775808" test2 high(int32), "2147483647" diff --git a/tests/tools/tctags.nim b/tests/tools/tctags.nim new file mode 100644 index 0000000000..1bba3edf23 --- /dev/null +++ b/tests/tools/tctags.nim @@ -0,0 +1,16 @@ +discard """ + cmd: '''nim ctags --stdout $file''' + nimout: ''' +Foo +hello +`$$` +''' + action: "compile" +""" + +type + Foo = object + +proc hello() = discard + +proc `$`(x: Foo): string = "foo"