HaxeFoundation / haxe

Haxe - The Cross-Platform Toolkit
https://haxe.org
6.14k stars 656 forks source link

C++ nullable comparsion problem #11259

Open barisyild opened 1 year ago

barisyild commented 1 year ago

Issued way

var numb:Null<UInt> = null;
if(numb != null)
{
  //nullable, null comparsion not working on C++ target
  trace("Something wrong with haxe: " + numb);
  return;
}

trace("PASS!");

Javascript target returns PASS! but C++ target returns Something wrong with haxe: null

https://try.haxe.org/#c8aE5aD5

Temporary fixed way

var numb:Null<UInt> = null;
if(Type.typeof(numb) != Type.ValueType.TNull)
{
  //Null comparsion working with this way, never calls here!
  trace("Something wrong with haxe: " + numb);
  return;
}

trace("PASS!");

Javascript and C++ target returns PASS!

https://try.haxe.org/#58D0d884

Platform

OS: Windows 11 Haxe Version: 4.3.1 Hxcpp Version: 4.3.2

Simn commented 1 year ago

UInt has pretty poor support in general, and is a silly type anyway because it has no defined size. I recommend not using it.

Dump looks like this:

[If:Void]
    [Parenthesis:Bool]
        [Binop:Bool]
            [Cast:Int] [Cast:UInt] [Local numb(521):Null<UInt>:Null<UInt>]
            !=
            [Local b(531):Null<UInt>:Null<UInt>]

This means we end up with 0 != null after the cast, which is indeed not equal.

The fundamental problem here is that we allow access on Null<Abstract>, which loses the original type (here Null<UInt>).

joshtynjala commented 6 months ago

I was about to submit the same issue. Luckily, I searched for Null<UInt> first.

Here's some more code that reproduces, with a workaround by assigning the Null<UInt> value to Any before comparing.

class Main {
    static function main() {
        var value:Null<UInt> = null;

        if (value == null) {
            trace("is null");
        }

        if (value != null) {
            trace("not null");
        }

        var assignedToAny:Any = value;

        if (assignedToAny == null) {
            trace("is null");
        }

        if (assignedToAny != null) {
            trace("not null");
        }
    }
}

Output:

not null is null