make privateAccess work with generic types and generic instantiations; fix a SIGSEGV (#18260)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
parent
5d15bd7b61
commit
7714ab468a
5 changed files with 118 additions and 15 deletions
|
|
@ -1887,6 +1887,26 @@ proc toObject*(typ: PType): PType =
|
||||||
if t.kind == tyRef: t.lastSon
|
if t.kind == tyRef: t.lastSon
|
||||||
else: typ
|
else: typ
|
||||||
|
|
||||||
|
proc toObjectFromRefPtrGeneric*(typ: PType): PType =
|
||||||
|
#[
|
||||||
|
See also `toObject`.
|
||||||
|
Finds the underlying `object`, even in cases like these:
|
||||||
|
type
|
||||||
|
B[T] = object f0: int
|
||||||
|
A1[T] = ref B[T]
|
||||||
|
A2[T] = ref object f1: int
|
||||||
|
A3 = ref object f2: int
|
||||||
|
A4 = object f3: int
|
||||||
|
]#
|
||||||
|
result = typ
|
||||||
|
while true:
|
||||||
|
case result.kind
|
||||||
|
of tyGenericBody: result = result.lastSon
|
||||||
|
of tyRef, tyPtr, tyGenericInst, tyGenericInvocation, tyAlias: result = result[0]
|
||||||
|
# automatic dereferencing is deep, refs #18298.
|
||||||
|
else: break
|
||||||
|
assert result.sym != nil
|
||||||
|
|
||||||
proc isImportedException*(t: PType; conf: ConfigRef): bool =
|
proc isImportedException*(t: PType; conf: ConfigRef): bool =
|
||||||
assert t != nil
|
assert t != nil
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -457,6 +457,11 @@ proc semOld(c: PContext; n: PNode): PNode =
|
||||||
localError(c.config, n[1].info, n[1].sym.name.s & " does not belong to " & getCurrOwner(c).name.s)
|
localError(c.config, n[1].info, n[1].sym.name.s & " does not belong to " & getCurrOwner(c).name.s)
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
|
proc semPrivateAccess(c: PContext, n: PNode): PNode =
|
||||||
|
let t = n[1].typ[0].toObjectFromRefPtrGeneric
|
||||||
|
c.currentScope.allowPrivateAccess.add t.sym
|
||||||
|
result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid))
|
||||||
|
|
||||||
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
flags: TExprFlags): PNode =
|
flags: TExprFlags): PNode =
|
||||||
## This is the preferred code point to implement magics.
|
## This is the preferred code point to implement magics.
|
||||||
|
|
@ -574,9 +579,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
n[0].sym.magic = mSubU
|
n[0].sym.magic = mSubU
|
||||||
result = n
|
result = n
|
||||||
of mPrivateAccess:
|
of mPrivateAccess:
|
||||||
var t = n[1].typ[0]
|
result = semPrivateAccess(c, n)
|
||||||
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:
|
else:
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -13,22 +13,32 @@ Possible future APIs:
|
||||||
]#
|
]#
|
||||||
|
|
||||||
when defined(nimImportutilsExample):
|
when defined(nimImportutilsExample):
|
||||||
type Foo = object
|
type
|
||||||
x1: int # private
|
Foo = object
|
||||||
|
f0: int # private
|
||||||
|
Goo*[T] = object
|
||||||
|
g0: int # private
|
||||||
proc initFoo*(): auto = Foo()
|
proc initFoo*(): auto = Foo()
|
||||||
|
|
||||||
proc privateAccess*(t: typedesc[object|(ref object)|(ptr object)]) {.magic: "PrivateAccess".} =
|
proc privateAccess*(t: typedesc) {.magic: "PrivateAccess".} =
|
||||||
## Enables access to private fields of `t` in current scope.
|
## Enables access to private fields of `t` in current scope.
|
||||||
runnableExamples("-d:nimImportutilsExample"):
|
runnableExamples("-d:nimImportutilsExample"):
|
||||||
# here we're importing a module containing:
|
# here we're importing a module containing:
|
||||||
# type Foo = object
|
# type
|
||||||
# x1: int # private
|
# Foo = object
|
||||||
|
# f0: int # private
|
||||||
|
# Goo*[T] = object
|
||||||
|
# g0: int # private
|
||||||
# proc initFoo*(): auto = Foo()
|
# proc initFoo*(): auto = Foo()
|
||||||
var a = initFoo()
|
var f = initFoo()
|
||||||
block:
|
block:
|
||||||
assert not compiles(a.x1)
|
assert not compiles(f.f0)
|
||||||
privateAccess(a.type)
|
privateAccess(f.type)
|
||||||
a.x1 = 1 # accessible in this scope
|
f.f0 = 1 # accessible in this scope
|
||||||
block:
|
block:
|
||||||
assert a.x1 == 1 # still in scope
|
assert f.f0 == 1 # still in scope
|
||||||
assert not compiles(a.x1)
|
assert not compiles(f.f0)
|
||||||
|
|
||||||
|
# this also works with generics
|
||||||
|
privateAccess(Goo)
|
||||||
|
assert Goo[float](g0: 1).g0 == 1
|
||||||
|
|
|
||||||
|
|
@ -13,5 +13,20 @@ type
|
||||||
hd1: float
|
hd1: float
|
||||||
PA* = ref A
|
PA* = ref A
|
||||||
PtA* = ptr A
|
PtA* = ptr A
|
||||||
|
E*[T] = object
|
||||||
|
he1: int
|
||||||
|
FSub[T1, T2] = object
|
||||||
|
h3: T1
|
||||||
|
h4: T2
|
||||||
|
F*[T1, T2] = ref FSub[T1, T2]
|
||||||
|
G*[T] = ref E[T]
|
||||||
|
H3*[T] = object
|
||||||
|
h5: T
|
||||||
|
H2*[T] = H3[T]
|
||||||
|
H1*[T] = ref H2[T]
|
||||||
|
H*[T] = H1[T]
|
||||||
|
|
||||||
|
type BAalias* = typeof(B.default)
|
||||||
|
# typeof is not a transparent abstraction, creates a `tyAlias`
|
||||||
|
|
||||||
proc initB*(): B = B()
|
proc initB*(): B = B()
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,55 @@ template main =
|
||||||
let c = C(c0: 1, hc1: 2)
|
let c = C(c0: 1, hc1: 2)
|
||||||
c.hc1 == 2
|
c.hc1 == 2
|
||||||
|
|
||||||
|
block:
|
||||||
|
assertAll:
|
||||||
|
not compiles(E[int](he1: 1))
|
||||||
|
privateAccess E[int]
|
||||||
|
var e = E[int](he1: 1)
|
||||||
|
e.he1 == 1
|
||||||
|
e.he1 = 2
|
||||||
|
e.he1 == 2
|
||||||
|
e.he1 += 3
|
||||||
|
e.he1 == 5
|
||||||
|
# xxx caveat: this currently compiles but in future, we may want
|
||||||
|
# to make `privateAccess E[int]` only affect a specific instantiation;
|
||||||
|
# note that `privateAccess E` does work to cover all instantiations.
|
||||||
|
var e2 = E[float](he1: 1)
|
||||||
|
|
||||||
|
block:
|
||||||
|
assertAll:
|
||||||
|
not compiles(E[int](he1: 1))
|
||||||
|
privateAccess E
|
||||||
|
var e = E[int](he1: 1)
|
||||||
|
e.he1 == 1
|
||||||
|
|
||||||
|
block:
|
||||||
|
assertAll:
|
||||||
|
not compiles(F[int, int](h3: 1))
|
||||||
|
privateAccess F[int, int]
|
||||||
|
var e = F[int, int](h3: 1)
|
||||||
|
e.h3 == 1
|
||||||
|
|
||||||
|
block:
|
||||||
|
assertAll:
|
||||||
|
not compiles(F[int, int](h3: 1))
|
||||||
|
privateAccess F[int, int].default[].typeof
|
||||||
|
var e = F[int, int](h3: 1)
|
||||||
|
e.h3 == 1
|
||||||
|
|
||||||
|
block:
|
||||||
|
assertAll:
|
||||||
|
var a = G[int]()
|
||||||
|
var b = a.addr
|
||||||
|
privateAccess b.type
|
||||||
|
discard b.he1
|
||||||
|
discard b[][].he1
|
||||||
|
|
||||||
|
block:
|
||||||
|
assertAll:
|
||||||
|
privateAccess H[int]
|
||||||
|
var a = H[int](h5: 2)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
assertAll:
|
assertAll:
|
||||||
privateAccess PA
|
privateAccess PA
|
||||||
|
|
@ -44,6 +93,13 @@ template main =
|
||||||
pa.ha1 = 3
|
pa.ha1 = 3
|
||||||
pa.ha1 == 3
|
pa.ha1 == 3
|
||||||
|
|
||||||
|
block:
|
||||||
|
assertAll:
|
||||||
|
var b = BAalias()
|
||||||
|
not compiles(b.hb1)
|
||||||
|
privateAccess BAalias
|
||||||
|
discard b.hb1
|
||||||
|
|
||||||
block:
|
block:
|
||||||
assertAll:
|
assertAll:
|
||||||
var a = A(a0: 1)
|
var a = A(a0: 1)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue