-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use correct script ctx when evaluating member init #15112
base: master
Are you sure you want to change the base?
Conversation
The initializer expression for class members is evaluated as-needed. Use the script context where the class is defined when evaluating it to avoid missing variable errors. Closes vim#14011
The example in #14402 does not fail with this patch; so you can add it as another issue that is fixed by this PR. I'll play with it a little more, see if I can come up with a multi-step/nested test that also fails. Maybe I can couple my test to @lifepillar test (the tests superficially seem different). |
Found another failing case which seems related. Put the two files in the same directory. Source t.vim vim9script
import './obj_key.vim' as obj_key
class C1 extends obj_key.ObjKey
endclass
var o = C1.new()
echom string(o) obj_key.vim vim9script
echom "OBJ_KEY IMPORTED"
const DEFAULT = 'default-obj_key'
export class ObjKey
const unique_object_id3 = DEFAULT
endclass
var o = ObjKey.new()
echom string(o) Source
Source
|
That's expected, the initializer expression is taken by reference and evaluated in the Is this right? I don't know. Braam modeled this behavior after Typescript (and I'm not really a fan) but have no idea of how it behaves in such situations. |
That sounds like an implementation issue. With that description, it could be argued that this PR as it stands is not needed. In the OP of this PR it says
If it doesn't use the context where it is defined for execution, then why is it needed for compilation?
I thought that if it compiled, then it would run. Excluding when
Anyway, this behavior is confusing and shouldn't be a runtime error. @yegappan can you offer some clarification?
I know nothing about Typescript. But if it must fail (and I don't agree that it should), better to fail in compilation. |
Without this patch the compilation failed because the variable could not be found in the script context, fixing that means you can now worry about the variable being exported or not. You can't do better than this if we wish to retain this behaviour, the Personally speaking I don't really like this dynamic behaviour and would rather require all the initializers to be constant rvalues. We could then evaluate the initializers at compile time and use that value in the constructor, avoiding all the context-related issues. |
Code that compiles should not fail at at runtime (except for type errors, probably a few other reasons)
It's good to know that I can still be shocked an horrified by vim9script ;-) BTW, this change is not backwards compatible (that doesn't bother me if it's a bug fix, but in this situation I'm lost). Add this line to t.vim
Then run
With this patch you get an error
@dkearns Were you aware of this? Do you have any words to bring me down? |
Well one could argue that the intializer expressions all must have the same privacy as the class itself. In this case the compilation would fail if the class is declared as
The previous behaviour look quite wrong to me. |
I don't understand how it is supposed to work.
What did you mean by the following?
|
No, and I can't believe it's by design. TypeScript works as expected. Foo.ts const DEFAULT: number = 42;
export class Foo {
thing: number = DEFAULT;
} Bar.ts import { Foo } from "./Foo.ts";
class Bar extends Foo {
}
console.log(new Bar().thing); // => 42 |
so, can we fix it, so that is behaves like for Typescript? |
The initializer expression for class members is evaluated as-needed. Use the script context where the class is defined when evaluating it to avoid missing variable errors.
Closes #14011