diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2018-12-12 18:19:52 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-12 18:19:52 +0100 |
commit | e4ae7a892948304e7317e3d8cc8d00cf9a91228c (patch) | |
tree | 876a43b594e983d9b1b4464b924b4de13855878a | |
parent | cc974538087674e1bf4028b2d9fd1c31ec3f265a (diff) | |
parent | 5afcd09cb3d75d4f01427082563966e3f435c9a2 (diff) | |
download | Nim-e4ae7a892948304e7317e3d8cc8d00cf9a91228c.tar.gz |
Merge pull request #8748 from LemonBoy/when-in-objects
Pervasive replacement of nkRecWhen in generic types
-rw-r--r-- | compiler/semtypinst.nim | 40 | ||||
-rw-r--r-- | tests/objects/twhen1.nim | 51 |
2 files changed, 91 insertions, 0 deletions
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index ffa913f1d..f3c12e557 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -166,6 +166,36 @@ proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode = return n +proc replaceObjBranches(cl: TReplTypeVars, n: PNode): PNode = + result = n + case n.kind + of nkNone..nkNilLit: + discard + of nkRecWhen: + var branch: PNode = nil # the branch to take + for i in countup(0, sonsLen(n) - 1): + var it = n.sons[i] + if it == nil: illFormedAst(n, cl.c.config) + case it.kind + of nkElifBranch: + checkSonsLen(it, 2, cl.c.config) + var cond = it.sons[0] + var e = cl.c.semConstExpr(cl.c, cond) + if e.kind != nkIntLit: + internalError(cl.c.config, e.info, "ReplaceTypeVarsN: when condition not a bool") + if e.intVal != 0 and branch == nil: branch = it.sons[1] + of nkElse: + checkSonsLen(it, 1, cl.c.config) + if branch == nil: branch = it.sons[0] + else: illFormedAst(n, cl.c.config) + if branch != nil: + result = replaceObjBranches(cl, branch) + else: + result = newNodeI(nkRecList, n.info) + else: + for i in 0..<n.sonsLen: + n.sons[i] = replaceObjBranches(cl, n.sons[i]) + proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode = if n == nil: return result = copyNode(n) @@ -549,6 +579,16 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = skipIntLiteralParams(result) else: discard + else: + # If this type doesn't refer to a generic type we may still want to run it + # trough replaceObjBranches in order to resolve any pending nkRecWhen nodes + result = t + + # Slow path, we have some work to do + if result.n != nil and t.kind == tyObject: + # Invalidate the type size as we may alter its structure + result.size = -1 + result.n = replaceObjBranches(cl, result.n) proc instAllTypeBoundOp*(c: PContext, info: TLineInfo) = var i = 0 diff --git a/tests/objects/twhen1.nim b/tests/objects/twhen1.nim new file mode 100644 index 000000000..2301d255a --- /dev/null +++ b/tests/objects/twhen1.nim @@ -0,0 +1,51 @@ +const Z = 0 + +type + Foo[T] = object + when true: + u: int + else: + v: int + Foo1[T] = object + when T is int: + x: T + elif true: + z: char + Foo2[x:static[int]] = object + when (x and 1) == 1: + x: array[x+1,int] + else: + x: array[x,int] + + Foo3 = Foo2[128] + + # #8417 + Foo4[A: static[int]] = object + when Z == 0: + discard + else: + discard + +block: + var x: Foo[int] = Foo[int](u: 42) + doAssert x.u == 42 + +# Don't evaluate `when` branches before the type is instantiated +block: + var x: Foo1[bool] = Foo1[bool](z: 'o') + doAssert x.z == 'o' + +block: + var x: Foo2[3] + doAssert x.x.len == 4 + +block: + var x: Foo2[4] + doAssert x.x.len == 4 + +block: + var x: Foo3 + doAssert x.x.len == 128 + +block: + var x: Foo4[0] |