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

At a certain level nested generics cause causes the typechecker to get stuck #20348

Closed
deech opened this issue Sep 13, 2022 · 3 comments
Closed

Comments

@deech
Copy link
Contributor

deech commented Sep 13, 2022

What happened?

This is a contrived example but please bear with me, it was difficult to distill a more minimal reproduction for this bug, it seems at a certain level of generics nesting the typechecker stops being able to deduce any further types and is stuck:

type
  Payload[T] = object
    payload: T
  Carrier[T] = object
    val: T

type
  Payload0*[T] = object
    payload: Payload[T]
  Payload1*[T] = object
    payload: Payload[T]
  Payload2*[T] = object
    payload: Payload[T]
  Payload3*[T] = object
    payload: Payload[T]
  Payload4*[T] = object
    payload: Payload[T]
  Payload5*[T] = object
    payload: Payload[T]
  Payload6*[T] = object
    payload: Payload[T]
  Payload7*[T] = object
    payload: Payload[T]
  Payload8*[T] = object
    payload: Payload[T]
  Payload9*[T] = object
    payload: Payload[T]
  Payload10*[T] = object
    payload: Payload[T]
  Payload11*[T] = object
    payload: Payload[T]
  Payload12*[T] = object
    payload: Payload[T]
  Payload13*[T] = object
    payload: Payload[T]
  Payload14*[T] = object
    payload: Payload[T]
  Payload15*[T] = object
    payload: Payload[T]
  Payload16*[T] = object
    payload: Payload[T]
  Payload17*[T] = object
    payload: Payload[T]
  Payload18*[T] = object
    payload: Payload[T]
  Payload19*[T] = object
    payload: Payload[T]
  Payload20*[T] = object
    payload: Payload[T]
  Payload21*[T] = object
    payload: Payload[T]
  Payload22*[T] = object
    payload: Payload[T]
  Payload23*[T] = object
    payload: Payload[T]
  Payload24*[T] = object
    payload: Payload[T]
  Payload25*[T] = object
    payload: Payload[T]
  Payload26*[T] = object
    payload: Payload[T]
  Payload27*[T] = object
    payload: Payload[T]
  Payload28*[T] = object
    payload: Payload[T]
  Payload29*[T] = object
    payload: Payload[T]
  Payload30*[T] = object
    payload: Payload[T]
  Payload31*[T] = object
    payload: Payload[T]
  Payload32*[T] = object
    payload: Payload[T]
  Payload33*[T] = object
    payload: Payload[T]
  Payload34*[T] = object
    payload: Payload[T]

type
  Carriers*[T] = object
    c0*: Carrier[Payload0[T]]
    c1*: Carrier[Payload1[T]]
    c2*: Carrier[Payload2[T]]
    c3*: Carrier[Payload3[T]]
    c4*: Carrier[Payload4[T]]
    c5*: Carrier[Payload5[T]]
    c6*: Carrier[Payload6[T]]
    c7*: Carrier[Payload7[T]]
    c8*: Carrier[Payload8[T]]
    c9*: Carrier[Payload9[T]]
    c10*: Carrier[Payload10[T]]
    c11*: Carrier[Payload11[T]]
    c12*: Carrier[Payload12[T]]
    c13*: Carrier[Payload13[T]]
    c14*: Carrier[Payload14[T]]
    c15*: Carrier[Payload15[T]]
    c16*: Carrier[Payload16[T]]
    c17*: Carrier[Payload17[T]]
    c18*: Carrier[Payload18[T]]
    c19*: Carrier[Payload19[T]]
    c20*: Carrier[Payload20[T]]
    c21*: Carrier[Payload21[T]]
    c22*: Carrier[Payload22[T]]
    c23*: Carrier[Payload23[T]]
    c24*: Carrier[Payload24[T]]
    c25*: Carrier[Payload25[T]]
    c26*: Carrier[Payload26[T]]
    c27*: Carrier[Payload27[T]]
    c28*: Carrier[Payload28[T]]
    c29*: Carrier[Payload29[T]]
    c30*: Carrier[Payload30[T]]
    c31*: Carrier[Payload31[T]]
    c32*: Carrier[Payload32[T]]
    c33*: Carrier[Payload33[T]]
    c34*: Carrier[Payload34[T]]

