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