-
Notifications
You must be signed in to change notification settings - Fork 9
Fix decls in value position without assignment to return nothing
#67
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
Conversation
|
I think we should try and match the flisp behaviour where no-assignment decls are still not allowed in value position in general (a user could reasonably expect As for |
|
Oh yes indeed, this PR doesn't seem like the correct fix. So. We currently have some weird behaviors: julia> local x
julia> begin
local x
end # returns nothing
julia> begin
x = 10
local x
end # also returns nothing :sweat_smile:
julia> global z # ok
julia> begin
global z # looks like a statement, but is an error
end
ERROR: syntax: misplaced "global" declaration
Stacktrace:
[1] top-level scope
@ REPL[36]:1I think this occurs because julia> Meta.@lower global x
:(global x)
julia> Meta.@lower local x
:($(Expr(:thunk, CodeInfo(
@ none within `top-level scope`
1 ─ Core.NewvarNode(:(x))
└── return nothing
))))To be honest, I don't love this about the existing system and I'm not 100% sure what to do about it. There's a certain sense in not lowering some constructs but it's also a fairly weird oddity that certain expressions never get turned into IR and are instead interpreted with their own special set of rules (which might diverge from IR generation!) I guess we can fix the error message just by detecting unadorned |
Sounds like an OK patch to me; I think this is what ends up happening in flisp with Also ref JuliaLang/julia#58279, which would improve all of this, but I believe requires a bunch of packages to be updated. |
|
We could probably adopt the |
|
RE |
Yes! It's problematic to have the rules for validity of top level expressions scattered in various places in the runtime. I've noticed that you've been progressively turning the special forms in IR into calls to runtime functions and I'm very happy about that. In case you didn't notice, this is something I've also been factoring out in JuliaLowering - if you look in src/runtime.jl you'll see there's various calls to |
Disallows "use" of the value of `global x`, except in tail position in top level thunks - in those cases, return `nothing` so that `global x` can be used in the value position of a top level thunk. This is normally harmless as one cannot observe this value, except in special circumstances - namely the return value of `eval()` (and things which call eval, such as `include()`). While we're thinking about this, also disallow a bare `local x` in a top level thunk because this cannot have useful side effects and is just confusing when it occurs outside a block construct. (This is not currently disallowed for `local` arising from macro expansions because it's not an obvious user error in that case. It could possibly arise as a valid macro expansion of a trivial case, for some macros?)
9952adb to
f98eee6
Compare
|
Ok, I've revised this significantly. For now, I've somewhat followed the logic in JuliaLang/julia#58279 by allowing global declarations in tail position but not value position, inspired by the @mlechu I've also tackled the " See tests for the current cases which are considered errors. I suspect that |
|
And here I was, yesterday, thinking "oh this is a cute and simple little bug I'll fix it in half an hour". haha! |
mlechu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, thanks for fixing this.
Effects on the RHS is a good catch. I'd take the triage decision to mean that we should make it an error anyway to prevent confusion, but I'm also OK leaving potentially-intentionally breaking stuff until after we've fixed our real bugs so as to not mix pkgeval failures. (Or I could make the change in flisp and try it there first.)
I'll start keeping a list of possibly-breaking syntax improvements like "try to make local non-assigning declaration throw an error in value position" and "try to make uncontained local assigning declaration at top level throw an error".
| compile(ctx, nothing_(ctx, ex), needs_value, in_tail_pos) | ||
| else | ||
| throw(LoweringError(ex, | ||
| "global declaration doesn't read the variable and can't return a value")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good error message
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
In a lot of these cases it could be useful to know "why are we in value position?" as well, so we could say "the value is used here" (eg, in an assignment) - see #8. But for now this will do I guess :)
| if kind(ex) == K"local" | ||
| # This error assumes we're expanding the body of a top level thunk but | ||
| # we might want to make that more explicit in the pass system. | ||
| throw(LoweringError(ex, "local declarations have no effect outside a scope")) | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm OK moving this to desugaring, as a macro that does nothing but declaring an unenclosed local escaped into the enclosing scope is probably being misused at top level anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just feel it's more possible to generate trivial code from a macro without it necessarily being a user error or an error by the macro writer. So on balance I think I'm preferring it where it is.
Fix #50