discard """
  output: '''after 2 2
after 2 2
after 2 2
after 2 2'''
"""
# bug #9263
type
  Matrix* = object
    # Array for internal storage of elements.
    data: ptr UncheckedArray[float]
    # Row and column dimensions.
    m*, n*: int

var
  allocCount, deallocCount: int

proc `=destroy`*(m: var Matrix) =
  if m.data != nil:
    dealloc(m.data)
    deallocCount.inc
    m.data = nil
    m.m = 0
    m.n = 0

proc `=sink`*(a: var Matrix; b: Matrix) =
  if a.data != nil and a.data != b.data:
    dealloc(a.data)
    deallocCount.inc
  a.data = b.data
  a.m = b.m
  a.n = b.n

proc `=`*(a: var Matrix; b: Matrix) =
  if a.data != nil and a.data != b.data:
    dealloc(a.data)
    deallocCount.inc
    a.data = nil
  a.m = b.m
  a.n = b.n
  if b.data != nil:
    a.data = cast[type(a.data)](alloc(a.m * a.n * sizeof(float)))
    allocCount.inc
    copyMem(a.data, b.data, b.m * b.n * sizeof(float))

proc matrix*(m, n: int, s: float): Matrix =
  ## Construct an m-by-n constant matrix.
  result.m = m
  result.n = n
  result.data = cast[type(result.data)](alloc(m * n * sizeof(float)))
  allocCount.inc
  for i in 0 ..< m * n:
    result.data[i] = s

proc len(m: Matrix): int = m.n * m.m

proc `[]`*(m: Matrix, i, j: int): float {.inline.} =
  ## Get a single element.
  m.data[i * m.n + j]

proc `[]`*(m: var Matrix, i, j: int): var float {.inline.} =
  ## Get a single element.
  m.data[i * m.n + j]

proc `[]=`*(m: var Matrix, i, j: int, s: float) =
  ## Set a single element.
  m.data[i * m.n + j] = s

proc `-`*(m: sink Matrix): Matrix =
  ## Unary minus
  result = m
  for i in 0 ..< result.m:
    for j in 0 ..< result.n:
      result[i, j] = -result[i, j]

proc `+`*(a: sink Matrix; b: Matrix): Matrix =
  ## ``C = A + B``
  doAssert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.")
  doAssert(a.len == b.len) # non destructive use before sink is ok
  result = a
  for i in 0 ..< result.m:
    for j in 0 ..< result.n:
      result[i, j] = result[i, j] + b[i, j]

proc `-`*(a: sink Matrix; b: Matrix): Matrix =
  ## ``C = A - B``
  assert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.")
  doAssert(a.len == b.len) # non destructive use before sink is ok
  result = a
  for i in 0 ..< result.m:
    for j in 0 ..< result.n:
      result[i, j] = a[i, j] - b[i, j]

proc info =
  echo "after ", allocCount, " ", deallocCount
  allocCount = 0
  deallocCount = 0

proc test1 =
  var a = matrix(5, 5, 1.0)
  var b = a
  var c = a + b

proc test2 =
  var a = matrix(5, 5, 1.0)
  var b = a
  var c = -a

proc test3 =
  var a = matrix(5, 5, 1.0)
  var b = matrix(5, 5, 2.0)
  #    a = a - b
  b = -b + a

proc test4 =
  # bug #9294
  var a = matrix(5, 5, 1.0)
  a = -a + a

test1()
info()

test2()
info()

test3()
info()

test4()
info()
