discard """
  output: '''----
myobj constructed
myobj destroyed
----
mygeneric1 constructed
mygeneric1 destroyed
----
mygeneric2 constructed
mygeneric2 destroyed
myobj destroyed
----
mygeneric3 constructed
mygeneric1 destroyed
----
mydistinctObj constructed
myobj destroyed
mygeneric2 destroyed
------------------
----
----
myobj destroyed
mygeneric1 destroyed
---
myobj destroyed
myobj destroyed
'''
"""

type
  TMyObj = object
    x, y: int
    p: pointer

proc `=destroy`(o: var TMyObj) =
  if o.p != nil:
    dealloc o.p
    o.p = nil
    echo "myobj destroyed"

type
  TMyGeneric1[T] = object
    x: T

  TMyGeneric2[A, B] = object
    x: A
    y: B

proc `=destroy`(o: var TMyGeneric1[int]) =
  echo "mygeneric1 destroyed"

proc `=destroy`[A, B](o: var TMyGeneric2[A, B]) =
  echo "mygeneric2 destroyed"

type
  TMyGeneric3[A, B, C] = object
    x: A
    y: B
    z: C

  TDistinctObjX = distinct TMyGeneric3[TMyObj, TMyGeneric2[int, int], int]
  TDistinctObj = TDistinctObjX

  TObjKind = enum Z, A, B, C, D

  TCaseObj = object
    z: TMyGeneric3[TMyObj, float, int]
    case kind: TObjKind
    of Z: discard
    of A:
      x: TMyGeneric1[int]
    of B, C:
      y: TMyObj
    else:
      case innerKind: TObjKind
      of Z: discard
      of A, B, C:
        p: TMyGeneric3[int, float, string]
      of D:
        q: TMyGeneric3[TMyObj, int, int]
      r: string

proc open: TMyObj =
  # allow for superfluous ()
  result = (TMyObj(x: 1, y: 2, p: alloc(3)))

proc `$`(x: TMyObj): string = $x.y

proc myobj() =
  var x = open()
  echo "myobj constructed"

proc mygeneric1() =
  var x = TMyGeneric1[int](x: 10)
  echo "mygeneric1 constructed"

proc mygeneric2[T](val: T) =
  var a = open()

  var b = TMyGeneric2[int, T](x: 10, y: val)
  echo "mygeneric2 constructed"

  var c = TMyGeneric3[int, int, string](x: 10, y: 20, z: "test")

proc mygeneric3 =
  var x = TMyGeneric3[int, string, TMyGeneric1[int]](
    x: 10, y: "test", z: TMyGeneric1[int](x: 10))

  echo "mygeneric3 constructed"

proc mydistinctObj =
  var x = TMyGeneric3[TMyObj, TMyGeneric2[int, int], int](
    x: open(), y: TMyGeneric2[int, int](x: 5, y: 15), z: 20)

  echo "mydistinctObj constructed"

echo "----"
myobj()

echo "----"
mygeneric1()

echo "----"
mygeneric2[int](10)

echo "----"
mygeneric3()

echo "----"
mydistinctObj()

proc caseobj =
  block:
    var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10))

  block:
    echo "----"
    var o2 = TCaseObj(kind: B, y: open())

  block:
    echo "----"
    var o3 = TCaseObj(kind: D, innerKind: B, r: "test",
                      p: TMyGeneric3[int, float, string](x: 10, y: 1.0, z: "test"))


echo "------------------"
caseobj()

proc caseobj_test_sink: TCaseObj =
  # check that lifted sink can destroy case val correctly
  result = TCaseObj(kind: D, innerKind: D, r: "test",
                      q: TMyGeneric3[TMyObj, int, int](x: open(), y: 1, z: 0))
  result = TCaseObj(kind: B, y: open())


echo "---"
discard caseobj_test_sink()