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

Changing statement order in generics can cause type mismatches #16128

Closed
haxscramper opened this issue Nov 25, 2020 · 3 comments · Fixed by #24119
Closed

Changing statement order in generics can cause type mismatches #16128

haxscramper opened this issue Nov 25, 2020 · 3 comments · Fixed by #24119

Comments

@haxscramper
Copy link
Contributor

haxscramper commented Nov 25, 2020

Changing statement order in simpleTreeDiff causes compilation error. I'm not entirely sure if this is a bug, or some insanely convoluted generic interaction, but since the behavior of the compiler wildly differs only based on the order of generic instantiations it is probably a bug.

Example

import std/[tables, hashes]

type
  NodeId*[L] = object
    isSource: bool
    index: Table[NodeId[L], seq[NodeId[L]]]

func hash*[L](id: NodeId[L]): Hash = discard
func `==`[L](a, b: NodeId[L]): bool = discard

proc makeIndex*[T, L](tree: T) =
  var parent = NodeId[L]()
  var tmp: Table[NodeId[L], seq[NodeId[L]]]
  tmp[parent] = @[parent]

proc simpleTreeDiff*[T, L](source, target: T) =
  # Swapping these two lines makes error disappear
  var m: Table[NodeId[L], NodeId[L]]
  makeIndex[T, L](target)

var tmp: Table[string, seq[string]] # removing this forward declaration also removes error

proc diff(x1, x2: string): auto =
  simpleTreeDiff[int, string](12, 12)

Current Output

/usercode/in.nim(29, 17) template/generic instantiation of `simpleTreeDiff` from here
/usercode/in.nim(24, 21) template/generic instantiation of `makeIndex` from here
/usercode/in.nim(18, 15) template/generic instantiation of `[]=` from here
/playground/nim/lib/pure/collections/tableimpl.nim(58, 21) template/generic instantiation of `rawGet` from here
/playground/nim/lib/pure/collections/hashcommon.nim(60, 48) Error: type mismatch: got <string, NodeId[system.string, system.string]>

Expected Output

No compilation errors

Additional

I added static: echo typeof ... in tables.[]= to printf-debug instantiation. Concreted code now is (module runnable example and documentation):

proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
  static:
    echo "proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) ="
    echo "  typeof(A) ", typeof(A)
    echo "  typeof(B) ", typeof(B)
    echo "  typeof(t) ", typeof(t)
    echo "  typeof(t.data) ", typeof(t.data)

  putImpl(enlarge)

And it produces different results based on order of the statements in code above or whether var tmp: Table[string, seq[string]] is present. When I try to compile example it outputs

proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
  typeof(A) NodeId[system.string]
  typeof(B) seq[NodeId[system.string]]
  typeof(t) Table[NodeId[system.string], seq[NodeId[system.string]]]
  typeof(t.data) KeyValuePairSeq[system.string, seq[string]]

When I remove var tmp: Table[string, seq[string]] compilations succeeds, printing out

proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
  typeof(A) NodeId[system.string]
  typeof(B) seq[NodeId[system.string]]
  typeof(t) Table[NodeId[system.string], seq[NodeId[system.string]]]
  typeof(t.data) KeyValuePairSeq[NodeId[system.string], seq[NodeId[system.string]]]

Which is what one could expect (t.data generic parameters are the same as in table itself).

Nim version

$ nim -v
Nim Compiler Version 1.4.0 [Linux: amd64]
Compiled at 2020-10-16
Copyright (c) 2006-2020 by Andreas Rumpf

git hash: bdcd87afca238a0a7b2c70971827cf9172817b12
active boot switches: -d:release -d:danger
@timotheecour
Copy link
Member

timotheecour commented Nov 25, 2020

IMO we should always allow passing the relevant hash/comparator to algorithms, it's explicit and more flexible, in particular doesn't affect unrelated code (if different hash/comparator is needed), as done in C++, D and other languages. This can be done in a backward compatible way and zero-cost way, avoiding a function pointer overhead even without lto

@haxscramper
Copy link
Contributor Author

Good to know that this at least somewhat known issue. Even though it might be considered duplicate I would still prefer to leave it open, since this is a particularly tricky to reproduce, so more examples would be nice to have.

Is there any way currently to deal with this right now? Or I need to somehow instantiate needed generics earlier (by explicitly stating this limitation in documentation and carefully watching order of imports each time?).

PS: I'm also in favor of passing hash/==/< explicitly to implementation.

haxscramper added a commit to haxscramper/hmisc that referenced this issue Aug 29, 2021
I somehow managed to trigger another generic sandwich or whatever it is
called, with symboms very similar to
nim-lang/Nim#16128 - can't get string from
`Table[string, string]`, things worked until I had another instantiation of
the table before one in ptree.

For some reason `std/tables` is the only module that triggers that kind of
bugs for me, though considering /how/ it is implemented internally it
should not come out as a surprise. Basicallyt an ideal environment to
trigger things like that - multiple spliced `{.dirty.}` template
instantiations, generics on top of generics, things are partially shared
with multiple other modules (like hashes etc).
@SirOlaf
Copy link
Contributor

SirOlaf commented Oct 30, 2023

Was fixed in #22828

Araq pushed a commit that referenced this issue Aug 30, 2024
closes #1969, closes #7547, closes #7737, closes #11838, closes #12283,
closes #12714, closes #12720, closes #14053, closes #16118, closes
#19670, closes #22645

I was going to wait on these but regression tests even for recent PRs
are turning out to be important in wide reaching PRs like #24010.

The other issues with the working label felt either finnicky (#7385,
#9156, #12732, #15247), excessive to test (#12405, #12424, #17527), or I
just don't know what fixed them/what the issue was (#16128: the PR link
gives a server error by Github, #12457, #12487).
metagn added a commit to metagn/Nim that referenced this issue Sep 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants