From f11082404c5aa0a717f9f4da085556484d5c8f4d Mon Sep 17 00:00:00 2001 From: zerbina <100542850+zerbina@users.noreply.github.com> Date: Mon, 5 Aug 2024 23:54:26 +0200 Subject: [PATCH] mirtypes: fix regression with cyclic generic object types (#1398) ## Summary Fix cyclic generic object types instantiated with tuple types as one of the arguments causing C compiler errors under some circumstances. ## Details * the type merging logic in `mirtypes` now uses `sighashes`, which is able to handle cyclic types * previously, `Obj[(int,)]` and `Obj[tuple[x: int]]` were not being merged into one when `Obj` is cyclic * this led to C compiler errors when assigning between such types, or when the type has hooks (explicit or synthesized) that are called --- compiler/mir/mirtypes.nim | 16 +++++++++++----- .../tequal_instantiation_with_tuple.nim | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 tests/lang_callable/generics/tequal_instantiation_with_tuple.nim diff --git a/compiler/mir/mirtypes.nim b/compiler/mir/mirtypes.nim index f8791ffd585..6b5055850c4 100644 --- a/compiler/mir/mirtypes.nim +++ b/compiler/mir/mirtypes.nim @@ -44,6 +44,10 @@ import idioms ] +# XXX: sighashes are currently needed for merging generic instantiations, but +# this should ultimately happen earlier - in sem - already +from compiler/sem/sighashes import hashType, ConsiderFlag + type TypeKind* = enum tkVoid @@ -133,9 +137,9 @@ type canon: Table[HeaderId, TypeId] ## maps headers of canonical type descriptions to their type symbol - instances: Table[(int, HeaderId), TypeId] - ## associates a generic type ID + instance body with a type symbol. This - ## is used for eliminating same-shaped instantiations of a generic + instances: Table[SigHash, TypeId] + ## associates the sighash of a generic type instance with a type symbol. + ## This is used for eliminating same-shaped instantiations of a generic ## object type idents: BiTable[string] @@ -1045,9 +1049,11 @@ proc typeSymToMir(env: var TypeEnv, t: PType): TypeId = # generic types support covariance for tuples. Pick an instance as the # "canonical" one, so that - for example - ``Generic[(int,)]`` and - # ``Generic[tuple[x: int]]`` map to the same MIR type in the end + # ``Generic[tuple[x: int]]`` map to the same MIR type in the end. In order + # to support cyclic types, ``sighashes`` has to be used if tfFromGeneric in t.flags and - (let c = env.instances.mgetOrPut((t.sym.owner.typ.id, canon), result); + (let c = env.instances.mgetOrPut(hashType(t, {CoType, CoDistinct}), + result); c != result): env.symbols[result].canon = c else: diff --git a/tests/lang_callable/generics/tequal_instantiation_with_tuple.nim b/tests/lang_callable/generics/tequal_instantiation_with_tuple.nim new file mode 100644 index 00000000000..1e5b60df212 --- /dev/null +++ b/tests/lang_callable/generics/tequal_instantiation_with_tuple.nim @@ -0,0 +1,19 @@ +discard """ + description: ''' + Ensure that two instantiations of a cyclic generic object type are + considered equal at every level (type system, backend, run-time) when + one of them is instantiated with a named tuple and the other with an + unnamed one + ''' + knownIssue.vm: "``vmtypegen`` considers the two types distinct" +""" + +type Recursive[T] = object + # the same problem occurred when a ``ref`` type is used + self: ptr Recursive[T] + val: T + +# it's important that both tuples are comprised of the exact same types +var x: Recursive[(int, int)] +var y: Recursive[tuple[a, b: int]] +x = y