diff --git a/changelog.md b/changelog.md index 82736d09a1c5..c010714fa10b 100644 --- a/changelog.md +++ b/changelog.md @@ -15,6 +15,8 @@ will no longer compile. - `internalNew` is removed from system, use `new` instead. +- `bindMethod` in `std/jsffi` is deprecated, don't use it with closures. + ## Standard library additions and changes [//]: # "Changes:" diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 0c0573ef082b..1d4f5519a0ed 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -106,12 +106,10 @@ type optionsStack: seq[TOptions] module: BModule g: PGlobals - generatedParamCopies: IntSet beforeRetNeeded: bool unique: int # for temp identifier generation blocks: seq[TBlock] extraIndent: int - up: PProc # up the call chain; required for closure support declaredGlobals: IntSet previousFileName: string # For frameInfo inside templates. @@ -119,12 +117,7 @@ template config*(p: PProc): ConfigRef = p.module.config proc indentLine(p: PProc, r: Rope): Rope = var p = p - var ind = 0 - while true: - inc ind, p.blocks.len + p.extraIndent - if p.up == nil or p.up.prc != p.prc.owner: - break - p = p.up + let ind = p.blocks.len + p.extraIndent result = repeat(' ', ind*2) & r template line(p: PProc, added: string) = @@ -843,6 +836,11 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = gen(p, n[1], x) gen(p, n[2], y) r.res = "($# == $# && $# == $#)" % [x.address, y.address, x.res, y.res] + of mEqProc: + if skipTypes(n[1].typ, abstractInst).callConv == ccClosure: + binaryExpr(p, n, r, "cmpClosures", "cmpClosures($1, $2)") + else: + arithAux(p, n, r, op) else: arithAux(p, n, r, op) r.kind = resExpr @@ -1204,8 +1202,16 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) = lineF(p, "}$n", []) line(p, repeat('}', toClose) & "\L") -proc generateHeader(p: PProc, typ: PType): Rope = +proc generateHeader(p: PProc, prc: PSym): Rope = result = "" + let typ = prc.typ + if typ.callConv == ccClosure: + # we treat Env as the `this` parameter of the function + # to keep it simple + let env = prc.ast[paramsPos].lastSon + assert env.kind == nkSym, "env is missing" + env.sym.loc.r = "this" + for i in 1..= 3: # echo "BEGIN generating code for: " & prc.name.s var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options) - p.up = oldProc var returnStmt: Rope = "" var resultAsgn: Rope = "" var name = mangleName(p.module, prc) - let header = generateHeader(p, prc.typ) + let header = generateHeader(p, prc) if prc.typ.returnType != nil and sfPure notin prc.flags: resultSym = prc.ast[resultPos].sym let mname = mangleName(p.module, resultSym) @@ -2918,7 +2914,15 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = genInfixCall(p, n, r) else: genCall(p, n, r) - of nkClosure: gen(p, n[0], r) + of nkClosure: + let tmp = getTemp(p) + var a: TCompRes = default(TCompRes) + var b: TCompRes = default(TCompRes) + gen(p, n[0], a) + gen(p, n[1], b) + lineF(p, "$1 = $2.bind($3); $1.ClP_0 = $2; $1.ClE_0 = $3;$n", [tmp, a.rdLoc, b.rdLoc]) + r.res = tmp + r.kind = resVal of nkCurly: genSetConstr(p, n, r) of nkBracket: genArrayConstr(p, n, r) of nkPar, nkTupleConstr: genTupleConstr(p, n, r) @@ -2950,9 +2954,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = let s = n[namePos].sym discard mangleName(p.module, s) r.res = s.loc.r - if s.kind == skIterator and s.typ.callConv == TCallingConvention.ccClosure: - globalError(p.config, n.info, "Closure iterators are not supported by JS backend!") - elif lfNoDecl in s.loc.flags or s.magic notin generatedMagics: discard + if lfNoDecl in s.loc.flags or s.magic notin generatedMagics: discard elif not p.g.generatedSyms.containsOrIncl(s.id): p.locals.add(genProc(p, s)) of nkType: r.res = genTypeInfo(p, n.typ) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 4db7471f14f8..4dea4d6c5e57 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -239,11 +239,6 @@ proc interestingIterVar(s: PSym): bool {.inline.} = template isIterator*(owner: PSym): bool = owner.kind == skIterator and owner.typ.callConv == ccClosure -proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} = - ## lambda lifting can be harmful for JS-like code generators. - let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro - result = conf.backend == backendJs and not isCompileTime - proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; idgen: IdGenerator; owner: PSym) = if owner.kind != skMacro: createTypeBoundOps(g, nil, refType.elementType, info, idgen) @@ -260,7 +255,6 @@ proc genCreateEnv(env: PNode): PNode = proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode = # transforms (iter) to (let env = newClosure[iter](); (iter, env)) - if liftingHarmful(g.config, owner): return n let iter = n.sym assert iter.isIterator @@ -883,14 +877,9 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType; proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool; idgen: IdGenerator; flags: TransformFlags): PNode = - # XXX backend == backendJs does not suffice! The compiletime stuff needs - # the transformation even when compiling to JS ... - - # However we can do lifting for the stuff which is *only* compiletime. let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro - if body.kind == nkEmpty or ( - g.config.backend == backendJs and not isCompileTime) or + if body.kind == nkEmpty or (fn.skipGenericOwner.kind != skModule and force notin flags): # ignore forward declaration: @@ -950,7 +939,6 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym): break ... """ - if liftingHarmful(g.config, owner): return body if not (body.kind == nkForStmt and body[^2].kind in nkCallKinds): localError(g.config, body.info, "ignored invalid for loop") return body diff --git a/compiler/transf.nim b/compiler/transf.nim index 4e6ca27f8693..070443b828a6 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -511,7 +511,6 @@ proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode = # we cannot generate a proper thunk here for GC-safety reasons # (see internal documentation): - if c.graph.config.backend == backendJs: return prc result = newNodeIT(nkClosure, prc.info, dest) var conv = newNodeIT(nkHiddenSubConv, prc.info, dest) conv.add(newNodeI(nkEmpty, prc.info)) diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim index 08b1c6db9ebb..d50d58ae5117 100644 --- a/lib/js/jsffi.nim +++ b/lib/js/jsffi.nim @@ -468,7 +468,7 @@ proc replaceSyms(n: NimNode): NimNode = for i in 0..