var carriers : Carriers[int]

proc printPayload33[T](p:Payload33[T]) = echo p.payload.payload
proc printPayload34[T](p:Payload34[T]) = echo p.payload.payload

printPayload33(carriers.c33.val)
# printPayload34(carriers.c34.val)

printPayload33(carriers.c33.val) fails with:

> nim c -r --verbosity\:0 --hint\[Processing\]\:off --excessiveStackTrace\:on /tmp/test.nim
/tmp/test.nim(122, 15) Error: type mismatch: got <Payload32[system.int]>
but expected one of:
proc printPayload33[T](p: Payload33[T])
  first type mismatch at position: 1
  required type for p: Payload33[printPayload33.T]
  but expression 'carriers.c33.val' is of type: Payload32[system.int]

expression: printPayload33(carriers.c33.val)

but so does printPayload34(carriers.c34.val). At this point any further Carrier[Payload*[T]] fields added to the Carrier object are stuck at Payload32[system.int].

Nim Version

Nim Compiler Version 1.7.1 [Linux: amd64]
Compiled at 2022-09-13
Copyright (c) 2006-2022 by Andreas Rumpf

git hash: 7c85b500df69cf5c5856549dafe59d7b619e8b26
active boot switches: -d:release

Current Standard Output Logs

No response

Expected Standard Output Logs

No response

Possible Solution

No response

Additional Information

No response

@deech
Copy link
Contributor Author

deech commented Sep 13, 2022

@Araq We talked about this yesterday but the repro shows it's not a type aliasing issue as we previously thought since objects are nominally typed.

@deech deech changed the title Nested generics in distinct types cause causes the typechecker to deduce the wrong type At a certain level nested generics cause causes the typechecker to get stuck Sep 13, 2022
@deech
Copy link
Contributor Author

deech commented Sep 13, 2022

This is a more realistic repro but it's less contained:

import std/[options]
type
  F1*[T] = object
    call: proc(self:T,callback:proc(self:T))
  F2*[T] = object
    call: proc(self:T,callback:proc(self:T))
  F3*[T] = object
    call: proc(self:T,callback:proc(self:T))

type
  Functions*[T] = object
    a*: Option[F1[T]]
    b*: Option[F1[T]]
    c*: Option[F1[T]]
    d*: Option[F1[T]]
    e*: Option[F1[T]]
    f*: Option[F1[T]]
    g*: Option[F1[T]]
    h*: Option[F1[T]]
    i*: Option[F2[T]]
    j*: Option[F3[T]]

var fs : Functions[int]
fs.j.map(proc(f:F3[int]) = discard)

it fails with:

/tmp/test.nim(25, 4) template/generic instantiation of `map` from here
/home/deech/Nim/lib/pure/options.nim(250, 13) Error: type mismatch: got <F2[system.int]>
but expected one of:
proc (input: F3[system.int]){.closure.}

@deech
Copy link
Contributor Author

deech commented Sep 14, 2022

This is happening due to the hardcoded recursionLimit. After it crosses the 100 threshold the previous instantiation of the generic type is retrieved from the cache causing the typechecker bug. I could use some guidance on how to address this.

capocasa pushed a commit to capocasa/Nim that referenced this issue Mar 31, 2023
narimiran pushed a commit that referenced this issue May 12, 2023
…ic type has been generated by the compiler (#20377)

Fixes #20348

(cherry picked from commit be4bd8a)
narimiran pushed a commit that referenced this issue May 15, 2023
…ic type has been generated by the compiler (#20377)

Fixes #20348

(cherry picked from commit be4bd8a)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant