diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index d8be85273..c6cf63767 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -578,9 +578,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, n[0].sym.magic = mSubU result = n of mPrivateAccess: - let sym = n[1].typ[0].sym - assert sym != nil - c.currentScope.allowPrivateAccess.add sym + var t = n[1].typ[0] + if t.kind in {tyRef, tyPtr}: t = t[0] + c.currentScope.allowPrivateAccess.add t.sym result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid)) else: result = n diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 7a2c0d964..f3add0849 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -258,7 +258,9 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = for module in c.friendModules: if fmoduleId == module.id: return true if f.kind == skField: - let symObj = f.owner + var symObj = f.owner + if symObj.typ.kind in {tyRef, tyPtr}: + symObj = symObj.typ[0].sym for scope in allScopes(c.currentScope): for sym in scope.allowPrivateAccess: if symObj.id == sym.id: return true diff --git a/lib/std/importutils.nim b/lib/std/importutils.nim index 4efe0e140..f7a3cbd03 100644 --- a/lib/std/importutils.nim +++ b/lib/std/importutils.nim @@ -17,7 +17,7 @@ when defined(nimImportutilsExample): x1: int # private proc initFoo*(): auto = Foo() -proc privateAccess*(t: typedesc) {.magic: "PrivateAccess".} = +proc privateAccess*(t: typedesc[object|ref|ptr]) {.magic: "PrivateAccess".} = ## Enables access to private fields of `t` in current scope. runnableExamples("-d:nimImportutilsExample"): # here we're importing a module containing: diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim index 35423de17..44048adbd 100644 --- a/testament/lib/stdtest/testutils.nim +++ b/testament/lib/stdtest/testutils.nim @@ -1,5 +1,6 @@ import std/private/miscdollars from std/os import getEnv +import std/[macros, genasts] template flakyAssert*(cond: untyped, msg = "", notifySuccess = true) = ## API to deal with flaky or failing tests. This avoids disabling entire tests @@ -89,3 +90,22 @@ template reject*(a) = template disableVm*(body) = when nimvm: discard else: body + +template typeOrVoid[T](a: T): type = + # FACTOR with asyncjs.typeOrVoid + T + +macro assertAll*(body) = + ## works in VM, unlike `check`, `require` + runnableExamples: + assertAll: + 1+1 == 2 + var a = @[1, 2] # statements work + a.len == 2 + # remove this once these support VM, pending #10129 (closed but not yet fixed) + result = newStmtList() + for a in body: + result.add genAst(a) do: + # better than: `when not compiles(typeof(a)):` + when typeOrVoid(a) is void: a + else: doAssert a diff --git a/tests/importalls/mt1.nim b/tests/importalls/mt1.nim index 87c4eff16..b7983945c 100644 --- a/tests/importalls/mt1.nim +++ b/tests/importalls/mt1.nim @@ -10,8 +10,8 @@ doAssert m.m3p1 == 2 ## field access import std/importutils privateAccess(Foo5) -# var x = Foo5(z1: "foo", z2: m.kg1) -# doAssert x.z1 == "foo" +var x = Foo5(z1: "foo", z2: m.kg1) +doAssert x.z1 == "foo" var f0: Foo5 f0.z3 = 3 diff --git a/tests/stdlib/mimportutils.nim b/tests/stdlib/mimportutils.nim new file mode 100644 index 000000000..d2b185cd3 --- /dev/null +++ b/tests/stdlib/mimportutils.nim @@ -0,0 +1,17 @@ +type + A* = object + a0*: int + ha1: float + B = object + b0*: int + hb1: float + C* = ref object + c0: int + hc1: float + D* = ptr object + d0: int + hd1: float + PA* = ref A + PtA* = ptr A + +proc initB*(): B = B() diff --git a/tests/stdlib/timportutils.nim b/tests/stdlib/timportutils.nim new file mode 100644 index 000000000..37e2b7102 --- /dev/null +++ b/tests/stdlib/timportutils.nim @@ -0,0 +1,82 @@ +import std/importutils +import stdtest/testutils +import mimportutils + +template main = + block: # privateAccess + assertAll: + var a: A + var b = initB() # B is private + compiles(a.a0) + compiles(b.b0) + not compiles(a.ha1) + not compiles(b.hb1) + + block: + assertAll: + privateAccess A + compiles(a.ha1) + a.ha1 == 0.0 + not compiles(a.hb1) + privateAccess b.typeof + b.hb1 = 3 + type B2 = b.typeof + let b2 = B2(b0: 4, hb1: 5) + b.hb1 == 3 + b2 == B2(b0: 4, hb1: 5) + + assertAll: + not compiles(a.ha1) + not compiles(b.hb1) + + block: + assertAll: + not compiles(C(c0: 1, hc1: 2)) + privateAccess C + let c = C(c0: 1, hc1: 2) + c.hc1 == 2 + + block: + assertAll: + privateAccess PA + var pa = PA(a0: 1, ha1: 2) + pa.ha1 == 2 + pa.ha1 = 3 + pa.ha1 == 3 + + block: + assertAll: + var a = A(a0: 1) + var a2 = a.addr + not compiles(a2.ha1) + privateAccess PtA + a2.type is PtA + a2.ha1 = 2 + a2.ha1 == 2 + a.ha1 = 3 + a2.ha1 == 3 + + block: + disableVm: + assertAll: + var a = A.create() + defer: dealloc(a) + a is PtA + a.typeof is PtA + not compiles(a.ha1) + privateAccess a.typeof + a.ha1 = 2 + a.ha1 == 2 + a[].ha1 = 3 + a.ha1 == 3 + + block: + disableVm: + assertAll: + var a = A.create() + defer: dealloc(a) + privateAccess PtA + a.ha1 == 0 + +static: main() +main() diff --git a/tests/stdlib/ttestutils.nim b/tests/stdlib/ttestutils.nim index 7e39c9ae3..0d789cd76 100644 --- a/tests/stdlib/ttestutils.nim +++ b/tests/stdlib/ttestutils.nim @@ -1,11 +1,24 @@ import stdtest/testutils -block: # greedyOrderedSubsetLines - doAssert greedyOrderedSubsetLines("a1\na3", "a0\na1\na2\na3\na4") - doAssert not greedyOrderedSubsetLines("a3\na1", "a0\na1\na2\na3\na4") # out of order - doAssert not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4") # a5 not in lhs +block: # assertAll + assertAll: + 1+1 == 2 + var a = 3 + a == 3 - doAssert not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\nprefix:a5") - doAssert not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\na5:suffix") - doAssert not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\nprefix:a5") - doAssert not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\na5:suffix") + doAssertRaises(AssertionDefect): + assertAll: + 1+1 == 2 + var a = 3 + a == 4 + +block: # greedyOrderedSubsetLines + assertAll: + greedyOrderedSubsetLines("a1\na3", "a0\na1\na2\na3\na4") + not greedyOrderedSubsetLines("a3\na1", "a0\na1\na2\na3\na4") # out of order + not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4") # a5 not in lhs + + not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\nprefix:a5") + not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\na5:suffix") + not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\nprefix:a5") + not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\na5:suffix")