Skip to content

Make world-age increments explicit#56509

Merged
Keno merged 6 commits intomasterfrom
kf/explicitageinc
Nov 21, 2024
Merged

Make world-age increments explicit#56509
Keno merged 6 commits intomasterfrom
kf/explicitageinc

Conversation

@Keno
Copy link
Copy Markdown
Member

@Keno Keno commented Nov 9, 2024

This PR introduces a new, toplevel-only, syntax form :worldinc that semantically represents the effect of raising the current task's world age to the latest world for the remainder of the current toplevel evaluation (that context being an entry to eval or a module expression). For detailed motivation on why this is desirable, see #55145, which I won't repeat here, but the gist is that we never really defined when world-age increments and worse are inconsistent about it. This is something we need to figure out now, because the bindings partition work will make world age even more observable via bindings.

Having created a mechanism for world age increments, the big question is one of policy, i.e. when should these world age increments be inserted.

Several reasonable options exist:

  1. After world-age affecting syntax constructs (as proprosed in Make precise semantics of world-age increments in top-level thunks #55145)
  2. Option 1 + some reasonable additional cases that people rely on
  3. Before any top level call expression
  4. Before any expression at toplevel whatsover

As an example, case, consider a == a at toplevel. Depending on the semantics that could either be the same as in local scope, or each of the four world age dependent lookups (three binding lookups, one method lookup) could (potentially) occur in a different world age.

The general tradeoff here is between the risk of exposing the user to confusing world age errors and our ability to optimize top-level code (in general, any :worldinc statement will require us to fully pessimize or recompile all following code).

This PR basically implements option 2 with the following semantics:

  1. The interpreter explicit raises the world age only at :worldinc exprs or after :module exprs.
  2. The frontend inserts :worldinc after all struct definitions, method definitions, using and `import.
  3. The @eval macro inserts a worldinc following the call to eval if at toplevel
  4. A literal (syntactic) call to include gains an implicit worldinc.

Of these the fourth is probably the most questionable, but is necessary to make this non-breaking for most code patterns. Perhaps it would have been better to make include a macro from the beginning (esp because it already has semantics that look a little like reaching into the calling module), but that ship has sailed.

Unfortunately, I don't see any good intermediate options between this PR and option #3 above. I think option #3 is closest to what we have right now, but if we were to choose it and actually fix the soundness issues, I expect that we would be destroying all performance of global-scope code. For this reason, I would like to try to make the version in this PR work, even if the semantics are a little ugly.

The biggest pattern that this PR does not catch is:

eval(:(f() = 1))
f()

We could apply the same include special case to eval, but given the existence of @eval which allows addressing this at the macro level, I decided not to. We can decide which way we want to go on this based on what the package ecosystem looks like.

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor change Marginal behavior change acceptable for a minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants