Acknowledged

Conditional type inference inconsistent for member variables

    import Toybox.Lang;

    class X {
        var x as Float?;
        var y as Float = 0.0;

        function bad() as Float? {
            if (x == null) { return null; }
            return x * y;
        }

        function good() as Float? {
            if (x != null) { return x * y; }
            return null;
        }
    }

WARNING: <device>: bug.mc:9: Attempting to perform operation 'mul' with invalid types 'Null' and '$.Toybox.Lang.Float'.

Note that "bad" and "good" are identical in functionality, but in "bad", there's a warning, and in "good" there isn't. If we change the functions so that x is an argument (or a local variable with deduced type Float?), then neither case warns.

I initially assumed the difference between member variables, and local variables is because its harder to track members. eg in:

        function bad() as Float? {
            if (x == null) { return null; }
            foo();
            return x * y;
        }

The method call foo() might change the value of x. But it turns out the compiler does handle that case if I insert a call to foo() prior to the return in the "good" case (ie the good case then warns that x might be null, even if foo() does nothing), so this looks more like a bug than an as yet unsolved problem.

  • Here's another one. But this time the only workaround seems to be to copy it into a local:

    import Toybox.Activity;
    import Toybox.Lang;
    
    function bad(info as Info) as Float {
        if (info has :elapsedTime) {
            if (info.elapsedTime != null) {
                return info.elapsedTime.toFloat();
            }
        }
        return 0.0;
    }
    
    function good(info as Info) as Float {
        if (info has :elapsedTime) {
            var t = info.elapsedTime;
            if (t != null) {
                return t.toFloat();
            }
        }
        return 0.0;
    }

    ERROR: <device>: bug.mc:7: Cannot find symbol ':toFloat' on type 'Null'.

    So even immediately after checking that its non-null, you can't assume its non-null...