Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Pervasive replacement of nkRecWhen in generic types #8748

Merged
merged 1 commit into from
Dec 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions compiler/semtypinst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -541,6 +571,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
Expand Down
51 changes: 51 additions & 0 deletions tests/objects/twhen1.nim
Original file line number Diff line number Diff line change
@@ -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]