diff --git a/compiler/sem/sighashes.nim b/compiler/sem/sighashes.nim index 1e417616928..e56fc615aed 100644 --- a/compiler/sem/sighashes.nim +++ b/compiler/sem/sighashes.nim @@ -164,28 +164,18 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) = else: c.hashSym(t.sym) - var symWithFlags: PSym - template hasFlag(sym): bool = - let ret = {sfAnon, sfGenSym} * sym.flags != {} - if ret: symWithFlags = sym - ret - if hasFlag(t.sym) or (t.kind == tyObject and t.owner.kind == skType and t.owner.typ.kind == tyRef and hasFlag(t.owner)): - # for `PFoo:ObjectType`, arising from `type PFoo = ref object` - # Generated object names can be identical, so we need to - # disambiguate furthermore by hashing the field types and names. - if t.n.len > 0: - let oldFlags = symWithFlags.flags - # Hack to prevent endless recursion - # xxx instead, use a hash table to indicate we've already visited a type, which - # would also be more efficient. - symWithFlags.flags.excl {sfAnon, sfGenSym} - hashTree(c, t.n, flags + {CoHashTypeInsideNode}) - symWithFlags.flags = oldFlags - else: - # The object has no fields: we _must_ add something here in order to - # make the hash different from the one we produce by hashing only the - # type name. - c &= ".empty" + if t.sym.flags * {sfAnon, sfGenSym} != {} or + (t.kind == tyObject and t.owner.kind == skType and + tfRefsAnonObj in t.owner.typ.flags): + # one or more of the following are true for the type: + # * it's anonymous + # * it's defined not in the top-level scope + # * it's the object type from a ``ref object`` type construction + # The only property that uniquely identifies the type in this case is + # the symbol ID, so we use that. **This means that the hash produced + # for such types is dependent on the type's surroundings** + c &= "." + c &= $t.sym.id else: c &= t.id if t.len > 0 and t[0] != nil: diff --git a/tests/lang_objects/destructor/tseparate_hooks1.nim b/tests/lang_objects/destructor/tseparate_hooks1.nim new file mode 100644 index 00000000000..d6ac8290f86 --- /dev/null +++ b/tests/lang_objects/destructor/tseparate_hooks1.nim @@ -0,0 +1,21 @@ +discard """ + description: ''' + Ensure that separate hooks are created for ``ref T`` types where T are non- + top-level object types sharing the exact same name and shape + ''' + targets: "c js vm" +""" + +# XXX: this currently relies on the backend C compiler complaining. Eventually, +# the test should inspect the MIR output and make sure two different +# destroy hooks are used + +block: + type Nested = object + + var a = (ref Nested)() + +block: + type Nested = object + + var b = (ref Nested)() diff --git a/tests/lang_objects/destructor/tseparate_hooks2.nim b/tests/lang_objects/destructor/tseparate_hooks2.nim new file mode 100644 index 00000000000..ab052a5806a --- /dev/null +++ b/tests/lang_objects/destructor/tseparate_hooks2.nim @@ -0,0 +1,31 @@ +discard """ + description: ''' + Ensure that separate hooks are created for ``ref T`` types where T are non- + top-level object types sharing the exact same name and shape + ''' + targets: "c js vm" +""" + +# XXX: this currently relies on the backend C compiler complaining. Eventually, +# the test should inspect the MIR output and make sure two different +# destroy hooks are used + +# for this test, both procedures must: +# * share the same user-provided name +# * create an anonymous environment object with the exact same shape and field +# names + +proc outer(x: int) = + var x = 1 + proc inner() = + x = 2 + inner() + +proc outer(x: float) = + var x = 1 + proc inner() = + x = 2 + inner() + +outer(1) +outer(1.0)