vlang / v

Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. Supports automatic C => V translation. https://vlang.io
MIT License
35.75k stars 2.16k forks source link

Is the data of an option reference returned from a method changed? #21559

Open forchid opened 4 months ago

forchid commented 4 months ago

Describe the bug

In my linked list implementation, push a ref object into the list, then pop it, but it's value changed!

The test code

import time
// 41s.
struct Node<T> {
  mut:
    data T
    prev ?&Node<T>
    next ?&Node<T>
}

struct LinkedList<T> {
  mut:
    size usize
    head ?&Node<T>
}

fn new_linked_list[T]() &LinkedList<T> {
  return &LinkedList<T>{}
}

fn (mut li LinkedList<T>) add[T](data T) {
  mut node := &Node<T>{ data, none, none }

  if li.head == none {
    li.head = node
    node.next = node
    node.prev = node
  } else {
    node.next = li.head
    node.prev = li.head?.prev
    node.prev?.next = node
    li.head?.prev = node
  }

  li.size += 1
}

fn (mut li LinkedList<T>) pop[T]() ?T {
  if li.head == none {
    return none
  }
  if li.size == 1 {
    data := li.head?.data
    li.head?.next = none
    li.head?.prev = none
    li.head = none
    li.size -= 1
    return data
  }

  mut tail := li.head?.prev?
  mut curr := tail.prev?
  curr.next = li.head
  li.head?.prev = curr

  tail.next = none
  tail.prev = none
  li.size -= 1

  return tail.data
}

@[heap]
struct Integer {
  mut:
    value int
}

fn (mut i Integer) inc() {
  i.value += 1
}

fn main() {
  max_itr := 10
  t := time.now()

  for itr in 0 .. max_itr {
    mut a := &Integer{1}
    b := a
    a.inc()
    assert a.value == b.value && b.value == 2

    mut list := new_linked_list[&Integer]()
    println('Itr#$itr list size: $list.size')

    ten := &Integer{10}
    list.add(ten)
    assert ten.value == 10
    println('Itr#$itr list size: $list.size')
    twe := &Integer{value: 20}
    list.add(twe)
    assert twe.value == 20
    println('Itr#$itr list size: $list.size')

    mut n := list.pop()?
    println('Itr#$itr list size: $list.size, data: ${n}')
    assert n.value == twe.value // assert failed!
    n = list.pop()?
    println('Itr#$itr list size: $list.size, data: ${n}')
    assert n.value == ten.value // assert failed!
    mut m := list.pop()
    assert m == none
    println('Itr#$itr list size: $list.size, data: $m')

    max := 1000_0000
    step := 100_0000
    for i in 0 .. max {
      mut item := &Integer{i};
      list.add(item)
      item.inc()
      assert item.value == i + 1
      if i % step == 0 {
        println('Itr#$itr list add: $list.size, i: $i')
      }
    }

    for i in 0 .. max {
      item := list.pop()
      assert item?.value == max - i
      if i % step == 0 {
        println('Itr#$itr list pop: $list.size, i: $i')
      }
    }
    println('Itr#$itr list size: $list.size')
  }

  d := time.since(t)
  println('Bye(time $d)!')
}

Reproduction Steps

>v linkedlist3.v
>linkedlist3
Itr#0 list size: 0
Itr#0 list size: 1
Itr#0 list size: 2
Itr#0 list size: 1, data: &Integer{
    value: 73482112
}
linkedlist3.v:96: FAIL: fn main.main: assert n.value == twe.value
   left value: n.value = 4
  right value: twe.value = 20
V panic: Assertion failed...
v hash: 736067d
.../AppData/Local/Temp/v_0/linkedlist3.01HYM5RQJFKAYPNB7AVED04MDD.tmp.c:7600: at _v_panic: Backtrace
.../AppData/Local/Temp/v_0/linkedlist3.01HYM5RQJFKAYPNB7AVED04MDD.tmp.c:16877: by main__main
.../AppData/Local/Temp/v_0/linkedlist3.01HYM5RQJFKAYPNB7AVED04MDD.tmp.c:17059: by wmain
0048ff38 : by ???
0049009b : by ???
7ff8c4b67034 : by ???

Expected Behavior

The test pass.

Current Behavior

linkedlist3.v:96: FAIL: fn main.main: assert n.value == twe.value left value: n.value = 4 right value: twe.value = 20 V panic: Assertion failed...

Possible Solution

No response

Additional Information/Context

No response

V version

V 0.4.6 736067d

Environment details (OS name and version, etc.)

>v doctor
V full version: V 0.4.6 c412b9f.736067d
OS: windows, Microsoft Windows 10 רҵ v19042 64 λ
Processor: 4 cpus, 64bit, little endian,

getwd: ...\vlang\ds
vexe: ...\v\v.exe
vexe mtime: 2024-05-20 18:12:48

vroot: OK, value: D:\Programs\v
VMODULES: OK, value: ...\.vmodules
VTMP: OK, value: ...\AppData\Local\Temp\v_0

Git version: git version 2.33.1.windows.1
Git vroot status: Error: fatal: not a git repository (or any of the parent directories): .git
.git/config present: false

CC version: Error: 'cc' is not recognized as an internal or external command,
operable program or batch file.

thirdparty/tcc: N/A

[!NOTE] You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote. Other reactions and those to comments will not be taken into account.

heyimtcn commented 4 months ago

could you provide a small runnable chunk that's the source of the error instead of the whole thing?