Skip to content

Commit b2ea077

Browse files
committed
mirtypes: fix alias translation in edge case
So far, translation for alias-like PTypes worked by first adding/ translating the target type and then creating a type symbol for the alias type mirroring the description of the target type. In the recursive translation scenario `A -> B -> ... -> C -> B`, where `A` and `C` are alias-like types and `B` is an object type, the second request to translate `B` yielded the still-incomplete but already registered type symbol for the object type, causing `C` to stay in an incomplete state, breaking type environment expectations. To fix the issue, translation of object types is always delayed till the end of the entry `add` call; a follow-up pass then patches the type symbols corresponding to alias-like PTypes aliasing object types.
1 parent 86011b3 commit b2ea077

File tree

1 file changed

+43
-7
lines changed

1 file changed

+43
-7
lines changed

compiler/mir/mirtypes.nim

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ type
144144
idents: BiTable[string]
145145
numbers: BiTable[BiggestInt]
146146

147+
guard: int
148+
## tracks the recursion depth for `add`, to know which call is the
149+
## top-level one
150+
delayed: seq[TypeId]
151+
## still-incomplete type symbols corresponding to object types, to be
152+
## completed later
153+
147154
config: ConfigRef
148155
graph: ModuleGraph
149156

@@ -1137,13 +1144,6 @@ proc typeSymToMir(env: var TypeEnv, t: PType): TypeId =
11371144
if sfImportc notin t.sym.flags:
11381145
env.map[t] = result
11391146

1140-
let
1141-
orig = typeToMir(env, t, canon=false)
1142-
canon = typeToMir(env, t, canon=true, unique=(tfFromGeneric notin t.flags))
1143-
1144-
# there's nothing to lower for object types
1145-
env.symbols[result].desc = [orig, canon, canon]
1146-
11471147
# generic types support covariance for tuples. Pick an instance as the
11481148
# "canonical" one, so that - for example - ``Generic[(int,)]`` and
11491149
# ``Generic[tuple[x: int]]`` map to the same MIR type in the end. In order
@@ -1153,12 +1153,16 @@ proc typeSymToMir(env: var TypeEnv, t: PType): TypeId =
11531153
result);
11541154
c != result):
11551155
env.symbols[result].canon = c
1156+
1157+
env.delayed.add result
11561158
of Skip:
11571159
# except for `inst`, the type symbol is identical to that of the
11581160
# skipped-to type
11591161
let base = env.add(skipIrrelevant(t))
11601162
var sym = env.symbols[base]
11611163
sym.inst = t
1164+
# note: for skipped types that reference object types, a separate pass
1165+
# makes sure the symbol is proper
11621166
result = env.symbols.add(sym)
11631167
env.map[t] = result
11641168
else:
@@ -1214,13 +1218,45 @@ proc handleImported(env: var TypeEnv, t: PType): TypeId =
12141218
else:
12151219
result = typeSymToMir(env, t)
12161220

1221+
proc translateObjects(env: var TypeEnv, since: Checkpoint) =
1222+
## Post-processes the type symbols added since `since`, translating all
1223+
## delayed object types and fixing alias-like symbols pointing to them.
1224+
# first pass: translate delayed object types
1225+
let needsFixup = env.delayed.len > 0
1226+
while env.delayed.len > 0:
1227+
let
1228+
id = env.delayed.pop()
1229+
inst = env.symbols[id].inst
1230+
orig = typeToMir(env, inst, canon=false)
1231+
canon = typeToMir(env, inst, canon=true,
1232+
unique=(tfFromGeneric notin inst.flags))
1233+
1234+
# there's nothing to lower for object types
1235+
env.symbols[id].desc = [orig, canon, canon]
1236+
1237+
if needsFixup:
1238+
# second pass: fix type-symbols corresponding to alias-like types pointing
1239+
# to object types
1240+
for id, it in since(env.symbols, since):
1241+
if it.inst != nil and it.inst.kind in Skip and
1242+
it.desc[Original] == HeaderId(0) and
1243+
env.headerFor(it.canon, Original).kind in {tkStruct, tkUnion}:
1244+
# inherit the description from the aliased type
1245+
let target = skipIrrelevant(it.inst)
1246+
env.symbols[id].desc = env.symbols[env.map[target]].desc
1247+
12171248
proc add*(env: var TypeEnv, t: PType): TypeId =
12181249
## If not registered yet, adds `t` to `env` and returns the ID to later
12191250
## look it up with.
12201251
result = env.map.getOrDefault(t, env.symbols.nextId())
12211252
if result == env.symbols.nextId(): # not seen yet?
1253+
let before = env.symbols.checkpoint()
1254+
inc env.guard
12221255
result = handleImported(env, t)
12231256
# translation of the type registered the mapping for us
1257+
if env.guard == 1: # top-most call?
1258+
translateObjects(env, before)
1259+
dec env.guard
12241260

12251261
proc addSignature*(env: var TypeEnv, t: PType): TypeId =
12261262
## Adds the proc type `t` to `env`, treating it as the type of a *procedure*,

0 commit comments

Comments
 (0)