nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.52k stars 1.46k forks source link

When self-referenced optional field is defined inside a ref type then the option type behaves in a wrong way during an assignment #24133

Open KarolBajkowski opened 3 weeks ago

KarolBajkowski commented 3 weeks ago

Description

When the type contains a self-referenced optional field then during the variable assignment (value copy takes place I believe), the field 'isSome' has a wrong value. Below are the examples:

This works fine:

import options

type Foo = ref object
    name: string

var foo1: Option[Foo] = none(Foo)
var foo2: Option[Foo] = foo1
if foo2.isSome:
    echo "SHOULD NOT BE REACHABLE"
else:
    echo "OK"

It will print: "OK"

however, when I add 'prev' field, this program misbehaves:

import options

type Foo = ref object
    name: string
    prev: Option[Foo]    # <-- this has been added

var foo1: Option[Foo] = none(Foo)
var foo2: Option[Foo] = foo1
if foo2.isSome:
    echo "SHOULD NOT BE REACHABLE"
else:
    echo "OK"

It will print "SHOULD NOT BE REACHABLE" which is an unexpected result.

Nim Version

Nim Compiler Version 2.0.8 [Windows: amd64] Compiled at 2024-07-03 Copyright (c) 2006-2023 by Andreas Rumpf

Current Output

No response

Expected Output

No response

Known Workarounds

import options

type 
    Foo = ref FooObj
    FooObj = object
        name: string
        abc: Option[Foo]

var foo1: Option[Foo] = none(Foo)
var foo2: Option[Foo] = foo1
if foo2.isSome:
    echo "SHOULD NOT BE REACHABLE"
else:
    echo "OK"

Additional Information

No response

metagn commented 3 weeks ago

Related #16754

KarolBajkowski commented 3 weeks ago

@metagn Actually it might be exactly the same. I refined my example. It looks like this one also misbehaves:

import options

type Foo = ref object
    name: string
    abc: Option[Foo]

var foo1: Option[Foo] = none(Foo)
var foo2: Option[Foo] = foo1
if foo2.isSome:
    echo "SHOULD NOT BE REACHABLE"
else:
    echo "OK"

It prints "SHOULD NOT BE REACHABLE" as well.