flofriday / Moose

🐐 A new fun programming language
MIT License
6 stars 1 forks source link

Scope cannot find function and variables of outer scope if they are used as Parameters in me dereference. #31

Closed Jozott00 closed 1 year ago

Jozott00 commented 1 year ago

If one derefers me inside of a class method and uses functions and variables outside of the class, the typechecker cannot see the variable or function.

This is because if me is derefered, the class is gonna closed. But now if the parameter is checked which happens inside of the dereference, it only searches until the class scope and then stops, since the class scope is closed.

Replication:

mut a = 0
A().call()

func test() > Int {
    return 2
}

class A {
    func call() {
        me.set(test())
    }

    func set(b: Int) {
        a = b
    }
}

Error:

/Users/jozott/development/Moose/Tests/MooseTests/Interpreter/InterpreterBaseClass.swift:54: error: -[MooseTests.InterpreterTests test_environment] : failed - -- CompileError ----------------------------------------------------------------

 10|         me.set(test())
                    ^^^^

Couldn't find callable `test()` in current scope: Function with signature `test()` isn't defined.

In this example the parameter is the test() function which is used as parameter for the me.set() call. Since the me dereference closes the A class scope, when searching test, it doesn't reach the global scope.

Note: If we call set() without me, so just set(test()), everything is fine, since the A class scope isn't closed. But also if we call A().set(test()) or objA.set(test()) where objA is some object of type A, the same thing happens as with me. So it happens if the dereference scope is the same as the one we are in when checking the params.

Solution: Inside of the dereferer we could probably check if the obj is of the same type as the current environment and if so, we will not close the environment. Since we are inside the same type as we are refering, it doesn't make sense to close the environment.

Attention: We have to be careful how this solution impacts inheritance, so if the class is inherited by an other class or vice versa. But I think this shouldn't be a problem

Jozott00 commented 1 year ago

Ok this solution doesn't work right away:

class A { func a() { me.f() }}
func f() { }

This does not crash with the upper solution...

Jozott00 commented 1 year ago

New plan, if we make typescope requests for arguments we disable the closed checks. This makes perfect sense since semantically the evaluation of the arguments is done before evaluating the dereference.

The only question is how we implement this... maybe over function Params 🤔

Jozott00 commented 1 year ago

So I fixed it by adding a static TypeScope property argumentCheck. If the typechecker checks arguments, we set the argumentCheck to true and reset it after the checking is done. If the argumentCheck is true, the closed property will always be false, even it is set internally to true.

I know it is not the most beautiful solution, since it requires a global static property of typescope, but otherwise we would have to pass it via parameters in all typescope functions...