Acknowledged
CIQQA-3186

if instance method of one class calls static method of another class, the 2nd class can inadvertently call instance methods on the 1st class

In this example, an instance of C calls a static function on A called doMore(). A.doMore() calls doSomething() which is a static function on A and an instance function on C. At runtime, C.doSomething() as actually called, which is contrary to both the user's and the type checker's expectations. (The type checker thinks A.doSomething() is called, based on the hover info).

Furthermore, if A.doMore() is called outside of the context of C (or outside of the context of any object that has a doSomething method()), then it will crash when it tries to call doSomething().

import Toybox.Lang;
import Toybox.System;

class A {
    public static function doSomething() as Void {
        System.println("A");
    }
    public static function doMore() as Void {
        // when called from instance of C, calls C.doSomething().
        // when called from global scope or some instance which doesn't
        // have doSomething, crashes with "symbol not found error"
        doSomething(); // [*] line 12
    }
    private static function getClass() as A {
        return A;
    }
}

class B extends A { // B is unnecessary for this example, it's just here to match a code sample in a related bug report
    function initialize() {
        A.initialize();
    }
    public static function doSomething() as Void {
        System.println("B");
    }
}

class C {
    public function doItAll() as Void {
        B.doMore();
    }
    public function doSomething() as Void {
        System.println("C");
    }
}

function test() as Void {
    new C().doItAll(); // prints "C" :/
    B.doMore(); // crash at line 12 [*]: "symbol not found error"
}

Same problem if `doSomething()` is replaced by `self.doSomething()`.

I think the problem is that when C.doItAll() is called, `self` is set to the instance of C [as it should be], but when A.doSomething() [static function on A] is called, `self` is STILL set to the instance of C, instead of being "non-existent" [*] (as it would be if a global function was called instead).

[*] "non-existent" in the sense that trying to access it would be a "symbol not found error".

Indeed:

- if you print the value of `self` in C.doItAll() and A.doMore(), they will print the same value [in the case that A.doSomething() was invoked from C.doItAll()]. If B.doMore() / A.doMore() is invoked from a global context, the access of self in A.doMore() will cause a symbol lookup error

- this bug does not occur if A.doMore() is replaced with a global function that just calls `doSomething()`. In this case, a symbol not found error occurs, and that is expected behaviour

Expected behaviour:

- The type checker recognizes that doSomething() on line 12 is *not* of type A.doSomething()

- doSomething() on line 12 always crashes with a symbol not found error, regardless of the context from which A.doMore() is called

Related: https://forums.garmin.com/developer/connect-iq/i/bug-reports/type-checker-allow-static-method-to-be-called-without-qualification-from-other-static-method-in-some-class-but-this-fails-at-runtime-with-a-symbol-not-found-error

^ sorry this is a plain text url instead of a clickable link, but the forum won't let me post it as a link