diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 7e8c251738fd1..0a7036b46f744 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -178,7 +178,7 @@ const proc mapType(typ: PType): TJSTypeKind = let t = skipTypes(typ, abstractInst) case t.kind - of tyVar, tyRef, tyPtr, tyLent: + of tyVar, tyRef, tyPtr: if skipTypes(t.lastSon, abstractInst).kind in MappedToObject: result = etyObject else: @@ -186,7 +186,8 @@ proc mapType(typ: PType): TJSTypeKind = of tyPointer: # treat a tyPointer like a typed pointer to an array of bytes result = etyBaseIndex - of tyRange, tyDistinct, tyOrdinal, tyProxy: + of tyRange, tyDistinct, tyOrdinal, tyProxy, tyLent: + # tyLent is no-op as JS has pass-by-reference semantics result = mapType(t[0]) of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt of tyBool: result = etyBool @@ -1060,14 +1061,14 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = xtyp = etySeq case xtyp of etySeq: - if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: + if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) else: useMagic(p, "nimCopy") lineF(p, "$1 = nimCopy(null, $2, $3);$n", [a.rdLoc, b.res, genTypeInfo(p, y.typ)]) of etyObject: - if x.typ.kind in {tyVar} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: + if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded: lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) else: useMagic(p, "nimCopy") @@ -1092,10 +1093,18 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res]) lineF(p, "$1 = $2;$n", [a.address, b.res]) lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) + elif a.typ == etyBaseIndex: + # array indexing may not map to var type + if b.address != nil: + lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res]) + else: + lineF(p, "$1 = $2;$n", [a.address, b.res]) else: internalError(p.config, x.info, $("genAsgn", b.typ, a.typ)) - else: + elif b.address != nil: lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res]) + else: + lineF(p, "$1 = $2;$n", [a.address, b.res]) else: lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) @@ -1288,7 +1297,7 @@ template isIndirect(x: PSym): bool = v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator, skConst, skTemp, skLet}) -proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) = +proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) = let s = n.sym if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3") case s.kind @@ -1456,13 +1465,17 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) = else: if s.loc.r == nil: internalError(p.config, n.info, "symbol has no generated name: " & s.name.s) - r.res = s.loc.r + if mapType(p, s.typ) == etyBaseIndex: + r.address = s.loc.r + r.res = s.loc.r & "_Idx" + else: + r.res = s.loc.r r.kind = resVal proc genDeref(p: PProc, n: PNode, r: var TCompRes) = let it = n[0] let t = mapType(p, it.typ) - if t == etyObject: + if t == etyObject or it.typ.kind == tyLent: gen(p, it, r) else: var a: TCompRes @@ -1703,7 +1716,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = result = putToSeq("0", indirect) of tyFloat..tyFloat128: result = putToSeq("0.0", indirect) - of tyRange, tyGenericInst, tyAlias, tySink, tyOwned: + of tyRange, tyGenericInst, tyAlias, tySink, tyOwned, tyLent: result = createVar(p, lastSon(typ), indirect) of tySet: result = putToSeq("{}", indirect) @@ -1745,7 +1758,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = createObjInitList(p, t, initIntSet(), initList) result = ("({$1})") % [initList] if indirect: result = "[$1]" % [result] - of tyVar, tyPtr, tyLent, tyRef, tyPointer: + of tyVar, tyPtr, tyRef, tyPointer: if mapType(p, t) == etyBaseIndex: result = putToSeq("[null, 0]", indirect) else: @@ -2394,16 +2407,17 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = if prc.typ[0] != nil and sfPure notin prc.flags: resultSym = prc.ast[resultPos].sym let mname = mangleName(p.module, resultSym) - if not isIndirect(resultSym) and + let returnAddress = not isIndirect(resultSym) and resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and - mapType(p, resultSym.typ) == etyBaseIndex: + mapType(p, resultSym.typ) == etyBaseIndex + if returnAddress: resultAsgn = p.indentLine(("var $# = null;$n") % [mname]) resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname]) else: let resVar = createVar(p, resultSym.typ, isIndirect(resultSym)) resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar]) gen(p, prc.ast[resultPos], a) - if mapType(p, resultSym.typ) == etyBaseIndex: + if returnAddress: returnStmt = "return [$#, $#];$n" % [a.address, a.res] else: returnStmt = "return $#;$n" % [a.res] @@ -2579,8 +2593,15 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = of nkObjConstr: genObjConstr(p, n, r) of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r) of nkAddr, nkHiddenAddr: - genAddr(p, n, r) - of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r) + if n.typ.kind in {tyLent}: + gen(p, n[0], r) + else: + genAddr(p, n, r) + of nkDerefExpr, nkHiddenDeref: + if n.typ.kind in {tyLent}: + gen(p, n[0], r) + else: + genDeref(p, n, r) of nkBracketExpr: genArrayAccess(p, n, r) of nkDotExpr: genFieldAccess(p, n, r) of nkCheckedFieldExpr: genCheckedFieldOp(p, n, nil, r) diff --git a/tests/js/tlent.nim b/tests/js/tlent.nim new file mode 100644 index 0000000000000..2546e5b1deefa --- /dev/null +++ b/tests/js/tlent.nim @@ -0,0 +1,33 @@ +discard """ + output: ''' +hmm +100 +hmm +100 +''' +""" + +# #16800 + +type A = object + b: int +var t = A(b: 100) +block: + proc getValues: lent int = + echo "hmm" + result = t.b + echo getValues() +block: + proc getValues: lent int = + echo "hmm" + t.b + echo getValues() + +when false: # still an issue, #16908 + template main = + iterator fn[T](a:T): lent T = yield a + let a = @[10] + for b in fn(a): echo b + + static: main() + main() diff --git a/tests/lent/tbasic_lent_check.nim b/tests/lent/tbasic_lent_check.nim index 0787e36d983a3..92d731451eb5b 100644 --- a/tests/lent/tbasic_lent_check.nim +++ b/tests/lent/tbasic_lent_check.nim @@ -17,22 +17,26 @@ proc main = main() template main2 = # bug #15958 + when defined(js): + proc sameAddress[T](a, b: T): bool {.importjs: "(# === #)".} + else: + template sameAddress(a, b): bool = a.unsafeAddr == b.unsafeAddr proc byLent[T](a: T): lent T = a let a = [11,12] let b = @[21,23] let ss = {1, 2, 3, 5} doAssert byLent(a) == [11,12] - doAssert byLent(a).addr == a.addr + doAssert sameAddress(byLent(a), a) doAssert byLent(b) == @[21,23] - when not defined(js): # pending bug #16073 - doAssert byLent(b).addr == b.addr + # pending bug #16073 + doAssert sameAddress(byLent(b), b) doAssert byLent(ss) == {1, 2, 3, 5} - doAssert byLent(ss).addr == ss.addr + doAssert sameAddress(byLent(ss), ss) let r = new(float) r[] = 10.0 - when not defined(js): # pending bug #16073 - doAssert byLent(r)[] == 10.0 + # bug #16073 + doAssert byLent(r)[] == 10.0 when not defined(js): # pending bug https://github.com/timotheecour/Nim/issues/372 let p = create(float) @@ -41,9 +45,9 @@ template main2 = # bug #15958 proc byLent2[T](a: openArray[T]): lent T = a[0] doAssert byLent2(a) == 11 - doAssert byLent2(a).addr == a[0].addr + doAssert sameAddress(byLent2(a), a[0]) doAssert byLent2(b) == 21 - doAssert byLent2(b).addr == b[0].addr + doAssert sameAddress(byLent2(b), b[0]) proc byLent3[T](a: varargs[T]): lent T = a[1] let