Thank you for the thorough explanation! /Jens On Thu, Sep 22, 2016 at 7:28 PM, Jordan Rose <jordan_r...@apple.com> wrote:
> Yep, it really is a long-standing bug. Script-mode top-level locals are > treated as globals (module-scope bindings) by the compiler, but their > initial bindings are evaluated eagerly instead of lazily (as you’d want in > a script). Taken together, this means that you can get this completely > unsafe behavior. > > So, why is ‘a’ accepted but ‘b’ not in your original example? > > func foo() -> Int { return b } > let a = 1 > let b = 2 > print(foo()) > > > The secret to the current behavior is that script mode is executed > interactively, instead of parsing it all up front. To make things a little > better, it *actually* parses any number of declarations until it sees > something it actually needs to execute—a statement or a declaration with an > initial value expression. This allows for recursive functions while still > being “live”. > > The consequence here is that *one* top-level binding after a series of > functions may be visible. This is obviously not optimal. > > To fix this, we should: > > - Distinguish between script-mode top-level locals and module-scope > variables that happen to be declared. My personal preference is to treat > anything with explicit access control as a normal lazy global and anything > without access as a top-level local. > > - Consider parsing everything up front, even if we don’t type-check it, so > that we can say “use of ‘b’ before it’s initialized” instead of “undeclared > name ‘b’” > > Note that we *do* need to be conservative here. This code should continue > to be rejected, even though ‘f’ doesn’t refer to ‘local’ directly, because > *calling* ‘f' would be dangerous before the initialization of ‘local': > > internal func f() -> Int { > return g() > } > *// more code here* > > let local = 42 > private func g() -> Int { > return local > } > > > Thanks for bringing this up, if only so I have an opportunity to write out > the issue. :-) > Jordan > > > On Sep 21, 2016, at 23:04, Jens Persson <j...@bitcycle.com> wrote: > > Did you see the other code examples that came up in that twitter > conversations? > For example: > > This worrying little program compiles: > func f() -> Int { > return a > } > let a = f() > > > It also compiles if you print(a) at the end, and it will print 0. > > If we replace Int with [Int] it will still compile but crash when run. > > And also this: > > AnotherFile.swift containing: > func f() -> Int { > return a > } > let a = f() > > main.swift containing > print(a) > > Compile, run (for eternity, at 0% CPU). > > /Jens > > > On Thu, Sep 22, 2016 at 3:13 AM, Joe Groff <jgr...@apple.com> wrote: > >> >> > On Sep 21, 2016, at 2:22 PM, Jens Persson via swift-users < >> swift-users@swift.org> wrote: >> > >> > // This little Swift program compiles (and runs) fine: >> > >> > func foo() -> Int { return a } >> > let a = 1 >> > let b = 2 >> > print(foo()) >> > >> > But if `foo()` returns `b` instead of `a`, I get this compile time >> error: >> > "Use of unresolved identifier `b`" >> >> This looks like a bug to me (cc-ing Jordan, who's thought about global >> scoping issues more than me). In "script mode", it shouldn't be possible to >> refer to a variable before its initialization is executed. However, the way >> this is currently modeled is…problematic, to say the least, among other >> reasons because script globals are still visible to "library" files in the >> same module. >> >> -Joe > > > >
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users