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

Infinite recursion instantiating generic defined on a concept #24463

Open
c-blake opened this issue Nov 21, 2024 · 1 comment
Open

Infinite recursion instantiating generic defined on a concept #24463

c-blake opened this issue Nov 21, 2024 · 1 comment
Labels

Comments

@c-blake
Copy link
Contributor

c-blake commented Nov 21, 2024

Description

It's possible this could be shrunken a little, but it's pretty minimal.

type
  Oat*[K, Q] = concept t
    eq(t, K, K) is bool
    key(t, int) is K

  Valued*[V] = concept t
    val(var t, int, V)
    val(t, int) is V

  VOat*[K,Q,V] = concept t
    t is Valued[V]
    t is Oat[K,Q]

proc getOrDefault*[K,Q,V](t: VOat[K,Q,V], q: Q, def=default(V)): V = discard

type
  Count = object
    cnt: int
    key: string
  Counts = object
    dat: seq[Count]

proc eq(t: Counts, a: string, b: string): bool = a == b
proc key(c: Counts, i: int): string = c.dat[i].key
proc val(c: var Counts, i: int, v: int) = c.dat[i].cnt = v
proc val(c: Counts, i: int): int = c.dat[i].cnt

proc foo() =
  var h: Counts
  when defined bug: # infinite loops compiler & nimsuggest
    let x = getOrDefault(h, "hi")
  else:
    let x = getOrDefault[string, string, int](h, "hi") # works

Nim Version

Compiling with nim c -d:bug makes all versions of Nim I have around infinite loop. This is at least 0.20.2, 1.2, 1.4, 1.6, 2.0, and current devel head.

Current Output

None.  Infinite loop with memory exhaustion.

Expected Output

Either correct compilation with the instantiated inferred or an instantiation error.

Known Workarounds

Always provide the generic parameter list with instance values. It is pretty bothersome need nimsuggest to infinite recurse as a "signal" that one needs to do this, however.

Additional Information

EDIT: The def=default(V) might look troubling to some, but dropping that defaulted parameter entirely seems to not change anything, but I'd like for that to work as well and so kept it in the code example in case this becomes a test case of some kind.

@metagn
Copy link
Collaborator

metagn commented Dec 6, 2024

This is an infinite cycle between a tyInferred type matching the given type against its generic parameter, when the generic parameter is somehow bound to a typedesc of the tyInferred type itself, which is then matched again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants