diff --git a/compiler/ast.nim b/compiler/ast.nim index bdb8d1c23e..51319127c5 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -263,7 +263,7 @@ type sfNamedParamCall, # symbol needs named parameter call syntax in target # language; for interfacing with Objective C sfDiscardable, # returned value may be discarded implicitly - sfDestructor, # proc is destructor + sfOverriden, # proc is overriden sfGenSym # symbol is 'gensym'ed; do not add to symbol table TSymFlags* = set[TSymFlag] @@ -785,12 +785,13 @@ type # the body of the user-defined type class # formal param list # else: unused - destructor*: PSym # destructor. warning: nil here may not necessary - # mean that there is no destructor. - # see instantiateDestructor in types.nim owner*: PSym # the 'owner' of the type sym*: PSym # types have the sym associated with them # it is used for converting types to strings + destructor*: PSym # destructor. warning: nil here may not necessary + # mean that there is no destructor. + # see instantiateDestructor in semdestruct.nim + deepCopy*: PSym # overriden 'deepCopy' operation size*: BiggestInt # the size of the type in bytes # -1 means that the size is unkwown align*: int # the type's alignment requirements @@ -1190,6 +1191,7 @@ proc assignType(dest, src: PType) = dest.size = src.size dest.align = src.align dest.destructor = src.destructor + dest.deepCopy = src.deepCopy # this fixes 'type TLock = TSysLock': if src.sym != nil: if dest.sym != nil: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 95167e1576..d5b2ad33d5 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -359,6 +359,32 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) else: internalError("genAssignment: " & $ty.kind) +proc genDeepCopy(p: BProc; dest, src: TLoc) = + var ty = skipTypes(dest.t, abstractRange) + case ty.kind + of tyPtr, tyRef, tyString, tyProc, tyTuple, tyObject, tyArray, tyArrayConstr: + # XXX optimize this + linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", + addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)) + of tySequence: + linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n", + addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t)) + of tyOpenArray, tyVarargs: + linefmt(p, cpsStmts, + "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len0, $3);$n", + addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)) + of tySet: + if mapType(ty) == ctArray: + useStringh(p.module) + linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n", + rdLoc(dest), rdLoc(src), toRope(getSize(dest.t))) + else: + linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) + of tyPointer, tyChar, tyBool, tyEnum, tyCString, + tyInt..tyUInt64, tyRange, tyVar: + linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) + else: internalError("genDeepCopy: " & $ty.kind) + proc getDestLoc(p: BProc, d: var TLoc, typ: PType) = if d.k == locNone: getTemp(p, typ, d) @@ -1578,25 +1604,25 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mGetTypeInfo: genGetTypeInfo(p, e, d) of mSwap: genSwap(p, e, d) of mUnaryLt: - if not (optOverflowCheck in p.options): unaryExpr(p, e, d, "$1 - 1") + if optOverflowCheck notin p.options: unaryExpr(p, e, d, "$1 - 1") else: unaryExpr(p, e, d, "#subInt($1, 1)") of mPred: # XXX: range checking? - if not (optOverflowCheck in p.options): binaryExpr(p, e, d, "$1 - $2") + if optOverflowCheck notin p.options: binaryExpr(p, e, d, "$1 - $2") else: binaryExpr(p, e, d, "#subInt($1, $2)") of mSucc: # XXX: range checking? - if not (optOverflowCheck in p.options): binaryExpr(p, e, d, "$1 + $2") + if optOverflowCheck notin p.options: binaryExpr(p, e, d, "$1 + $2") else: binaryExpr(p, e, d, "#addInt($1, $2)") of mInc: - if not (optOverflowCheck in p.options): + if optOverflowCheck notin p.options: binaryStmt(p, e, d, "$1 += $2;$n") elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64: binaryStmt(p, e, d, "$1 = #addInt64($1, $2);$n") else: binaryStmt(p, e, d, "$1 = #addInt($1, $2);$n") of ast.mDec: - if not (optOverflowCheck in p.options): + if optOverflowCheck notin p.options: binaryStmt(p, e, d, "$1 -= $2;$n") elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64: binaryStmt(p, e, d, "$1 = #subInt64($1, $2);$n") @@ -1659,6 +1685,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mParallel: let n = semparallel.liftParallel(p.module.module, e) expr(p, n, d) + of mDeepCopy: + var a, b: TLoc + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) + genDeepCopy(p, a, b) else: internalError(e.info, "genMagicExpr: " & $op) proc genConstExpr(p: BProc, n: PNode): PRope @@ -1878,7 +1909,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of skVar, skForVar, skResult, skLet: if sfGlobal in sym.flags: genVarPrototype(p.module, sym) if sym.loc.r == nil or sym.loc.t == nil: - internalError(n.info, "expr: var not init " & sym.name.s) + internalError n.info, "expr: var not init " & sym.name.s & "_" & $sym.id if sfThread in sym.flags: accessThreadLocalVar(p, sym) if emulatedThreadVars(): @@ -1893,7 +1924,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = putLocIntoDest(p, d, sym.loc) of skParam: if sym.loc.r == nil or sym.loc.t == nil: - internalError(n.info, "expr: param not init " & sym.name.s) + #echo "FAILED FOR PRCO ", p.prc.name.s + internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id) putLocIntoDest(p, d, sym.loc) else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol") of nkNilLit: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 8e762ce279..4c71c6ff79 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -453,7 +453,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope, appf(result, " {$n", [name]) var desc = getRecordFields(m, typ, check) - if (desc == nil) and not hasField: + if desc == nil and not hasField: appf(result, "char dummy;$n", []) else: app(result, desc) @@ -895,11 +895,20 @@ type include ccgtrav -proc genTypeInfo(m: BModule, t: PType): PRope = +proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) = + genProc(m, s) + appf(m.s[cfsTypeInit3], "$1.deepcopy = (N_NIMCALL_PTR(void*, void*)) $2;$n", + [result, s.loc.r]) + +proc genTypeInfo(m: BModule, t: PType): PRope = + let origType = t var t = getUniqueType(t) result = ropef("NTI$1", [toRope(t.id)]) if containsOrIncl(m.typeInfoMarker, t.id): return con("(&".toRope, result, ")".toRope) + + # getUniqueType doesn't skip tyDistinct when that has an overriden operation: + while t.kind == tyDistinct: t = t.lastSon let owner = t.skipTypes(typedescPtrs).owner.getModule if owner != m.module: # make sure the type info is created in the owner module @@ -936,6 +945,10 @@ proc genTypeInfo(m: BModule, t: PType): PRope = # results are not deterministic! genTupleInfo(m, t, result) else: internalError("genTypeInfo(" & $t.kind & ')') + if t.deepCopy != nil: + genDeepCopyProc(m, t.deepCopy, result) + elif origType.deepCopy != nil: + genDeepCopyProc(m, origType.deepCopy, result) result = con("(&".toRope, result, ")".toRope) proc genTypeSection(m: BModule, n: PNode) = diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 04983d6a4f..6af6a857c6 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -89,8 +89,10 @@ proc getUniqueType*(key: PType): PType = of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor: internalError("GetUniqueType") - of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, - tyConst, tyIter, tyStatic: + of tyDistinct: + if key.deepCopy != nil: result = key + else: result = getUniqueType(lastSon(key)) + of tyGenericInst, tyOrdinal, tyMutable, tyConst, tyIter, tyStatic: result = getUniqueType(lastSon(key)) of tyArrayConstr, tyGenericInvokation, tyGenericBody, tyOpenArray, tyArray, tySet, tyRange, tyTuple, diff --git a/compiler/cgen.nim b/compiler/cgen.nim index e2f3b5ab0a..b930bea8d4 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -295,6 +295,7 @@ proc postStmtActions(p: BProc) {.inline.} = proc accessThreadLocalVar(p: BProc, s: PSym) proc emulatedThreadVars(): bool {.inline.} +proc genProc(m: BModule, prc: PSym) include "ccgtypes.nim" @@ -574,7 +575,6 @@ proc fixLabel(p: BProc, labl: TLabel) = proc genVarPrototype(m: BModule, sym: PSym) proc requestConstImpl(p: BProc, sym: PSym) -proc genProc(m: BModule, prc: PSym) proc genStmts(p: BProc, t: PNode) proc expr(p: BProc, n: PNode, d: var TLoc) proc genProcPrototype(m: BModule, sym: PSym) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 5b61a9cae9..1f1a7647b4 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -122,8 +122,8 @@ proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode = if t == nil: break t = t.skipTypes(abstractInst) #if field == nil: + # echo "FIELD ", b # debug deref.typ - # echo deref.typ.id internalAssert field != nil addSon(deref, a) result = newNodeI(nkDotExpr, info) @@ -202,7 +202,8 @@ proc flowVarKind(t: PType): TFlowVarKind = elif containsGarbageCollectedRef(t): fvInvalid else: fvBlob -proc addLocalVar(varSection: PNode; owner: PSym; typ: PType; v: PNode): PSym = +proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType; + v: PNode): PSym = result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info) result.typ = typ incl(result.flags, sfFromGeneric) @@ -210,8 +211,15 @@ proc addLocalVar(varSection: PNode; owner: PSym; typ: PType; v: PNode): PSym = var vpart = newNodeI(nkIdentDefs, varSection.info, 3) vpart.sons[0] = newSymNode(result) vpart.sons[1] = ast.emptyNode - vpart.sons[2] = v + vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode varSection.add vpart + if varInit != nil: + let deepCopyCall = newNodeI(nkCall, varInit.info, 3) + deepCopyCall.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy)) + deepCopyCall.sons[1] = newSymNode(result) + deepCopyCall.sons[2] = v + deepCopyCall.typ = typ + varInit.add deepCopyCall discard """ We generate roughly this: @@ -244,24 +252,25 @@ stmtList: """ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; - varSection, call, barrier, fv: PNode; + varSection, varInit, call, barrier, fv: PNode; spawnKind: TSpawnResult): PSym = var body = newNodeI(nkStmtList, f.info) var threadLocalBarrier: PSym if barrier != nil: var varSection = newNodeI(nkVarSection, barrier.info) - threadLocalBarrier = addLocalVar(varSection, argsParam.owner, + threadLocalBarrier = addLocalVar(varSection, nil, argsParam.owner, barrier.typ, barrier) body.add varSection body.add callCodeGenProc("barrierEnter", threadLocalBarrier.newSymNode) var threadLocalProm: PSym if spawnKind == srByVar: - threadLocalProm = addLocalVar(varSection, argsParam.owner, fv.typ, fv) + threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv) elif fv != nil: internalAssert fv.typ.kind == tyGenericInst - threadLocalProm = addLocalVar(varSection, argsParam.owner, fv.typ, fv) - - body.add varSection + threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv) + if barrier == nil: + body.add varSection + body.add varInit if fv != nil and spawnKind != srByVar: # generate: # fv.owner = threadParam @@ -314,7 +323,8 @@ proc createCastExpr(argsParam: PSym; objType: PType): PNode = result.typ.rawAddSon(objType) proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym, - castExpr, call, varSection, result: PNode) = + castExpr, call, + varSection, varInit, result: PNode) = let formals = n[0].typ.n let tmpName = getIdent(genPrefix) for i in 1 .. ", importc: "printf", varargs.} Note that this pragma is somewhat of a misnomer: Other backends will provide -the same feature under the same name. Also, if you are interfacing with C++ -you can use the `ImportCpp pragma `_ and +the same feature under the same name. Also, if one is interfacing with C++ +the `ImportCpp pragma `_ and interfacing with Objective-C the `ImportObjC pragma -`_. +`_ can be used. Exportc pragma @@ -5781,12 +5842,14 @@ used instead. `spawn`:idx: is used to pass a task to the thread pool: Currently the expression that ``spawn`` takes is however quite restricted: -* It must be a call expresion ``f(a, ...)``. +* It must be a call expression ``f(a, ...)``. * ``f`` must be ``gcsafe``. * ``f`` must not have the calling convention ``closure``. -* ``f``'s parameters may not be of type ``var`` nor may they contain ``ref``. - This means you have to use raw ``ptr``'s for data passing reminding the +* ``f``'s parameters may not be of type ``var``. + This means one has to use raw ``ptr``'s for data passing reminding the programmer to be careful. +* ``ref`` parameters are deeply copied which is a subtle semantic change and + can cause performance problems but ensures memory safety. * For *safe* data exchange between ``f`` and the caller a global ``TChannel`` needs to be used. Other means will be provided soon. diff --git a/lib/system.nim b/lib/system.nim index 753205777e..3e4d3fb9e7 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2997,10 +2997,13 @@ proc locals*(): TObject {.magic: "Locals", noSideEffect.} = ## # -> B is 1 discard -proc deepCopy*[T](x: T): T {.magic: "DeepCopy", noSideEffect.} = - ## performs a deep copy of `x`. This is also used by the code generator - ## for the implementation of ``spawn``. - discard +when hostOS != "standalone" and not defined(NimrodVM) and not defined(JS): + proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} = + ## performs a deep copy of `x`. This is also used by the code generator + ## for the implementation of ``spawn``. + discard + + include "system/deepcopy" {.pop.} #{.push warning[GcMem]: off.} diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim new file mode 100644 index 0000000000..d3f9c5d7c9 --- /dev/null +++ b/lib/system/deepcopy.nim @@ -0,0 +1,121 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) {.gcsafe.} +proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode) {.gcsafe.} = + var + d = cast[TAddress](dest) + s = cast[TAddress](src) + case n.kind + of nkSlot: + genericDeepCopyAux(cast[pointer](d +% n.offset), + cast[pointer](s +% n.offset), n.typ) + of nkList: + for i in 0..n.len-1: + genericDeepCopyAux(dest, src, n.sons[i]) + of nkCase: + var dd = selectBranch(dest, n) + var m = selectBranch(src, n) + # reset if different branches are in use; note different branches also + # imply that's not self-assignment (``x = x``)! + if m != dd and dd != nil: + genericResetAux(dest, dd) + copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset), + n.typ.size) + if m != nil: + genericDeepCopyAux(dest, src, m) + of nkNone: sysAssert(false, "genericDeepCopyAux") + +proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) = + var + d = cast[TAddress](dest) + s = cast[TAddress](src) + sysAssert(mt != nil, "genericDeepCopyAux 2") + case mt.kind + of tyString: + var x = cast[PPointer](dest) + var s2 = cast[PPointer](s)[] + if s2 == nil: + unsureAsgnRef(x, s2) + else: + unsureAsgnRef(x, copyString(cast[NimString](s2))) + of tySequence: + var s2 = cast[PPointer](src)[] + var seq = cast[PGenericSeq](s2) + var x = cast[PPointer](dest) + if s2 == nil: + unsureAsgnRef(x, s2) + return + sysAssert(dest != nil, "genericDeepCopyAux 3") + unsureAsgnRef(x, newSeq(mt, seq.len)) + var dst = cast[TAddress](cast[PPointer](dest)[]) + for i in 0..seq.len-1: + genericDeepCopyAux( + cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), + cast[pointer](cast[TAddress](s2) +% i *% mt.base.size +% + GenericSeqSize), + mt.base) + of tyObject: + # we need to copy m_type field for tyObject, as it could be empty for + # sequence reallocations: + var pint = cast[ptr PNimType](dest) + pint[] = cast[ptr PNimType](src)[] + if mt.base != nil: + genericDeepCopyAux(dest, src, mt.base) + genericDeepCopyAux(dest, src, mt.node) + of tyTuple: + genericDeepCopyAux(dest, src, mt.node) + of tyArray, tyArrayConstr: + for i in 0..(mt.size div mt.base.size)-1: + genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size), + cast[pointer](s +% i*% mt.base.size), mt.base) + of tyRef: + var z: pointer + if mt.base.deepCopy != nil: + z = mt.base.deepCopy(cast[PPointer](s)[]) + else: + # we modify the header of the cell temporarily; instead of the type + # field we store a forwarding pointer. XXX This is bad when the cloning + # fails due to OOM etc. + let x = usrToCell(cast[PPointer](s)[]) + let forw = cast[int](x.typ) + if (forw and 1) == 1: + # we stored a forwarding pointer, so let's use that: + z = cast[pointer](forw and not 1) + else: + let realType = x.typ + z = newObj(realType, realType.base.size) + x.typ = cast[PNimType](cast[int](z) or 1) + genericDeepCopyAux(dest, addr(z), realType) + x.typ = realType + unsureAsgnRef(cast[PPointer](dest), z) + of tyPtr: + # no cycle check here, but also not really required + if mt.base.deepCopy != nil: + cast[PPointer](dest)[] = mt.base.deepCopy(cast[PPointer](s)[]) + else: + cast[PPointer](dest)[] = cast[PPointer](s)[] + else: + copyMem(dest, src, mt.size) # copy raw bits + +proc genericDeepCopy(dest, src: pointer, mt: PNimType) {.compilerProc.} = + genericDeepCopyAux(dest, src, mt) + +proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerProc.} = + var src = src + genericDeepCopy(dest, addr(src), mt) + +proc genericDeepCopyOpenArray(dest, src: pointer, len: int, + mt: PNimType) {.compilerproc.} = + var + d = cast[TAddress](dest) + s = cast[TAddress](src) + for i in 0..len-1: + genericDeepCopy(cast[pointer](d +% i*% mt.base.size), + cast[pointer](s +% i*% mt.base.size), mt.base) diff --git a/lib/system/hti.nim b/lib/system/hti.nim index 64174e60f1..5689f92b36 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -86,6 +86,7 @@ type node: ptr TNimNode # valid for tyRecord, tyObject, tyTuple, tyEnum finalizer: pointer # the finalizer for the type marker: proc (p: pointer, op: int) {.nimcall, gcsafe.} # marker proc for GC + deepcopy: proc (p: pointer): pointer {.nimcall, gcsafe.} PNimType = ptr TNimType # node.len may be the ``first`` element of a set diff --git a/tests/destructor/tdestructor.nim b/tests/destructor/tdestructor.nim index e5236aaab3..f0ea3c5c67 100644 --- a/tests/destructor/tdestructor.nim +++ b/tests/destructor/tdestructor.nim @@ -55,14 +55,14 @@ type q: TMyGeneric3[TMyObj, int, int] r: string -proc destruct(o: var TMyObj) {.destructor.} = +proc destroy(o: var TMyObj) {.override.} = if o.p != nil: dealloc o.p echo "myobj destroyed" -proc destroy(o: var TMyGeneric1) {.destructor.} = +proc destroy(o: var TMyGeneric1) {.override.} = echo "mygeneric1 destroyed" -proc destroy[A, B](o: var TMyGeneric2[A, B]) {.destructor.} = +proc destroy[A, B](o: var TMyGeneric2[A, B]) {.override.} = echo "mygeneric2 destroyed" proc open: TMyObj = diff --git a/tests/destructor/tdestructor2.nim b/tests/destructor/tdestructor2.nim index da9192a3f9..a5b62860ca 100644 --- a/tests/destructor/tdestructor2.nim +++ b/tests/destructor/tdestructor2.nim @@ -8,7 +8,7 @@ type x, y: int p: pointer -proc destruct(o: var TMyObj) {.destructor.} = +proc destroy(o: var TMyObj) {.override.} = if o.p != nil: dealloc o.p proc open: TMyObj = diff --git a/todo.txt b/todo.txt index bd8f7f89e4..6ae5df509c 100644 --- a/todo.txt +++ b/todo.txt @@ -3,20 +3,26 @@ version 0.9.6 - scopes are still broken for generic instantiation! - start experimental branch -- overloading of '='; general lift mechanism +- implicit deref for parameter matching Concurrency ----------- - 'gcsafe' inferrence needs to be fixed +- 'deepCopy' needs to be instantiated for + generics *when the type is constructed* +- test 'deepCopy' +- overloading of '='; general lift mechanism + - the disjoint checker needs to deal with 'a = spawn f(); g = spawn f()' -- implement 'deepCopy' builtin - implement 'foo[1..4] = spawn(f[4..7])' -- support for exception propagation -- Minor: The copying of the 'ref Promise' into the thead local storage only +- document the new 'spawn' and 'parallel' statements + +Low priority: +- support for exception propagation? (hard to implement) +- the copying of the 'ref Promise' into the thead local storage only happens to work due to the write barrier's implementation - implement lock levels --> first without the more complex race avoidance -- document the new 'spawn' and 'parallel' statements Misc @@ -27,8 +33,6 @@ Misc - fix the tuple unpacking in lambda bug - make tuple unpacking work in a non-var/let context - special rule for ``[]=`` -- ``=`` should be overloadable; requires specialization for ``=``; general - lift mechanism in the compiler is already implemented for 'fields' - built-in 'getImpl' - type API for macros; make 'spawn' a macro - markAndSweepGC should expose an API for fibers @@ -57,13 +61,9 @@ version 0.9.x - implement 'bits' pragmas - we need a magic thisModule symbol - provide --nilChecks:on|off -- fix closures/lambdalifting - ensure (ref T)(a, b) works as a type conversion and type constructor - optimize 'genericReset'; 'newException' leads to code bloat - stack-less GC -- implicit deref for parameter matching - -- VM: optimize opcAsgnStr version 0.9.X diff --git a/web/news.txt b/web/news.txt index 62a923dcd5..3aca10692c 100644 --- a/web/news.txt +++ b/web/news.txt @@ -20,6 +20,14 @@ News representation. - ``uri.TUrl`` as well as the ``parseurl`` module are now deprecated in favour of the new ``TUri`` type in the ``uri`` module. + - The ``destructor`` pragma has been deprecated. Use the ``override`` pragma + instead. The destructor's name has to be ``destroy`` now. + + Language Additions + ------------------ + + - There is a new ``parallel`` statement for safe fork&join parallel computing. + Library Additions -----------------