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.